protected override BuildResult Build(IProgressMonitor monitor, SolutionEntityItem item, ConfigurationSelector configuration) { MonobjcProject proj = item as MonobjcProject; if (proj == null || proj.CompileTarget != CompileTarget.Exe) return base.Build(monitor, item, configuration); BuildResult result = base.Build(monitor, item, configuration); if (result.ErrorCount > 0) return result; var conf = (MonobjcProjectConfiguration) proj.GetConfiguration(configuration); // Create directories monitor.BeginTask("Creating application bundle", 0); foreach (var path in new [] { conf.ResourcesDirectory, conf.MacOSDirectory }) { if (!Directory.Exists(path)) Directory.CreateDirectory(path); } monitor.EndTask(); string exeName = Path.GetFileNameWithoutExtension(conf.CompiledOutputName); // Write Info.plist into 'Contents' directory monitor.BeginTask("Updating application manifest", 0); var doc = new PlistDocument(); var docRoot = new PlistDictionary(); docRoot["CFBundleExecutable"] = exeName; docRoot["CFBundleInfoDictionaryVersion"] = "6.0"; docRoot["CFBundlePackageType"] = "APPL"; docRoot["CFBundleName"] = proj.BundleDisplayName ?? proj.Name; docRoot["CFBundleDisplayName"] = proj.BundleDisplayName ?? proj.Name; docRoot["CFBundleIdentifier"] = proj.BundleIdentifier ?? String.Format("com.yourcompany.{0}", proj.Name); docRoot["CFBundleVersion"] = proj.BundleVersion ?? "1.0"; docRoot["CFBundleDevelopmentRegion"] = proj.BundleDevelopmentRegion ?? "English"; FilePath icon = proj.BundleIcon.ToRelative (proj.BaseDirectory); if (!(icon.IsNullOrEmpty || icon.ToString () == ".")) docRoot["CFBundleIconFile"] = icon.FileName; if (!String.IsNullOrEmpty (proj.MainNibFile.ToString ())) docRoot["NSMainNibFile"] = Path.GetFileNameWithoutExtension(proj.MainNibFile.ToString ()); doc.Root = docRoot; var plistOut = conf.ContentsDirectory.Combine("Info.plist"); using (XmlTextWriter writer = new XmlTextWriter(plistOut, Encoding.UTF8)) { doc.Write(writer); } monitor.EndTask(); // Copy project binary into 'Resources' directory monitor.BeginTask("Copying application binary", 0); File.Copy(conf.CompiledOutputName, conf.ResourcesDirectory.Combine(conf.CompiledOutputName.FileName), true); if (File.Exists(conf.CompiledOutputName + ".mdb")) File.Copy(conf.CompiledOutputName + ".mdb", conf.ResourcesDirectory.Combine(conf.CompiledOutputName.FileName + ".mdb"), true); monitor.EndTask(); // Copy references into 'Resources' directory var references = BuildUtils.GetReferencesFilePairs(proj, configuration); foreach (var pair in references) { pair.EnsureOutputDirectory(); monitor.Log.WriteLine("Copying '{0}' to '{1}'", pair.Input, pair.Output); File.Copy(pair.Input, pair.Output, true); monitor.Step(1); } monitor.EndTask(); // Write launcher script into 'MacOS' directory monitor.BeginTask("Writing launcher script", 0); string scriptPath = conf.MacOSDirectory.Combine(exeName); var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("LaunchScript.sh"); using (StreamReader reader = new StreamReader(stream)) { using (StreamWriter writer = new StreamWriter(scriptPath)) { writer.Write(reader.ReadToEnd()); } } // Make executable (755) new UnixFileInfo(scriptPath).FileAccessPermissions = FileAccessPermissions.UserReadWriteExecute | FileAccessPermissions.GroupRead | FileAccessPermissions.GroupExecute | FileAccessPermissions.OtherRead | FileAccessPermissions.OtherExecute; monitor.EndTask(); return result; }
static void WriteXcent (PlistDocument doc, string file) { //write the plist to a byte[] as UTF8 without a BOM var ms = new MemoryStream (); var xmlSettings = new XmlWriterSettings () { Encoding = new UTF8Encoding (false), //no BOM CloseOutput = false, Indent = true, IndentChars = "\t", NewLineChars = "\n", }; using (var writer = XmlTextWriter.Create (ms, xmlSettings)) doc.Write (writer); //HACK: workaround for bug in Apple's entitlements XML parser //having written to a UTF8 stream to convince the xmlwriter to do the right thing, //we now convert to string and back to do some substitutions to work around bugs //in Apple's braindead entitlements XML parser. //Specifically, it chokes on "<true />" but accepts "<true"> //Hence, to be on the safe side, we produce EXACTLY the same format var sb = new StringBuilder (Encoding.UTF8.GetString (ms.GetBuffer ())); sb.Replace ("-//Apple Computer//DTD PLIST 1.0//EN", "-//Apple//DTD PLIST 1.0//EN"); sb.Replace ("<?xml version=\"1.0\" encoding=\"utf-8\"?>", "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); sb.Replace ("\n\t", "\n"); sb.Replace (" />\n", "/>\n"); sb.Append ("\n"); var buf = Encoding.UTF8.GetBytes (sb.ToString ()); //write the xcent file with the magic header, length, and the plist byte[] magic = new byte[] { 0xfa, 0xde, 0x71, 0x71 }; byte[] fileLen = Mono.DataConverter.BigEndian.GetBytes ((uint)buf.Length + 8); // 8 = magic.length + magicLen.Length using (var fs = File.Open (file, FileMode.Create)) { fs.Write (magic, 0, magic.Length); fs.Write (fileLen, 0, fileLen.Length); fs.Write (buf, 0, (int)buf.Length); } }
public override bool Execute() { string displayName = DisplayName ?? Name; string identifier = Identifier ?? String.Format("com.yourcompany.{0}", Name); string version = Version ?? "1.0"; string region = DevelopmentRegion ?? "English"; var doc = new PlistDocument(); var docRoot = new PlistDictionary(); docRoot["CFBundleExecutable"] = ExeName; docRoot["CFBundleInfoDictionaryVersion"] = "6.0"; docRoot["CFBundlePackageType"] = "APPL"; docRoot["CFBundleName"] = displayName; docRoot["CFBundleDisplayName"] = displayName; docRoot["CFBundleIdentifier"] = identifier; docRoot["CFBundleVersion"] = version; docRoot["CFBundleDevelopmentRegion"] = region; if (!String.IsNullOrEmpty(Icon)) docRoot["CFBundleIconFile"] = Icon; if (!String.IsNullOrEmpty(MainNibFile)) docRoot["NSMainNibFile"] = Path.GetFileNameWithoutExtension(MainNibFile); doc.Root = docRoot; using (XmlTextWriter writer = new XmlTextWriter(FileName, Encoding.UTF8)) { doc.Write(writer); } Log.LogMessage("Wrote {0}", FileName); return true; }
static BuildResult CreateMergedPlist (IProgressMonitor monitor, IPhoneProjectConfiguration conf, ProjectFile template, string outPath, Func<IPhoneProjectConfiguration, PlistDocument,BuildResult> merge) { var result = new BuildResult (); var doc = new PlistDocument (); if (template != null) { try { doc.LoadFromXmlFile (template.FilePath); } catch (Exception ex) { if (ex is XmlException) result.AddError (template.FilePath, ((XmlException)ex).LineNumber, ((XmlException)ex).LinePosition, null, ex.Message); else result.AddError (template.FilePath, 0, 0, null, ex.Message); monitor.ReportError (GettextCatalog.GetString ("Could not load file '{0}': {1}", template.FilePath, ex.Message), null); return result; } } if (result.Append (merge (conf, doc)).ErrorCount > 0) return result; try { EnsureDirectoryForFile (outPath); using (XmlTextWriter writer = new XmlTextWriter (outPath, Encoding.UTF8)) { writer.Formatting = Formatting.Indented; doc.Write (writer); } } catch (Exception ex) { result.AddError (outPath, 0, 0, null, ex.Message); monitor.ReportError (GettextCatalog.GetString ("Could not write file '{0}'", outPath), ex); } return result; }