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); } }
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); }
void DeleteXcproj() { XC4Debug.Log("Deleting project artifacts"); if (Directory.Exists(xcproj)) { Directory.Delete(xcproj, true); } }
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); }
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); }
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); }
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); }
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); }
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(); } } } }
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; }
// 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); } }
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(); } }
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); } } } } }
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); } } }
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)); }
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); } }