static PlistDocument LoadSdkSettings (IPhoneSdkVersion sdk) { var doc = new PlistDocument (); doc.LoadFromXmlFile ("/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS" + sdk.ToString () + ".sdk/SDKSettings.plist"); return doc; }
public static bool BuildPackage (IProgressMonitor monitor, MonoMacProject project, ConfigurationSelector conf, MonoMacPackagingSettings settings, FilePath target) { string bundleKey = settings.BundleSigningKey; string packageKey = settings.PackageSigningKey; if (settings.SignBundle || (settings.CreatePackage && settings.SignPackage)) { var identities = Keychain.GetAllSigningIdentities (); if (string.IsNullOrEmpty (bundleKey)) { bundleKey = identities.FirstOrDefault (k => k.StartsWith (MonoMacPackagingSettingsWidget.APPLICATION_PREFIX)); if (string.IsNullOrEmpty (bundleKey)) { monitor.ReportError ("Did not find default app signing key", null); return false; } else if (!identities.Any (k => k == bundleKey)) { monitor.ReportError ("Did not find app signing key in keychain", null); return false; } } if (string.IsNullOrEmpty (packageKey)) { packageKey = identities.FirstOrDefault (k => k.StartsWith (MonoMacPackagingSettingsWidget.INSTALLER_PREFIX)); if (string.IsNullOrEmpty (packageKey)) { monitor.ReportError ("Did not find default package signing key", null); return false; } else if (!identities.Any (k => k == packageKey)) { monitor.ReportError ("Did not find package signing key in keychain", null); return false; } } } if (project.NeedsBuilding (conf)) { BuildResult res = project.Build (monitor, conf); if (res.ErrorCount > 0) { foreach (BuildError e in res.Errors) monitor.ReportError (e.ToString (), null); monitor.ReportError (GettextCatalog.GetString ("The project failed to build."), null); return false; } } var cfg = (MonoMacProjectConfiguration) project.GetConfiguration (conf); FilePath tempDir = "/tmp/monomac-build-" + DateTime.Now.Ticks; FilePath workingApp = tempDir.Combine (cfg.AppDirectory.FileName); try { //user will have agreed to overwrite when they picked the target if (Directory.Exists (target)) Directory.Delete (target, true); else if (File.Exists (target)) File.Delete (target); monitor.BeginTask (GettextCatalog.GetString ("Creating app bundle"), 0); var files = Directory.GetFiles (cfg.AppDirectory, "*", SearchOption.AllDirectories); HashSet<string> createdDirs = new HashSet<string> (); foreach (FilePath f in files) { var rel = f.ToRelative (cfg.AppDirectory); var parentDir = rel.ParentDirectory; if (settings.IncludeMono) { if (parentDir.IsNullOrEmpty || parentDir == "." || parentDir == "Contents/MacOS") continue; var ext = rel.Extension; if (ext == ".mdb" || ext == ".exe" || ext == ".dll") continue; } if (monitor.IsCancelRequested) return false; if (createdDirs.Add (parentDir)) Directory.CreateDirectory (workingApp.Combine (parentDir)); monitor.Log.WriteLine (rel); File.Copy (f, workingApp.Combine (rel)); } monitor.EndTask (); if (settings.IncludeMono) { monitor.BeginTask (GettextCatalog.GetString ("Merging Mono into app bundle"), 0); var args = new ProcessArgumentBuilder (); switch (settings.LinkerMode){ case MonoMacLinkerMode.LinkNone: args.Add ("--nolink"); break; case MonoMacLinkerMode.LinkFramework: args.Add ("--linksdkonly"); break; case MonoMacLinkerMode.LinkAll: // nothing break; } args.Add ("-o"); args.AddQuoted (tempDir); args.Add ("-n"); args.AddQuoted (cfg.AppName); var assemblies = project.GetReferencedAssemblies (conf, true); foreach (var a in assemblies) { args.Add ("-a"); args.AddQuoted (a); } args.AddQuoted (cfg.CompiledOutputName); string mmpPath = Mono.Addins.AddinManager.CurrentAddin.GetFilePath ("mmp"); //FIXME: workaround for Mono.Addins losing the executable bit during packaging var mmpInfo = new Mono.Unix.UnixFileInfo (mmpPath); if ((mmpInfo.FileAccessPermissions & Mono.Unix.FileAccessPermissions.UserExecute) == 0) mmpInfo.FileAccessPermissions |= Mono.Unix.FileAccessPermissions.UserExecute; var psi = new ProcessStartInfo (mmpPath, args.ToString ()); if (MacBuildUtilities.ExecuteBuildCommand (monitor, psi) != 0) { monitor.ReportError ("Merging Mono failed", null); return false; } var plistFile = workingApp.Combine ("Contents", "Info.plist"); var plistDoc = new PlistDocument (); plistDoc.LoadFromXmlFile (plistFile); ((PlistDictionary)plistDoc.Root)["MonoBundleExecutable"] = cfg.CompiledOutputName.FileName; plistDoc.WriteToFile (plistFile); monitor.EndTask (); } //TODO: verify bundle details if for app store? if (settings.SignBundle) { monitor.BeginTask (GettextCatalog.GetString ("Signing app bundle"), 0); // Sign any dynamic libraries, before we sign the bundle var dylibs = Directory.GetFiles (workingApp, "*.dylib", SearchOption.AllDirectories); foreach (var dylib in dylibs){ if (!Sign (monitor, bundleKey, dylib)) return false; } if (!Sign (monitor, bundleKey, workingApp)) return false; monitor.EndTask (); } if (settings.CreatePackage) { monitor.BeginTask (GettextCatalog.GetString ("Creating installer"), 0); var args = new ProcessArgumentBuilder (); args.Add ("--component"); args.AddQuoted (workingApp); args.Add ("/Applications"); if (settings.SignPackage) { args.Add ("--sign"); args.AddQuoted (packageKey); } if (!settings.ProductDefinition.IsNullOrEmpty) { args.Add ("--product"); args.AddQuoted (settings.ProductDefinition); } args.AddQuoted (target); var psi = new ProcessStartInfo ("productbuild", args.ToString ()); try { if (MacBuildUtilities.ExecuteBuildCommand (monitor, psi) != 0) { monitor.ReportError ("Package creation failed", null); return false; } } catch (System.ComponentModel.Win32Exception) { monitor.ReportError ("productbuild not found", null); return false; } monitor.EndTask (); } else { Directory.Move (workingApp, target); } } finally { try { if (Directory.Exists (tempDir)) Directory.Delete (tempDir, true); } catch (Exception ex) { LoggingService.LogError ("Error removing temp directory", ex); } } return true; }
static PlistDocument LoadDTSettings () { var doc = new PlistDocument (); doc.LoadFromXmlFile ("/Developer/Platforms/iPhoneOS.platform/Info.plist"); return doc; }
public static DTSdkSettings GetSdkSettings (IPhoneSdkVersion sdk) { DTSdkSettings settings; if (sdkSettingsCache.TryGetValue (sdk.ToString (), out settings)) return settings; settings = new DTSdkSettings (); var doc = new PlistDocument (); doc.LoadFromXmlFile (GetSdkPlistFilename (sdk.ToString ())); var dict = (PlistDictionary) doc.Root; settings.AlternateSDK = ((PlistString)dict["AlternateSDK"]).Value; settings.CanonicalName = ((PlistString)dict["CanonicalName"]).Value; var props = (PlistDictionary) dict["DefaultProperties"]; settings.DTCompiler = ((PlistString)props["GCC_VERSION"]).Value; var sdkPath = GetSdkPath (sdk.ToString ()); var file = sdkPath + "/System/Library/CoreServices/SystemVersion.plist"; settings.DTPlatformBuild = GrabRootString (file, "ProductBuildVersion"); sdkSettingsCache[sdk.ToString ()] = settings; return settings; }
public static BuildResult CreateMergedPlist (IProgressMonitor monitor, ProjectFile template, string outPath, Func<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; } } try { if (result.Append (merge (doc)).ErrorCount > 0) return result; } catch (Exception ex) { result.AddError ("Error merging Info.plist: " + ex.Message); LoggingService.LogError ("Error merging Info.plist", ex); return result; } try { EnsureDirectoryForFile (outPath); doc.WriteToFile (outPath); } catch (Exception ex) { result.AddError (outPath, 0, 0, null, ex.Message); monitor.ReportError (GettextCatalog.GetString ("Could not write file '{0}'", outPath), ex); } return result; }
public static DTSettings GetDTSettings () { if (dtSettings != null) return dtSettings; var doc = new PlistDocument (); doc.LoadFromXmlFile (PLAT_PLIST); var dict = (PlistDictionary) doc.Root; var infos = (PlistDictionary) dict["AdditionalInfo"]; var vals = new DTSettings (); vals.DTPlatformVersion = ((PlistString)infos["DTPlatformVersion"]).Value; var xcodeVersion = GrabRootString ("/Developer/Applications/Xcode.app/Contents/Info.plist", "CFBundleShortVersionString"); vals.DTXcode = "0" + xcodeVersion.Replace (".", ""); vals.DTXcodeBuild = GrabRootString ("/Developer/Library/version.plist", "ProductBuildVersion"); return (dtSettings = vals); }
static string GrabRootString (string file, string key) { var doc = new PlistDocument (); doc.LoadFromXmlFile (file); return ((PlistString) ((PlistDictionary)doc.Root)[key]).Value; }
public void Store (IPhoneProject proj) { proj.BundleDevelopmentRegion = NullIfEmpty (devRegionEntry.Text); proj.BundleIdentifier = NullIfEmpty (bundleIdEntry.Text); proj.BundleVersion = NullIfEmpty (bundleVersionEntry.Text); proj.BundleDisplayName = NullIfEmpty (displayNameEntry.Text); proj.MainNibFile = NullIfEmpty (mainNibPicker.SelectedFile); proj.MainNibFileIPad = NullIfEmpty (iPadNibPicker.SelectedFile); proj.BundleIcon = NullIfEmpty (iphoneIconPicker.SelectedFile); proj.BundleIconHigh = NullIfEmpty (iphoneIconHighPicker.SelectedFile); proj.BundleIconIPad = NullIfEmpty (ipadIconPicker.SelectedFile); proj.BundleIconSpotlight = NullIfEmpty (settingsIconPicker.SelectedFile); proj.BundleIconSpotlightHigh = NullIfEmpty (settingsIconHighPicker.SelectedFile); proj.BundleIconIPadSpotlight = NullIfEmpty (ipadSpotlightIconPicker.SelectedFile); proj.SupportedDevices = SupportedDevices; if (badPlist) return; try { var pf = proj.GetInfoPlist (); var doc = new PlistDocument (); doc.LoadFromXmlFile (pf.FilePath); var dict = doc.Root as PlistDictionary; if (dict == null) doc.Root = dict = new PlistDictionary (); var orientations = SaveOrientationsCombo (supportedOrientationsCombo); if (orientations != null) dict [OrientationUtil.KEY] = orientations; else dict.Remove (OrientationUtil.KEY); var iPadOrientations = SaveOrientationsCombo (iPadOrientationsCombo); if (proj.SupportedDevices == TargetDevice.IPhoneAndIPad && iPadOrientations != null) dict [OrientationUtil.KEY_IPAD] = iPadOrientations; else dict.Remove (OrientationUtil.KEY_IPAD); doc.WriteToFile (pf.FilePath); } catch (Exception ex) { badPlist = true; MonoDevelop.Ide.MessageService.ShowException (ex, "Error saving Info.plist."); } }
public void Load (IPhoneProject proj) { devRegionEntry.Text = proj.BundleDevelopmentRegion ?? ""; bundleIdEntry.Text = proj.BundleIdentifier ?? ""; bundleVersionEntry.Text = proj.BundleVersion ?? ""; displayNameEntry.Text = proj.BundleDisplayName ?? ""; mainNibPicker.Project = iPadNibPicker.Project = proj; mainNibPicker.EntryIsEditable = iPadNibPicker.EntryIsEditable = true; mainNibPicker.DefaultFilter = iPadNibPicker.DefaultFilter = "*.xib"; mainNibPicker.DialogTitle = GettextCatalog.GetString ("Select main interface file..."); mainNibPicker.SelectedFile = proj.MainNibFile.ToString () ?? ""; iPadNibPicker.DialogTitle = GettextCatalog.GetString ("Select iPad interface file..."); iPadNibPicker.SelectedFile = proj.MainNibFileIPad.ToString () ?? ""; targetDevicesCombo.AppendText (GettextCatalog.GetString ("iPhone and iPad")); targetDevicesCombo.AppendText (GettextCatalog.GetString ("iPhone only")); targetDevicesCombo.AppendText (GettextCatalog.GetString ("iPad only")); SupportedDevices = proj.SupportedDevices; ProjectFileEntry [] pickers = { iphoneIconPicker, iphoneIconHighPicker, ipadIconPicker, settingsIconPicker, settingsIconHighPicker, ipadSpotlightIconPicker, }; foreach (var p in pickers) { p.Project = proj; p.DefaultFilter = "*.png"; p.EntryIsEditable = true; p.DialogTitle = GettextCatalog.GetString ("Select icon..."); } iphoneIconPicker.SelectedFile = proj.BundleIcon.ToString () ?? ""; iphoneIconHighPicker.SelectedFile = proj.BundleIconHigh.ToString () ?? ""; ipadIconPicker.SelectedFile = proj.BundleIconIPad.ToString () ?? ""; settingsIconPicker.SelectedFile = proj.BundleIconSpotlight.ToString () ?? ""; settingsIconHighPicker.SelectedFile = proj.BundleIconSpotlightHigh.ToString () ?? ""; ipadSpotlightIconPicker.SelectedFile = proj.BundleIconIPadSpotlight.ToString () ?? ""; badPlist = false; try { var pf = proj.GetInfoPlist (); var doc = new PlistDocument (); doc.LoadFromXmlFile (pf.FilePath); var dict = doc.Root as PlistDictionary; if (dict == null) doc.Root = dict = new PlistDictionary (); var orientationArr = dict.TryGetValue (OrientationUtil.KEY) as PlistArray; var ipadOrientationArr = dict.TryGetValue (OrientationUtil.KEY_IPAD) as PlistArray; LoadOrientationsCombo (supportedOrientationsCombo, orientationArr); LoadOrientationsCombo (iPadOrientationsCombo, ipadOrientationArr); } catch (Exception ex) { badPlist = true; MonoDevelop.Ide.MessageService.ShowException (ex, "Error reading Info.plist. Some settings may not be saved."); } HandleTargetDevicesComboChanged (null, null); }
public static DTSettings GetDTSettings () { if (dtSettings != null) return dtSettings; var doc = new PlistDocument (); doc.LoadFromXmlFile (PLAT_PLIST); var dict = (PlistDictionary) doc.Root; var infos = (PlistDictionary) dict["AdditionalInfo"]; var vals = new DTSettings (); vals.DTPlatformVersion = ((PlistString)infos["DTPlatformVersion"]).Value; var pool = SendMessage (GetClass ("NSAutoreleasePool"), GetSelector ("new")); var bundle = SendMessage (GetClass ("NSString"), GetSelector ("stringWithUTF8String:"), "CFBundleShortVersionString"); var plist = SendMessage (GetClass ("NSString"), GetSelector ("stringWithUTF8String:"), "/Developer/Applications/Xcode.app/Contents/Info.plist"); var data = SendMessage (GetClass ("NSDictionary"), GetSelector ("dictionaryWithContentsOfFile:"), plist); var val = SendMessage (data, GetSelector ("objectForKey:"), bundle); var xcodeVersion = Marshal.PtrToStringAuto (SendMessage (val, GetSelector ("UTF8String"))); SendMessage (pool, GetSelector ("release")); vals.DTXcode = "0" + xcodeVersion.Replace (".", ""); vals.DTXcodeBuild = GrabRootString (VERSION_PLIST, "ProductBuildVersion"); return (dtSettings = vals); }
static BuildResult GenXcent (IProgressMonitor monitor, IPhoneSdkVersion sdkVersion, IPhoneProject proj, IPhoneProjectConfiguration conf, IPhoneAppIdentity identity, out string xcentName) { xcentName = conf.CompiledOutputName.ChangeExtension (".xcent"); monitor.BeginTask (GettextCatalog.GetString ("Processing entitlements file"), 0); string srcFile; if (!string.IsNullOrEmpty (conf.CodesignEntitlements)) { if (!File.Exists (conf.CodesignEntitlements)) return BuildError ("Entitlements file \"" + conf.CodesignEntitlements + "\" not found."); srcFile = conf.CodesignEntitlements; } else { srcFile = "/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS" + sdkVersion.ToString () + ".sdk/Entitlements.plist"; } var doc = new PlistDocument (); try { doc.LoadFromXmlFile (srcFile); } catch (Exception ex) { monitor.Log.WriteLine (ex.ToString ()); return BuildError ("Error loading entitlements source file '" + srcFile +"'."); } //insert the app ID into the plist at the beginning var oldDict = doc.Root as PlistDictionary; var newDict = new PlistDictionary (); doc.Root = newDict; newDict["application-identifier"] = identity.AppID; var keychainGroups = new PlistArray (new [] { identity.AppID } ); newDict["keychain-access-groups"] = keychainGroups; //merge in the user's values foreach (var item in oldDict) { //FIXME: we currently ignore these items, and write our own, but maybe we should do substitutes //i.e. $(AppIdentifierPrefix)$(CFBundleIdentifier) if (item.Key == "application-identifier") { var str = item.Value as PlistString; if (str == null || string.IsNullOrEmpty (str.Value) || str.Value.Contains ('$')) continue; } else if (item.Key == "keychain-access-groups") { //special handling, merge into the array var keyArr = item.Value as PlistArray; foreach (var key in keyArr) { var str = key as PlistString; if (str != null && !string.IsNullOrEmpty (str.Value) && !str.Value.Contains ('$')) { keychainGroups.Add (str.Value); } } continue; } newDict[item.Key] = item.Value; } //merge in the settings from the provisioning profile, skipping some foreach (var item in identity.Profile.Entitlements) if (item.Key != "application-identifier" && item.Key != "keychain-access-groups") newDict[item.Key] = item.Value; try { WriteXcent (doc, xcentName); } catch (Exception ex) { monitor.Log.WriteLine (ex.ToString ()); return BuildError ("Error writing entitlements file '" + xcentName +"'."); } monitor.EndTask (); return null; }
static bool BuildPackage (IProgressMonitor monitor, MonoMacProject project, ConfigurationSelector conf, MonoMacPackagingSettings settings, FilePath target) { string bundleKey = settings.BundleSigningKey; string packageKey = settings.PackageSigningKey; if (settings.SignBundle || settings.SignPackage) { var identities = Keychain.GetAllSigningIdentities (); if (string.IsNullOrEmpty (bundleKey)) { bundleKey = identities.FirstOrDefault (k => k.StartsWith (MonoMacPackagingSettingsWidget.APPLICATION_PREFIX)); if (string.IsNullOrEmpty (bundleKey)) { monitor.ReportError ("Did not find default app signing key", null); return false; } else if (!identities.Any (k => k == bundleKey)) { monitor.ReportError ("Did not find app signing key in keychain", null); return false; } } if (string.IsNullOrEmpty (packageKey)) { packageKey = identities.FirstOrDefault (k => k.StartsWith (MonoMacPackagingSettingsWidget.INSTALLER_PREFIX)); if (string.IsNullOrEmpty (packageKey)) { monitor.ReportError ("Did not find default package signing key", null); return false; } else if (!identities.Any (k => k == packageKey)) { monitor.ReportError ("Did not find package signing key in keychain", null); return false; } } } if (project.NeedsBuilding (conf)) { BuildResult res = project.Build (monitor, conf); if (res.ErrorCount > 0) { foreach (BuildError e in res.Errors) monitor.ReportError (e.ToString (), null); monitor.ReportError (GettextCatalog.GetString ("The project failed to build."), null); return false; } } var cfg = (MonoMacProjectConfiguration) project.GetConfiguration (conf); FilePath tempDir = "/tmp/monomac-build-" + DateTime.Now.Ticks; FilePath workingApp = tempDir.Combine (cfg.AppDirectory.FileName); try { monitor.BeginTask (GettextCatalog.GetString ("Creating app bundle"), 0); var files = Directory.GetFiles (cfg.AppDirectory, "*", SearchOption.AllDirectories); HashSet<string> createdDirs = new HashSet<string> (); foreach (FilePath f in files) { var rel = f.ToRelative (cfg.AppDirectory); var parentDir = rel.ParentDirectory; if (settings.IncludeMono) { if (parentDir.IsNullOrEmpty || parentDir == "." || parentDir == "Contents/MacOS") continue; var ext = rel.Extension; if (ext == ".mdb" || ext == ".exe" || ext == ".dll") continue; } if (monitor.IsCancelRequested) return false; if (createdDirs.Add (parentDir)) Directory.CreateDirectory (workingApp.Combine (parentDir)); monitor.Log.WriteLine (rel); File.Copy (f, workingApp.Combine (rel)); } monitor.EndTask (); if (settings.IncludeMono) { monitor.BeginTask (GettextCatalog.GetString ("Merging Mono into app bundle"), 0); var args = new ProcessArgumentBuilder (); args.Add ("-o"); args.AddQuoted (tempDir); args.Add ("-n"); args.AddQuoted (cfg.AppName); var assemblies = project.GetReferencedAssemblies (conf, true); foreach (var a in assemblies) { args.Add ("-a"); args.AddQuoted (a); } args.AddQuoted (cfg.CompiledOutputName); string mmpPath = Mono.Addins.AddinManager.CurrentAddin.GetFilePath ("mmp"); var psi = new ProcessStartInfo (mmpPath, args.ToString ()); monitor.Log.WriteLine ("mmp " + psi.Arguments); string err; if (MacBuildUtilities.ExecuteCommand (monitor, psi, out err) != 0) { monitor.Log.WriteLine (err); monitor.ReportError ("Merging Mono failed", null); return false; } var plistFile = workingApp.Combine ("Contents", "Info.plist"); var plistDoc = new PlistDocument (); plistDoc.LoadFromXmlFile (plistFile); ((PlistDictionary)plistDoc.Root)["MonoBundleExecutable"] = cfg.CompiledOutputName.FileName; plistDoc.WriteToFile (plistFile); monitor.EndTask (); } //TODO: verify bundle details if for app store? if (settings.SignBundle) { monitor.BeginTask (GettextCatalog.GetString ("Signing app bundle"), 0); var args = new ProcessArgumentBuilder (); args.Add ("-v", "-f", "-s"); args.AddQuoted (bundleKey, workingApp); var psi = new ProcessStartInfo ("codesign", args.ToString ()); monitor.Log.WriteLine ("codesign " + psi.Arguments); string err; if (MacBuildUtilities.ExecuteCommand (monitor, psi, out err) != 0) { monitor.Log.WriteLine (err); monitor.ReportError ("Signing failed", null); return false; } monitor.EndTask (); } if (settings.CreatePackage) { monitor.BeginTask (GettextCatalog.GetString ("Creating installer"), 0); var args = new ProcessArgumentBuilder (); args.Add ("--component"); args.AddQuoted (workingApp); args.Add ("/Applications", "--sign"); args.AddQuoted (packageKey); if (!settings.ProductDefinition.IsNullOrEmpty) { args.Add ("--product"); args.AddQuoted (settings.ProductDefinition); } args.AddQuoted (target); var psi = new ProcessStartInfo ("productbuild", args.ToString ()); monitor.Log.WriteLine ("productbuild " + psi.Arguments); string err; if (MacBuildUtilities.ExecuteCommand (monitor, psi, out err) != 0) { monitor.Log.WriteLine (err); monitor.ReportError ("Package creation failed", null); return false; } monitor.EndTask (); } else { Directory.Move (workingApp, target); } } finally { try { if (Directory.Exists (tempDir)) Directory.Delete (tempDir, true); } catch (Exception ex) { LoggingService.LogError ("Error removing temp directory", ex); } } return true; }