Beispiel #1
0
        void FileRemovedFromProject(object sender, ProjectFileEventArgs e)
        {
            lock (xcode_lock) {
                if (!SyncingEnabled)
                {
                    return;
                }

                XC4Debug.Log("Files removed from project '{0}'", dnp.Name);
                foreach (var file in e)
                {
                    XC4Debug.Log("   * Removed: {0}", file.ProjectFile.ProjectVirtualPath);
                }

                XC4Debug.Indent();
                try {
                    if (e.Any(finf => finf.Project == dnp && IsInterfaceDefinition(finf.ProjectFile)))
                    {
                        if (!dnp.Files.Any(IsInterfaceDefinition))
                        {
                            XC4Debug.Log("Last Interface Definition file removed from '{0}', disabling Xcode sync.", dnp.Name);
                            DisableSyncing(true);
                            return;
                        }
                    }
                } finally {
                    XC4Debug.Unindent();
                }

                CheckFileChanges(e);
            }
        }
Beispiel #2
0
        void DisableSyncing(bool closeProject)
        {
            if (!SyncingEnabled)
            {
                return;
            }

            XC4Debug.Log("Disabled syncing for project: {0}", dnp.Name);

            XC4Debug.Indent();
            try {
                if (closeProject)
                {
                    xcode.CloseProject();
                }
                xcode.DeleteProjectDirectory();
            } finally {
                MonoDevelop.Ide.IdeApp.CommandService.ApplicationFocusIn -= AppRegainedFocus;
                dnp.FileAddedToProject           -= FileAddedToProject;
                dnp.FilePropertyChangedInProject -= FilePropertyChangedInProject;;
                dnp.FileRemovedFromProject       -= FileRemovedFromProject;
                dnp.FileChangedInProject         -= FileChangedInProject;
                dnp.NameChanged -= ProjectNameChanged;

                XC4Debug.Unindent();
                xcode = null;
            }
        }
 void ProjectNameChanged(object sender, SolutionItemRenamedEventArgs e)
 {
     XC4Debug.Log("Project name changed, resetting sync");
     xcode.CloseProject();
     xcode.DeleteProjectDirectory();
     xcode = new XcodeMonitor(dnp.BaseDirectory.Combine("obj", "Xcode"), dnp.Name);
 }
Beispiel #4
0
 void DeleteXcproj()
 {
     XC4Debug.Log("Deleting project artifacts");
     if (Directory.Exists(xcproj))
     {
         Directory.Delete(xcproj, true);
     }
 }
Beispiel #5
0
        public bool OpenProject()
        {
            SyncProject();
            var success = AppleScript.Run(XCODE_OPEN_PROJECT, AppleSdkSettings.XcodePath, projectDir) == "true";

            XC4Debug.Log("Opening project: {0}", success);
            return(success);
        }
        public bool OpenDocument(string file)
        {
            XC4Debug.Log("Opening file {0}", file);
            var xibFile = dnp.Files.GetFile(file);

            System.Diagnostics.Debug.Assert(xibFile != null);
            System.Diagnostics.Debug.Assert(IsInterfaceDefinition(xibFile));

            return(OpenFileInXcodeProject(xibFile.ProjectVirtualPath));
        }
        //FIXME: should be use a modal monitor to prevent the user doing unexpected things?
        IProgressMonitor GetStatusMonitor(string title)
        {
            IProgressMonitor monitor = MonoDevelop.Ide.IdeApp.Workbench.ProgressMonitors.GetStatusProgressMonitor(
                title, null, true);

            monitor = new MonoDevelop.Core.ProgressMonitoring.AggregatedProgressMonitor(
                monitor, XC4Debug.GetLoggingMonitor());

            return(monitor);
        }
Beispiel #8
0
        public bool CloseProject()
        {
            if (!CheckRunning())
            {
                return(true);
            }

            var success = AppleScript.Run(XCODE_CLOSE_IN_PATH, AppleSdkSettings.XcodePath, projectDir) == "true";

            XC4Debug.Log("Closing project: {0}", success);
            return(success);
        }
Beispiel #9
0
        public bool CloseFile(string fileName)
        {
            if (!CheckRunning())
            {
                return(true);
            }

            var success = AppleScript.Run(XCODE_CLOSE_IN_PATH, AppleSdkSettings.XcodePath, fileName) == "true";

            XC4Debug.Log("Closing file {0}: {1}", fileName, success);
            return(success);
        }
        void FileRemovedFromProject(object sender, ProjectFileEventArgs e)
        {
            if (syncing && e.Any(finf => finf.Project == dnp && IsInterfaceDefinition(finf.ProjectFile)))
            {
                if (!dnp.Files.Any(IsInterfaceDefinition))
                {
                    XC4Debug.Log("All page files removed, disabling sync");
                    DisableSyncing();
                    return;
                }
            }

            CheckFileChanges(e);
        }
Beispiel #11
0
        void ProjectNameChanged(object sender, SolutionItemRenamedEventArgs e)
        {
            XC4Debug.Log("Project '{0}' was renamed to '{1}', resetting Xcode sync.", e.OldName, e.NewName);

            XC4Debug.Indent();
            try {
                xcode.CloseProject();
                xcode.DeleteProjectDirectory();
            } finally {
                XC4Debug.Unindent();
            }

            xcode = new XcodeMonitor(dnp.BaseDirectory.Combine("obj", "Xcode"), dnp.Name);
        }
Beispiel #12
0
        void FileAddedToProject(object sender, ProjectFileEventArgs e)
        {
            if (!SyncingEnabled)
            {
                return;
            }

            XC4Debug.Log("Files added to project '{0}'", dnp.Name);
            foreach (var file in e)
            {
                XC4Debug.Log("   * Added: {0}", file.ProjectFile.ProjectVirtualPath);
            }

            CheckFileChanges(e);
        }
Beispiel #13
0
        void FilePropertyChangedInProject(object sender, ProjectFileEventArgs e)
        {
            if (!SyncingEnabled)
            {
                return;
            }

            XC4Debug.Log("File properties changed in project '{0}'", dnp.Name);
            foreach (var file in e)
            {
                XC4Debug.Log("   * Property Changed: {0}", file.ProjectFile.ProjectVirtualPath);
            }

            CheckFileChanges(e);
        }
        void CheckFileChanges(ProjectFileEventArgs e)
        {
            if (!syncing)
            {
                return;
            }

            XC4Debug.Log("Checking for changed files");
            bool updateTypes = false, updateProject = false;

            foreach (ProjectFileEventInfo finf in e)
            {
                if (finf.Project != dnp)
                {
                    continue;
                }
                if (finf.ProjectFile.BuildAction == BuildAction.Compile)
                {
                    updateTypes = true;
                }
                else if (IncludeInSyncedProject(finf.ProjectFile))
                {
                    updateProject = true;
                }
            }

            if (updateTypes)
            {
                using (var monitor = GetStatusMonitor(GettextCatalog.GetString("Syncing types to Xcode..."))) {
                    //FIXME: make this async (and safely async)
                    //FIXME: only update the project if obj-c types change
                    updateProject |= UpdateTypes(monitor, true);
                }
            }

            if (updateProject)
            {
                using (var monitor = GetStatusMonitor(GettextCatalog.GetString("Syncing project to Xcode..."))) {
                    //FIXME: make this async (and safely async)
                    var running = xcode.CheckRunning();
                    UpdateXcodeProject(monitor);
                    if (running)
                    {
                        xcode.OpenProject();
                    }
                }
            }
        }
Beispiel #15
0
        void FileChangedInProject(object sender, ProjectFileEventArgs e)
        {
            // avoid infinite recursion when we add files
            if (!SyncingEnabled || updatingProjectFiles)
            {
                return;
            }

            XC4Debug.Log("Files changed in project '{0}'", dnp.Name);
            foreach (var file in e)
            {
                XC4Debug.Log("   * Changed: {0}", file.ProjectFile.ProjectVirtualPath);
            }

            CheckFileChanges(e);
        }
        public void DeleteProjectDirectory()
        {
            bool isRunning = CheckRunning();

            XC4Debug.Log("Deleting temporary Xcode project directories.");

            try
            {
                if (Directory.Exists(projectDir))
                {
                    Directory.Delete(projectDir, true);
                }
            }
            catch (Exception ex)
            {
                XC4Debug.Indent();
                XC4Debug.Log(ex.Message);
                XC4Debug.Unindent();
            }

            if (isRunning)
            {
                XC4Debug.Log("Xcode still running, leaving empty directory in place to prevent name re-use.");
                if (!Directory.Exists(projectDir))
                {
                    Directory.CreateDirectory(projectDir);
                }
            }
            else
            {
                XC4Debug.Log("Xcode not running, removing all temporary directories.");
                try
                {
                    if (Directory.Exists(originalProjectDir))
                    {
                        Directory.Delete(originalProjectDir, true);
                    }
                }
                catch (Exception ex)
                {
                    XC4Debug.Indent();
                    XC4Debug.Log(ex.Message);
                    XC4Debug.Unindent();
                }
            }
        }
        void EnableSyncing()
        {
            if (syncing)
            {
                return;
            }
            syncing = true;
            xcode   = new XcodeMonitor(dnp.BaseDirectory.Combine("obj", "Xcode"), dnp.Name);

            XC4Debug.Log("Enabled syncing for project: {0}", dnp.Name);

            dnp.FileAddedToProject           += FileAddedToProject;
            dnp.FilePropertyChangedInProject += FilePropertyChangedInProject;
            dnp.FileRemovedFromProject       += FileRemovedFromProject;
            dnp.FileChangedInProject         += FileChangedInProject;
            dnp.NameChanged += ProjectNameChanged;
            MonoDevelop.Ide.IdeApp.CommandService.ApplicationFocusIn += AppRegainedFocus;
        }
Beispiel #18
0
        // Xcode keeps some kind of internal lock on project files while it's running and
        // gets extremely unhappy if a new or changed project is in the same location as
        // a previously opened one.
        //
        // To work around this we increment a subdirectory name and use that, and do some
        // careful bookkeeping to reduce the unnecessary I/O overhead that this adds.
        //
        void HackRelocateProject()
        {
            var oldProjectDir = projectDir;

            HackGetNextProjectDir();
            XC4Debug.Log("Relocating {0} to {1}", oldProjectDir, projectDir);
            foreach (var f in syncTimeCache)
            {
                var target = projectDir.Combine(f.Key);
                var src    = oldProjectDir.Combine(f.Key);
                var parent = target.ParentDirectory;
                if (!Directory.Exists(parent))
                {
                    Directory.CreateDirectory(parent);
                }
                File.Move(src, target);
            }
        }
Beispiel #19
0
        public void CloseProject()
        {
            if (!CheckRunning())
            {
                return;
            }

            XC4Debug.Log("Asking Xcode to close the {0} project...", name);

            try {
                // Exceptions closing the project are non-fatal.
                bool closed = AppleScript.Run(XCODE_CLOSE_IN_PATH, AppleSdkSettings.XcodePath, projectDir) == "true";
                XC4Debug.Log("Xcode {0} the project.", closed ? "successfully closed" : "failed to close");
            } catch (AppleScriptException asex) {
                XC4Debug.Log("Xcode failed to close the project: OSAError {0}: {1}", (int)asex.ErrorCode, asex.Message);
            } catch (TimeoutException) {
                XC4Debug.Log("Xcode timed out trying to close the project.");
            }
        }
        void DisableSyncing()
        {
            if (!syncing)
            {
                return;
            }
            syncing = false;

            xcode.CloseProject();
            xcode.DeleteProjectDirectory();
            xcode = null;

            XC4Debug.Log("Disabled syncing for project: {0}", dnp.Name);

            dnp.FileAddedToProject           -= FileAddedToProject;
            dnp.FilePropertyChangedInProject -= FilePropertyChangedInProject;;
            dnp.FileRemovedFromProject       -= FileRemovedFromProject;
            dnp.FileChangedInProject         -= FileChangedInProject;
            dnp.NameChanged -= ProjectNameChanged;
            MonoDevelop.Ide.IdeApp.CommandService.ApplicationFocusIn -= AppRegainedFocus;
        }
        void AppRegainedFocus(object sender, EventArgs e)
        {
            if (!syncing)
            {
                return;
            }

            bool isOpen = false;

            using (var monitor = GetStatusMonitor(GettextCatalog.GetString("Synchronizing changes from Xcode"))) {
                try {
                    isOpen = xcode != null && xcode.IsProjectOpen();
                    if (isOpen)
                    {
                        monitor.BeginTask(GettextCatalog.GetString("Saving Xcode project"), 0);
                        xcode.SaveProject();
                    }
                } catch (Exception ex) {
                    MonoDevelop.Ide.MessageService.ShowError(
                        GettextCatalog.GetString("MonoDevelop could not communicate with XCode"),
                        GettextCatalog.GetString(
                            "If XCode is still running, please ensure that all changes have been saved and " +
                            "XCode has been exited before continuing, otherwise any new changes may be lost."));
                    monitor.Log.WriteLine("XCode could not be made save pending changes: {0}", ex);
                }
                if (isOpen)
                {
                    monitor.EndTask();
                }

                SyncXcodeChanges(monitor);
            }

            if (!isOpen)
            {
                XC4Debug.Log("Project closed, disabling syncing");
                DisableSyncing();
            }
        }
Beispiel #22
0
        void AppRegainedFocus(object sender, EventArgs e)
        {
            lock (xcode_lock) {
                if (!SyncingEnabled)
                {
                    return;
                }

                XC4Debug.Log("MonoDevelop has regained focus.");

                using (var monitor = GetStatusMonitor(GettextCatalog.GetString("Synchronizing changes from Xcode..."))) {
                    bool projectOpen = false;

                    try {
                        // Note: Both IsProjectOpen() and SaveProject() may throw TimeoutExceptions or AppleScriptExceptions
                        if ((projectOpen = xcode.IsProjectOpen()))
                        {
                            xcode.SaveProject(monitor);
                        }
                    } catch (Exception ex) {
                        ShowXcodeScriptError();
                        monitor.Log.WriteLine("Xcode failed to save pending changes to project: {0}", ex);

                        // Note: This will cause us to disable syncing after we sync whatever we can over from Xcode...
                        projectOpen = false;
                    }

                    try {
                        SyncXcodeChanges(monitor);
                    } finally {
                        if (!projectOpen)
                        {
                            XC4Debug.Log("Xcode project for '{0}' is not open, disabling syncing.", dnp.Name);
                            DisableSyncing(false);
                        }
                    }
                }
            }
        }
Beispiel #23
0
        public void DeleteProjectDirectory()
        {
            XC4Debug.Log("Deleting temp project directories");
            bool isRunning = CheckRunning();

            if (Directory.Exists(projectDir))
            {
                Directory.Delete(projectDir, true);
            }
            if (isRunning)
            {
                XC4Debug.Log("Xcode still running, leaving empty directory in place to prevent name re-use");
                Directory.CreateDirectory(projectDir);
            }
            else
            {
                XC4Debug.Log("Xcode not running, removing all temp directories");
                if (Directory.Exists(this.originalProjectDir))
                {
                    Directory.Delete(this.originalProjectDir, true);
                }
            }
        }
Beispiel #24
0
 public void OpenFile(string relativeName)
 {
     XC4Debug.Log("Opening file in Xcode: {0}", relativeName);
     SyncProject();
     AppleScript.Run(XCODE_OPEN_PROJECT_FILE, AppleSdkSettings.XcodePath, xcproj, projectDir.Combine(relativeName));
 }
Beispiel #25
0
        public void UpdateProject(IProgressMonitor monitor, List <XcodeSyncedItem> allItems, XcodeProject emptyProject)
        {
            items = allItems;

            monitor.BeginTask(GettextCatalog.GetString("Updating Xcode project..."), items.Count);
            monitor.Log.WriteLine("Updating synced project with {0} items", items.Count);
            XC4Debug.Log("Updating synced project with {0} items", items.Count);

            var ctx = new XcodeSyncContext(projectDir, syncTimeCache);

            var  toRemove      = new HashSet <string> (itemMap.Keys);
            var  toClose       = new HashSet <string> ();
            var  syncList      = new List <XcodeSyncedItem> ();
            bool updateProject = false;

            foreach (var item in items)
            {
                bool needsSync = item.NeedsSyncOut(ctx);
                if (needsSync)
                {
                    syncList.Add(item);
                }

                var files = item.GetTargetRelativeFileNames();
                foreach (var f in files)
                {
                    toRemove.Remove(f);
                    if (!itemMap.ContainsKey(f))
                    {
                        updateProject = true;
                    }
                    else if (needsSync)
                    {
                        toClose.Add(f);
                    }
                    itemMap [f] = item;
                }
            }
            updateProject = updateProject || toRemove.Any();

            bool removedOldProject = false;

            if (updateProject)
            {
                if (pendingProjectWrite == null && ProjectExists())
                {
                    monitor.Log.WriteLine("Project file needs to be updated, closing and removing old project");
                    CloseProject();
                    DeleteXcproj();
                    removedOldProject = true;
                }
            }
            else
            {
                foreach (var f in toClose)
                {
                    CloseFile(projectDir.Combine(f));
                }
            }

            foreach (var f in toRemove)
            {
                itemMap.Remove(f);
                syncTimeCache.Remove(f);
                var path = projectDir.Combine(f);
                if (File.Exists(path))
                {
                    File.Delete(path);
                }
            }

            if (removedOldProject)
            {
                HackRelocateProject();
            }

            foreach (var item in items)
            {
                if (updateProject)
                {
                    item.AddToProject(emptyProject, projectDir);
                }
            }

            foreach (var item in syncList)
            {
                monitor.Log.WriteLine("Syncing item {0}", item.GetTargetRelativeFileNames()[0]);
                item.SyncOut(ctx);
                monitor.Step(1);
            }

            if (updateProject)
            {
                monitor.Log.WriteLine("Queuing Xcode project {0} to write when opened", projectDir);
                pendingProjectWrite = emptyProject;
            }

            monitor.EndTask();
            monitor.ReportSuccess(GettextCatalog.GetString("Xcode project updated."));
        }
        void AggregateTypeUpdates(CodeDomProvider provider, Dictionary <string, List <NSObjectTypeInfo> > designerFiles,
                                  out Dictionary <string, NSObjectTypeInfo> newTypes,
                                  out Dictionary <string, ProjectFile> newFiles)
        {
            XC4Debug.Log("Aggregating {0} type updates", typeSyncJobs.Count);
            newFiles = null;
            newTypes = null;

            foreach (var job in TypeSyncJobs)
            {
                if (job.IsFreshlyAdded)
                {
                    // Need to define what file this new type is defined in
                    string filename = job.Type.ObjCName + "." + provider.FileExtension;
                    string path;

                    if (job.RelativePath != null)
                    {
                        path = Path.Combine(Project.BaseDirectory, job.RelativePath, filename);
                    }
                    else
                    {
                        path = Path.Combine(Project.BaseDirectory, filename);
                    }

                    job.Type.DefinedIn = new string[] { path };

                    if (newFiles == null)
                    {
                        newFiles = new Dictionary <string, ProjectFile> ();
                    }
                    if (!newFiles.ContainsKey(path))
                    {
                        newFiles.Add(path, new ProjectFile(path));
                    }

                    if (newTypes == null)
                    {
                        newTypes = new Dictionary <string, NSObjectTypeInfo> ();
                    }
                    if (!newTypes.ContainsKey(path))
                    {
                        newTypes.Add(path, job.Type);
                    }
                }

                // generate designer filenames for classes without designer files
                if (job.DesignerFile == null)
                {
                    var df = CreateDesignerFile(job);
                    job.DesignerFile = df.FilePath;
                    if (newFiles == null)
                    {
                        newFiles = new Dictionary <string, ProjectFile> ();
                    }
                    if (!newFiles.ContainsKey(job.DesignerFile))
                    {
                        newFiles.Add(job.DesignerFile, df);
                    }
                }

                // group all the types by designer file
                List <NSObjectTypeInfo> types;
                if (!designerFiles.TryGetValue(job.DesignerFile, out types))
                {
                    designerFiles[job.DesignerFile] = types = new List <NSObjectTypeInfo> ();
                }
                XC4Debug.Log("{0}: {1}", job.DesignerFile, job.Type.ObjCName);
                types.Add(job.Type);
            }
        }