public static void Generate(IProgressMonitor monitor, BuildResult result, MonobjcProject project, ConfigurationSelector configuration, String outputDirectory, bool native)
        {
            // Infer application name from configuration
            String applicationName = project.GetApplicationName(configuration);

            LoggingService.LogInfo("Generate => applicationName='" + applicationName + "'");
            LoggingService.LogInfo("Generate => outputDirectory='" + outputDirectory + "'");

            // Create the bundle maker
            BundleMaker maker = new BundleMaker(applicationName, outputDirectory);

            // Compile the XIB files
            BuildHelper.CompileXIBFiles(monitor, project, maker, result);
            if (result.ErrorCount > 0)
            {
                monitor.ReportError(GettextCatalog.GetString("Failed to compile XIB files"), null);
                return;
            }

            // Copy the output and dependencies
            BuildHelper.CopyOutputFiles(monitor, project, configuration, maker);

            // Copy the content files
            BuildHelper.CopyContentFiles(monitor, project, configuration, maker);

            // Create the Info.plist
            BuildHelper.CreateInfoPList(monitor, project, configuration, maker);

            if (native)
            {
                GenerateNative(monitor, result, project, configuration, maker);
            }
            else
            {
                // Copy the Monobjc assemblies
                BuildHelper.CopyMonobjcAssemblies(monitor, project, configuration, maker);

                // Write the native runtime
                monitor.BeginTask(GettextCatalog.GetString("Copying native launcher..."), 0);
                maker.WriteRuntime(project.TargetOSVersion);
                monitor.EndTask();
            }

            BuildHelper.CombineArtwork(monitor, project, maker);
            BuildHelper.EncryptContentFiles(monitor, project, configuration, maker);

            // Perform the signing
            BuildHelper.SignBundle(monitor, project, maker);
            BuildHelper.SignNativeBinaries(monitor, project, maker);
        }
        public static void Archive(IProgressMonitor monitor, BuildResult result, MonobjcProject project, ConfigurationSelector configuration, String outputDirectory)
        {
            monitor.BeginTask(GettextCatalog.GetString("Archiving..."), 0);

            // Infer application name from configuration
            String applicationName = project.GetApplicationName(configuration);

            // Create the bundle maker
            BundleMaker maker = new BundleMaker(applicationName, outputDirectory);

            // Archive the application
            BuildHelper.ArchiveBundle(monitor, project, maker);

            monitor.EndTask();
        }
        /// <summary>
        /// Combines the artwork.
        /// </summary>
        public static void CombineArtwork(IProgressMonitor monitor, MonobjcProject project, BundleMaker maker)
        {
            if (!project.CombineArtwork) {
                return;
            }

            monitor.BeginTask (GettextCatalog.GetString ("Combining artwork..."), 0);
            using (StringWriter outputWriter = new StringWriter()) {
                using (StringWriter errorWriter = new StringWriter()) {
                    ArtworkCombiner combiner = new ArtworkCombiner();
                    combiner.Combine(maker.ResourcesFolder, outputWriter, errorWriter);
                    LoggingService.LogInfo ("Combiner returns: " + outputWriter.ToString ());
                }
            }
            monitor.EndTask ();
        }
        /// <summary>
        ///   Archive the application bundle.
        /// </summary>
        /// <param name = 'monitor'>The progress monitor.</param>
        /// <param name = 'project'>The project.</param>
        /// <param name = 'maker'>The bundle maker.</param>
        public static void ArchiveBundle(IProgressMonitor monitor, MonobjcProject project, BundleMaker maker)
        {
            if (project.Archive && project.ArchiveIdentity != null) {
                FilePath definitionFile = project.BaseDirectory.Combine ("Definition.plist");
                String definitionFilename = File.Exists (definitionFile) ? definitionFile.ToString () : null;
                monitor.BeginTask (GettextCatalog.GetString ("Signing archive..."), 0);

                using (StringWriter outputWriter = new StringWriter()) {
                    using (StringWriter errorWriter = new StringWriter()) {
                        ProductBuild.ArchiveApplication (maker.ApplicationDirectory, project.ArchiveIdentity, definitionFilename, outputWriter, errorWriter);
                        LoggingService.LogInfo ("ProductBuild returns: " + outputWriter.ToString ());
                    }
                }

                monitor.EndTask ();
            }
        }
 /// <summary>
 ///   Compiles the XIB files.
 /// </summary>
 /// <param name = 'monitor'>The progress monitor.</param>
 /// <param name = 'project'>The project.</param>
 /// <param name = 'maker'>The bundle maker.</param>
 /// <param name = 'result'>The build result.</param>
 public static void CompileXIBFiles(IProgressMonitor monitor, MonobjcProject project, BundleMaker maker, BuildResult result)
 {
     XibCompiler xibCompiler = new XibCompiler ();
     IEnumerable<FilePair> files = project.GetIBFiles (Constants.InterfaceDefinition, maker.ResourcesFolder);
     if (files == null || files.Count() == 0) {
         return;
     }
     List<FilePair> pairs = new List<FilePair> (files);
     monitor.BeginTask (GettextCatalog.GetString ("Compiling XIB files..."), files.Count ());
     foreach (FilePair pair in pairs) {
         monitor.Log.WriteLine (GettextCatalog.GetString ("Compiling {0}", pair.Source.ToRelative (project.BaseDirectory)));
         xibCompiler.Logger = new BuildLogger (pair.Source, monitor, result);
         xibCompiler.Compile (pair.Source, pair.DestinationDir);
         monitor.Step (1);
     }
     monitor.EndTask ();
 }
        /// <summary>
        ///   Sign the native libraries inside the bundle.
        /// </summary>
        /// <param name = 'monitor'>The progress monitor.</param>
        /// <param name = 'project'>The project.</param>
        /// <param name = 'maker'>The bundle maker.</param>
        public static void SignNativeBinaries(IProgressMonitor monitor, MonobjcProject project, BundleMaker maker)
        {
            if (project.Signing && !String.IsNullOrEmpty(project.SigningIdentity)) {
                String[] files = Directory.GetFiles (maker.MacOSDirectory, "*.dylib");
                if (files == null || files.Count() == 0) {
                    return;
                }

                monitor.BeginTask (GettextCatalog.GetString ("Signing native libraries..."), files.Length);

                foreach (String file in files) {
                    using (StringWriter outputWriter = new StringWriter()) {
                        using (StringWriter errorWriter = new StringWriter()) {
                            CodeSign.PerformSigning (file, project.SigningIdentity, outputWriter, errorWriter);
                            LoggingService.LogInfo ("CodeSign returns: " + outputWriter.ToString ());
                        }
                    }
                    monitor.Step (1);
                }

                monitor.EndTask ();
            }
        }
        /// <summary>
        ///   Sign the application bundle.
        /// </summary>
        /// <param name = 'monitor'>The progress monitor.</param>
        /// <param name = 'project'>The project.</param>
        /// <param name = 'maker'>The bundle maker.</param>
        public static void SignBundle(IProgressMonitor monitor, MonobjcProject project, BundleMaker maker)
        {
            if (project.Signing && !String.IsNullOrEmpty(project.SigningIdentity)) {
                monitor.BeginTask (GettextCatalog.GetString ("Signing bundle..."), 0);

                using (StringWriter outputWriter = new StringWriter()) {
                    using (StringWriter errorWriter = new StringWriter()) {
                        FilePath file = project.BaseDirectory.Combine(Constants.APP_ENTITLEMENTS);
                        if (project.UseEntitlements && File.Exists(file)) {
                            monitor.Log.WriteLine (GettextCatalog.GetString ("Signing with identity '{0}' and entitlements '{1}'", project.SigningIdentity, file.FileName));
                            CodeSign.PerformSigning (maker.ApplicationDirectory, project.SigningIdentity, file, outputWriter, errorWriter);
                        } else {
                            monitor.Log.WriteLine (GettextCatalog.GetString ("Signing with identity='{0}'", project.SigningIdentity));
                            CodeSign.PerformSigning (maker.ApplicationDirectory, project.SigningIdentity, outputWriter, errorWriter);
                        }
                        LoggingService.LogInfo ("CodeSign returns: " + outputWriter.ToString ());
                    }
                }

                monitor.EndTask ();
            }
        }
 /// <summary>
 /// Combines the artwork.
 /// </summary>
 public static void EncryptContentFiles(IProgressMonitor monitor, MonobjcProject project, ConfigurationSelector configuration, BundleMaker maker)
 {
     IEnumerable<FilePair> files = project.GetEncryptedContentFiles (configuration, maker.ResourcesFolder);
     if (files == null || files.Count() == 0) {
         return;
     }
     Aes provider = FileEncrypter.GetProvider (project.EncryptionSeed);
     monitor.BeginTask (GettextCatalog.GetString ("Encrypting content files..."), files.Count ());
     foreach (FilePair pair in files) {
         monitor.Log.WriteLine (GettextCatalog.GetString ("Encrypting {0}", pair.Source.ToRelative (project.BaseDirectory)));
         pair.Encrypt(provider);
         monitor.Step (1);
     }
     monitor.EndTask ();
 }
        /// <summary>
        ///   Creates the Info.plist file.
        /// </summary>
        /// <param name = 'monitor'>The progress monitor.</param>
        /// <param name = 'project'>The project.</param>
        /// <param name = 'configuration'>The configuration.</param>
        /// <param name = 'maker'>The bundle maker.</param>
        public static void CreateInfoPList(IProgressMonitor monitor, MonobjcProject project, ConfigurationSelector configuration, BundleMaker maker)
        {
            monitor.BeginTask (GettextCatalog.GetString ("Generating the Info.plist..."), 0);

            InfoPListGenerator pListGenerator = new InfoPListGenerator ();

            // If an Info.plist exists in the project then use it
            FilePath infoPListFile = project.BaseDirectory.Combine (Constants.INFO_PLIST);
            if (File.Exists (infoPListFile)) {
                pListGenerator.Content = File.ReadAllText (infoPListFile);
            }

            String mainAssembly = project.GetOutputFileName (configuration);
            Assembly assembly = Assembly.ReflectionOnlyLoadFrom (mainAssembly);
            AssemblyName assemblyName = assembly.GetName ();

            // TODO: Review to use new parameters
            pListGenerator.DevelopmentRegion = project.DevelopmentRegion;
            pListGenerator.ApplicationName = assemblyName.Name;
            pListGenerator.Identifier = project.BundleId;
            pListGenerator.Version = project.BundleVersion;
            pListGenerator.Icon = project.BundleIcon.IsNullOrEmpty ? null : project.BundleIcon.FileNameWithoutExtension;
            pListGenerator.MainNibFile = project.MainNibFile.IsNullOrEmpty ? null : project.MainNibFile.FileNameWithoutExtension;
            pListGenerator.TargetOSVersion = project.TargetOSVersion;
            pListGenerator.PrincipalClass = "NSApplication";
            pListGenerator.WriteTo (Path.Combine (maker.ContentsDirectory, Constants.INFO_PLIST));

            monitor.EndTask ();
        }
 /// <summary>
 ///   Copies the content files.
 /// </summary>
 /// <param name = 'monitor'>The progress monitor.</param>
 /// <param name = 'project'>The project.</param>
 /// <param name = 'configuration'>The configuration.</param>
 /// <param name = 'maker'>The bundle maker.</param>
 public static void CopyOutputFiles(IProgressMonitor monitor, MonobjcProject project, ConfigurationSelector configuration, BundleMaker maker)
 {
     IEnumerable<FilePair> files = project.GetOutputFiles (configuration, maker.ResourcesFolder);
     if (files == null || files.Count() == 0) {
         return;
     }
     monitor.BeginTask (GettextCatalog.GetString ("Copying output files..."), files.Count ());
     foreach (FilePair pair in files) {
         monitor.Log.WriteLine (GettextCatalog.GetString ("Copying {0}", pair.Source.ToRelative (project.BaseDirectory)));
         pair.Copy (false);
         monitor.Step (1);
     }
     monitor.EndTask ();
 }
 /// <summary>
 /// Copies the Monobjc assemblies.
 /// </summary>
 /// <param name="monitor">The monitor.</param>
 /// <param name="project">The project.</param>
 /// <param name="configuration">The configuration.</param>
 /// <param name="maker">The maker.</param>
 public static void CopyMonobjcAssemblies(IProgressMonitor monitor, MonobjcProject project, ConfigurationSelector configuration, BundleMaker maker)
 {
     IEnumerable<String> assemblies = project.ProjectMonobjcAssemblies.Select (a => a.GetReferencedFileNames (configuration) [0]);
     monitor.BeginTask (GettextCatalog.GetString ("Copying Monobjc assemblies..."), assemblies.Count ());
     foreach (String assembly in assemblies) {
         String filename = Path.GetFileName (assembly);
         monitor.Log.WriteLine (GettextCatalog.GetString ("Copying {0}", filename));
         File.Copy (assembly, Path.Combine (maker.ResourcesFolder, filename), true);
         monitor.Step (1);
     }
     monitor.EndTask ();
 }
		/// <summary>
		///   Creates the execution command.
		/// </summary>
		/// <param name = "configSel">The configuration selector.</param>
		/// <param name = "configuration">The configuration.</param>
		/// <returns>The execution command.</returns>
		protected override ExecutionCommand CreateExecutionCommand (ConfigurationSelector configSel, DotNetProjectConfiguration configuration)
		{
			if (this.CompileTarget != CompileTarget.Exe) {
				return base.CreateExecutionCommand (configSel, configuration);
			}

			if (this.projectType == MonobjcProjectType.None) {
				return base.CreateExecutionCommand (configSel, configuration);
			}

			// Infer application name from configuration
			MonobjcProjectConfiguration conf = (MonobjcProjectConfiguration)configuration;
			String applicationName = this.GetApplicationName (configSel);
			conf.ApplicationName = applicationName;
			
			switch (this.ApplicationType) {
			case MonobjcProjectType.CocoaApplication:
				{
					// Create the bundle maker to get the path to the runtime
					BundleMaker maker = new BundleMaker (applicationName, conf.OutputDirectory);
					conf.Runtime = maker.Runtime;
				}
				break;
			case MonobjcProjectType.ConsoleApplication:
				{
					// Build the command line
					conf.Runtime = FileProvider.GetPath (this.TargetOSVersion, "runtime");
					conf.CommandLineParameters = this.GetOutputFileName (configSel);
				}
				break;
			default:
				throw new NotSupportedException ("Unsupported application type " + this.ApplicationType);
			}

			// Create the command
			MonobjcExecutionCommand command = new MonobjcExecutionCommand (conf);
			command.UserAssemblyPaths = this.GetUserAssemblyPaths (configSel);

			return command;
		}
        private static void GenerateNative(IProgressMonitor monitor, BuildResult result, MonobjcProject project, ConfigurationSelector configuration, BundleMaker maker)
        {
            // Create a directory for generation
            String tempDir = Path.Combine(project.GetOutputFileName(configuration).ParentDirectory, ".native");
            Directory.CreateDirectory(tempDir);

            // Build a list of all folders to visit when collecting managed references
            String mainAssembly = project.GetOutputFileName(configuration);
            String configurationDir = Path.GetDirectoryName(mainAssembly);
            List<String> searchDirs = new List<String>();
            searchDirs.Add(configurationDir);

            // For each reference, add its base dir
            foreach (ProjectReference reference in project.References)
            {
                String[] files = reference.GetReferencedFileNames(configuration);
                foreach (string file in files)
                {
                    String dir = Path.GetDirectoryName(file);
                    searchDirs.Add(dir);
                }
            }

            // Remove redundant entries
            searchDirs = searchDirs.Distinct().ToList();

            // Collect all the assemblies
            monitor.BeginTask(GettextCatalog.GetString("Collecting assemblies..."), 0);
            ManagedReferenceCollector collector = new ManagedReferenceCollector();
            collector.Logger = new BuildLogger(monitor, result);
            collector.SearchDirectories = searchDirs;
            monitor.EndTask();

            // Collect the main assembly references
            List<String> assemblies = new List<String>();
            assemblies.AddRange(collector.Collect(mainAssembly));

            // Remove redundant entries
            assemblies = assemblies.Distinct().ToList();

            // Generate the embedded executable
            monitor.BeginTask(GettextCatalog.GetString("Generating native code..."), 0);
            NativeCodeGenerator codeGenerator = new NativeCodeGenerator();
            codeGenerator.Logger = new BuildLogger(monitor, result);
            codeGenerator.Assemblies = assemblies;
            codeGenerator.DeveloperToolsFolder = DeveloperToolsDesktopApplication.DeveloperToolsFolder;
            codeGenerator.TargetOSVersion = project.TargetOSVersion;
            codeGenerator.TargetArchitecture = project.TargetOSArch;

            // We embed the machine.config file; it depends on the target framework
            int version = (int) project.TargetFramework.ClrVersion;
            switch (version)
            {
                case 2: // ClrVersion.Net_2_0:
                    codeGenerator.MachineConfiguration = "/Library/Frameworks/Mono.framework/Home/etc/mono/2.0/machine.config";
                    break;
                case 4: // ClrVersion.Net_4_0:
                    codeGenerator.MachineConfiguration = "/Library/Frameworks/Mono.framework/Home/etc/mono/4.0/machine.config";
                    break;
                case 5: // ClrVersion.Net_4_5:
                    codeGenerator.MachineConfiguration = "/Library/Frameworks/Mono.framework/Home/etc/mono/4.5/machine.config";
                    break;
            }

            // Launch the generation
            String executableFile = codeGenerator.Generate(tempDir);
            String libraryFile = Path.Combine(tempDir, "libmonobjc.dylib");
            monitor.EndTask();

            // Copy the native parts into the bundle
            monitor.BeginTask(GettextCatalog.GetString("Copying native code..."), 0);
            maker.CopyTo(executableFile, maker.MacOSDirectory);
            maker.CopyTo(libraryFile, maker.MacOSDirectory);
            monitor.EndTask();

            // Change the paths
            executableFile = maker.Combine(maker.MacOSDirectory, executableFile);
            libraryFile = maker.Combine(maker.MacOSDirectory, libraryFile);

            // Relocate the libraries
            monitor.BeginTask(GettextCatalog.GetString("Relocating native code..."), 0);
            NativeCodeRelocator relocator = new NativeCodeRelocator();
            relocator.Logger = new BuildLogger(monitor, result);
            relocator.DependencyPattern = new List<string> {"Mono.framework"};
            relocator.Relocate(executableFile, maker.MacOSDirectory);
            relocator.Relocate(libraryFile, maker.MacOSDirectory);
            monitor.EndTask();
        }
        /// <summary>
        ///   Cleans the specified solution item.
        /// </summary>
        /// <param name = "monitor">The monitor.</param>
        /// <param name = "item">The item.</param>
        /// <param name = "configuration">The configuration.</param>
        protected override void Clean(IProgressMonitor monitor, SolutionEntityItem item, ConfigurationSelector configuration)
        {
            // Call base implementation
            base.Clean (monitor, item, configuration);

            // Balk if the project is not a Monobjc one
            MonobjcProject project = item as MonobjcProject;
            if (project == null) {
                return;
            }

            // Call specific implementation
            switch (project.ApplicationType) {
            case MonobjcProjectType.CocoaApplication:
                {
                    MonobjcProjectConfiguration conf = (MonobjcProjectConfiguration)project.GetConfiguration (configuration);

                    // Infer application name from configuration
                    string applicationName = project.GetApplicationName (configuration);

                    // Create the bundle maker
                    BundleMaker maker = new BundleMaker (applicationName, conf.OutputDirectory);

                    // Remove the application bundle
                    Directory.Delete (maker.ApplicationDirectory, true);
                }
                break;
            case MonobjcProjectType.ConsoleApplication:
                {
                    // Do nothing
                }
                break;
            case MonobjcProjectType.CocoaLibrary:
                {
                    // Do nothing
                }
                break;
            default:
                throw new NotSupportedException ("Unsupported application type " + project.ApplicationType);
            }
        }
        /// <summary>
        ///   Checks if the solution items needs building.
        /// </summary>
        /// <param name = "item">The item.</param>
        /// <param name = "configuration">The configuration.</param>
        /// <returns></returns>
        protected override bool GetNeedsBuilding(SolutionEntityItem item, ConfigurationSelector configuration)
        {
            // Call base implementation
            bool result = base.GetNeedsBuilding (item, configuration);

            // Balk if the project is not a Monobjc one
            MonobjcProject project = item as MonobjcProject;
            if (result || project == null) {
                return result;
            }

            // Call specific implementation
            switch (project.ApplicationType) {
            case MonobjcProjectType.CocoaApplication:
                {
                    MonobjcProjectConfiguration conf = (MonobjcProjectConfiguration)project.GetConfiguration (configuration);

                    // Infer application name from configuration
                    string applicationName = project.GetApplicationName (configuration);

                    // Create the bundle maker
                    BundleMaker maker = new BundleMaker (applicationName, conf.OutputDirectory);

                    // Info.plist
                    if (!File.Exists (Path.Combine (maker.ContentsDirectory, Constants.INFO_PLIST))) {
                        return true;
                    }

                    // Runtime executable
                    if (!File.Exists (maker.Runtime)) {
                        return true;
                    }

                    // The IB files
                    if (project.GetIBFiles (Constants.InterfaceDefinition, maker.ResourcesFolder).Where (p => p.NeedsBuilding).Any ()) {
                        return true;
                    }

                    // The IB files
                    if (project.GetIBFiles (Constants.EmbeddedInterfaceDefinition, null).Where (p => p.NeedsBuilding).Any ()) {
                        return true;
                    }

                    // The output files (output assembly and references)
                    if (project.GetOutputFiles (configuration, maker.ResourcesFolder).Where (p => p.NeedsBuilding).Any ()) {
                        return true;
                    }

                    // The content files (file marked as content)
                    if (project.GetContentFiles (configuration, maker.ResourcesFolder).Where (p => p.NeedsBuilding).Any ()) {
                        return true;
                    }
                }
                break;
            case MonobjcProjectType.ConsoleApplication:
                {
                    // Do nothing
                }
                break;
            case MonobjcProjectType.CocoaLibrary:
                {
                    // The IB files
                    if (project.GetIBFiles (Constants.EmbeddedInterfaceDefinition, null).Where (p => p.NeedsBuilding).Any ()) {
                        return true;
                    }
                }
                break;
            default:
                throw new NotSupportedException ("Unsupported application type " + project.ApplicationType);
            }

            return false;
        }