protected override bool OnBuild (ProgressMonitor monitor, DeployContext ctx)
		{
			string tmpFolder = null;

			try {
				SolutionConfigurationSelector conf = (SolutionConfigurationSelector) configuration;
				var bt = RootSolutionItem as IBuildTarget;
				if (bt != null) {
					BuildResult res = bt.Build (monitor, conf).Result;
					if (res.ErrorCount > 0) {
						foreach (BuildError e in res.Errors)
							monitor.ReportError (e.ToString (), null);
						monitor.ReportError (GettextCatalog.GetString ("The source project failed to build."), null);
						return false;
					}
				}
				
				tmpFolder = FileService.CreateTempDirectory ();
				
				string tf = Path.GetFileNameWithoutExtension (targetFile);
				if (tf.EndsWith (".tar")) tf = Path.GetFileNameWithoutExtension (tf);
				string folder = FileService.GetFullPath (Path.Combine (tmpFolder, tf));
				
				// Export the binary files
				DeployFileCollection deployFiles = GetDeployFiles (ctx, conf);
				foreach (DeployFile file in deployFiles) {
					string tfile = Path.Combine (folder, file.ResolvedTargetFile);
					string tdir = FileService.GetFullPath (Path.GetDirectoryName (tfile));
					if (!Directory.Exists (tdir))
						Directory.CreateDirectory (tdir);
					File.Copy (file.SourcePath, tfile, true);
				}
				
				// Create the archive
				string td = Path.GetDirectoryName (targetFile);
				if (!Directory.Exists (td))
					Directory.CreateDirectory (td);
				DeployService.CreateArchive (monitor, tmpFolder, targetFile);
			}
			catch (Exception ex) {
				monitor.ReportError ("Package creation failed", ex);
				LoggingService.LogError ("Package creation failed", ex);
				return false;
			}
			finally {
				if (tmpFolder != null)
					Directory.Delete (tmpFolder, true);
			}
			monitor.Log.WriteLine (GettextCatalog.GetString ("Created file: {0}", targetFile));
			return true;
		}
    protected override Task OnExecute(ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration)
    {
      if (base.OnGetCanExecute(context, configuration))
      {
        return base.OnExecute(monitor, context, configuration);
      }

      try
      {
        var project = Project as DotNetProject;
        if (project != null && IsSupportedProject)
        {
          const string SoftDebuggerName = RhinoSoftDebuggerEngine.DebuggerName;
          var config = project.GetConfiguration(configuration) as DotNetProjectConfiguration;
          var cmd = new RhinoCommonExecutionCommand(project.GetOutputFileName(configuration), project);
          cmd.Arguments = config.CommandLineParameters;
          cmd.WorkingDirectory = Path.GetDirectoryName(config.CompiledOutputName);
          cmd.EnvironmentVariables = config.GetParsedEnvironmentVariables();
          cmd.TargetRuntime = project.TargetRuntime;
          cmd.UserAssemblyPaths = project.GetUserAssemblyPaths(configuration);

          var executionModes = Runtime.ProcessService.GetExecutionModes();
          var executionMode = executionModes.SelectMany(r => r.ExecutionModes).FirstOrDefault(r => r.Id == SoftDebuggerName);
          var console = context.ConsoleFactory.CreateConsole(new OperationConsoleFactory.CreateConsoleOptions(true));
          var operation = executionMode.ExecutionHandler.Execute(cmd, console);
          monitor.CancellationToken.Register(() => operation.Cancel());
          return operation.Task;
        }
      }
      catch (Exception ex)
      {
        monitor.ReportError($"An error occurred starting Rhino.\n{ex}", ex);
      }
      return null;
    }
		public override void CopyFiles (ProgressMonitor monitor, IFileReplacePolicy replacePolicy, FileCopyConfiguration copyConfig, DeployFileCollection deployFiles, DeployContext context)
		{
			DirectoryInfo tempDir = null;
			try {
				tempDir = CreateTempDir ();
			} catch (Exception e) {
				monitor.ReportError (GettextCatalog.GetString ("Could not create temporary directory."), e);
				return;
			}
			
			try {
				MountTempDirectory (monitor, copyConfig, tempDir.FullName);
			} catch (Exception e) {
				monitor.ReportError (GettextCatalog.GetString ("Could not mount FUSE filesystem."), e);
				RemoveTempDirIfEmpty (tempDir);
				return;
			}
			
			try {
				base.InternalCopyFiles (monitor, replacePolicy, copyConfig, deployFiles, context, tempDir.FullName);
			} finally {
				//unmount the filesystem
				try {
					string escapedDir = tempDir.FullName.Replace ("\"", "\\\"");
					string cmd, args;
					
					if (Platform.IsMac) {
						cmd = "umount";
						args = string.Format ("\"{0}\"", escapedDir);
					} else {
						cmd = "fusermount";
						args = string.Format ("-u \"{0}\"", escapedDir);
					}
					RunFuseCommand (monitor, cmd, args);
				} catch (Exception e) {
					LoggingService.LogError (GettextCatalog.GetString ("Could not unmount FUSE filesystem."), e);
					monitor.ReportError (GettextCatalog.GetString ("Could not unmount FUSE filesystem."), e);
				}
				RemoveTempDirIfEmpty (tempDir);
			}
		}
		public Task WriteFile (string file, object obj, bool saveProjects, ProgressMonitor monitor)
		{
			return Task.Run (delegate {
				Solution sol = (Solution)obj;

				try {
					monitor.BeginTask (GettextCatalog.GetString ("Saving solution: {0}", file), 1);
					WriteFileInternal (file, file, sol, saveProjects, monitor);
				} catch (Exception ex) {
					monitor.ReportError (GettextCatalog.GetString ("Could not save solution: {0}", file), ex);
					LoggingService.LogError (GettextCatalog.GetString ("Could not save solution: {0}", file), ex);
					throw;
				} finally {
					monitor.EndTask ();
				}
			});
		}
		protected override void OnReadSolution (ProgressMonitor monitor, MonoDevelop.Projects.MSBuild.SlnFile file)
		{
			base.OnReadSolution (monitor, file);

			//Resolve project references
			try {
				MakefileData.ResolveProjectReferences (Solution.RootFolder, monitor);
			} catch (Exception e) {
				LoggingService.LogError (GettextCatalog.GetString (
					"Error resolving Makefile based project references for solution {0}", Solution.Name), e);
				monitor.ReportError (GettextCatalog.GetString (
					"Error resolving Makefile based project references for solution {0}", Solution.Name), e);
			}

			// All done, dispose myself
			Dispose ();
		}
		WorkspaceItem ReadWorkspaceItemFile (FilePath fileName, ProgressMonitor monitor)
		{
			XmlTextReader reader = new XmlTextReader (new StreamReader (fileName));
			try {
				monitor.BeginTask (string.Format (GettextCatalog.GetString ("Loading workspace item: {0}"), fileName), 1);
				reader.MoveToContent ();
				XmlDataSerializer ser = new XmlDataSerializer (MD1ProjectService.DataContext);
				ser.SerializationContext.BaseFile = fileName;
				ser.SerializationContext.ProgressMonitor = monitor;
				WorkspaceItem entry = (WorkspaceItem)ser.Deserialize (reader, typeof(WorkspaceItem));
				entry.FileName = fileName;
				return entry;
			} catch (Exception ex) {
				monitor.ReportError (string.Format (GettextCatalog.GetString ("Could not load solution item: {0}"), fileName), ex);
				throw;
			} finally {
				monitor.EndTask ();
				reader.Close ();
			}
		}
		/// <summary>
		/// Checks that the xml in this view is well-formed.
		/// </summary>
		public static XmlDocument ValidateWellFormedness (ProgressMonitor monitor, string xml, string fileName)
		{
			monitor.BeginTask (GettextCatalog.GetString ("Validating XML..."), 1);
			bool error = false;
			XmlDocument doc = null;
			
			try {
				doc = new XmlDocument ();
				doc.LoadXml (xml);
			} catch (XmlException ex) {
				monitor.ReportError (ex.Message, ex);
				AddTask (fileName, ex.Message, ex.LinePosition, ex.LineNumber, TaskSeverity.Error);
				error = true;
			}
			
			if (error) {
				monitor.Log.WriteLine (GettextCatalog.GetString ("Validation failed."));
				TaskService.ShowErrors ();
			} else {
				monitor.Log.WriteLine (GettextCatalog.GetString ("XML is valid."));
			}
			
			monitor.EndTask ();
			return error? null: doc;
		}
		internal void LoadSolution (Solution sol, SlnFile sln, ProgressMonitor monitor, SolutionLoadContext ctx)
		{
			var version = sln.FormatVersion;

			//Parse the .sln file
			var folder = sol.RootFolder;
			sol.Version = "0.1"; //FIXME:

			monitor.BeginTask("Loading projects ..", sln.Projects.Count + 1);
			Dictionary<string, SolutionFolderItem> items = new Dictionary<string, SolutionFolderItem> ();
			List<string> sortedList = new List<string> ();

			List<Task> loadTasks = new List<Task> ();

			foreach (SlnProject sec in sln.Projects) {
				try {
					// Valid guid?
					new Guid (sec.TypeGuid);
				} catch (FormatException) {
					monitor.Step (1);
					//Use default guid as projectGuid
					LoggingService.LogDebug (GettextCatalog.GetString (
						"Invalid Project type guid '{0}' on line #{1}. Ignoring.",
						sec.Id,
						sec.Line));
					continue;
				}

				string projTypeGuid = sec.TypeGuid.ToUpper ();
				string projectName = sec.Name;
				string projectPath = sec.FilePath;
				string projectGuid = sec.Id;

				lock (items)
					sortedList.Add (projectGuid);

				if (projTypeGuid == MSBuildProjectService.FolderTypeGuid) {
					//Solution folder
					SolutionFolder sfolder = new SolutionFolder ();
					sfolder.Name = projectName;
					sfolder.ItemId = projectGuid;

					DeserializeSolutionItem (monitor, sol, sfolder, sec);
					
					foreach (string f in ReadFolderFiles (sec))
						sfolder.Files.Add (MSBuildProjectService.FromMSBuildPath (Path.GetDirectoryName (sol.FileName), f));

					lock (items)
						items.Add (projectGuid, sfolder);

					monitor.Step (1);
					continue;
				}

				if (projectPath.StartsWith("http://")) {
					monitor.ReportWarning (GettextCatalog.GetString (
						"{0}({1}): Projects with non-local source (http://...) not supported. '{2}'.",
						sol.FileName, sec.Line, projectPath));
					monitor.Step (1);
					continue;
				}

				string path = MSBuildProjectService.FromMSBuildPath (Path.GetDirectoryName (sol.FileName), projectPath);
				if (String.IsNullOrEmpty (path)) {
					monitor.ReportWarning (GettextCatalog.GetString (
						"Invalid project path found in {0} : {1}", sol.FileName, projectPath));
					LoggingService.LogWarning (GettextCatalog.GetString (
						"Invalid project path found in {0} : {1}", sol.FileName, projectPath));
					monitor.Step (1);
					continue;
				}

				projectPath = Path.GetFullPath (path);
				
				SolutionItem item = null;
				Task<SolutionItem> loadTask;
				DateTime ti = DateTime.Now;

				if (sol.IsSolutionItemEnabled (projectPath)) {
					loadTask = Services.ProjectService.ReadSolutionItem (monitor, projectPath, format, projTypeGuid, projectGuid, ctx);
				} else {
					loadTask = Task.FromResult<SolutionItem> (new UnloadedSolutionItem () {
						FileName = projectPath
					});
				}

				var ft = loadTask.ContinueWith (ta => {
					try {
						item = ta.Result;
						if (item == null)
							throw new UnknownSolutionItemTypeException (projTypeGuid);
					} catch (Exception cex) {
						var e = UnwrapException (cex).First ();

						string unsupportedMessage = e.Message;

						if (e is UserException) {
							var ex = (UserException) e;
							LoggingService.LogError ("{0}: {1}", ex.Message, ex.Details);
							monitor.ReportError (string.Format ("{0}{1}{1}{2}", ex.Message, Environment.NewLine, ex.Details), null);
						} else {
							LoggingService.LogError (string.Format ("Error while trying to load the project {0}", projectPath), e);
							monitor.ReportWarning (GettextCatalog.GetString (
								"Error while trying to load the project '{0}': {1}", projectPath, e.Message));
						}

						SolutionItem uitem;
						uitem = new UnknownSolutionItem () {
							FileName = projectPath,
							LoadError = unsupportedMessage,
						};
						item = uitem;
						item.ItemId = projectGuid;
						item.TypeGuid = projTypeGuid;
					}

					item.UnresolvedProjectDependencies = ReadSolutionItemDependencies (sec);

					// Deserialize the object
					DeserializeSolutionItem (monitor, sol, item, sec);

					lock (items) {
						if (!items.ContainsKey (projectGuid)) {
							items.Add (projectGuid, item);
						} else {
							monitor.ReportError (GettextCatalog.GetString ("Invalid solution file. There are two projects with the same GUID. The project {0} will be ignored.", projectPath), null);
						}
					}
					monitor.Step (1);
				});
				loadTasks.Add (ft);
			}

			Task.WaitAll (loadTasks.ToArray ());

			sol.LoadedProjects = new HashSet<string> (items.Keys);

			var nested = sln.Sections.GetSection ("NestedProjects");
			if (nested != null)
				LoadNestedProjects (nested, items, monitor);

			// Resolve project dependencies
			foreach (var it in items.Values.OfType<SolutionItem> ()) {
				if (it.UnresolvedProjectDependencies != null) {
					foreach (var id in it.UnresolvedProjectDependencies.ToArray ()) {
						SolutionFolderItem dep;
						if (items.TryGetValue (id, out dep) && dep is SolutionItem) {
							it.UnresolvedProjectDependencies.Remove (id);
							it.ItemDependencies.Add ((SolutionItem)dep);
						}
					}
					if (it.UnresolvedProjectDependencies.Count == 0)
						it.UnresolvedProjectDependencies = null;
				}
			}

			//Add top level folders and projects to the main folder
			foreach (string id in sortedList) {
				SolutionFolderItem ce;
				if (items.TryGetValue (id, out ce) && ce.ParentFolder == null)
					folder.Items.Add (ce);
			}

			//FIXME: This can be just SolutionConfiguration also!
			LoadSolutionConfigurations (sln.SolutionConfigurationsSection, sol, monitor);

			LoadProjectConfigurationMappings (sln.ProjectConfigurationsSection, sol, items, monitor);

			foreach (var e in sln.Sections) {
				string name = e.Id;
				if (name.StartsWith ("MonoDevelopProperties.")) {
					int i = name.IndexOf ('.');
					LoadMonoDevelopConfigurationProperties (name.Substring (i+1), e, sol, monitor);
				}
			}

			monitor.EndTask ();
		}
		async Task ExecuteSolutionItemAsync (ProgressMonitor monitor, IBuildTarget entry, ExecutionContext context, ConfigurationSelector configuration, RunConfiguration runConfiguration)
		{
			try {
				OnBeforeStartProject ();
				if (entry is IRunTarget)
					await ((IRunTarget)entry).Execute (monitor, context, configuration, runConfiguration);
				else
					await entry.Execute (monitor, context, configuration);
			} catch (Exception ex) {
				monitor.ReportError (GettextCatalog.GetString ("Execution failed."), ex);
				LoggingService.LogError ("Execution failed", ex);
			} finally {
				monitor.Dispose ();
			}
		}
Beispiel #10
0
		static bool UpdateCompleted (ProgressMonitor monitor,
		                             ProjectFile file, ProjectFile genFile, SingleFileCustomToolResult result,
		                             bool runMultipleFiles)
		{
			monitor.EndTask ();

			if (monitor.CancellationToken.IsCancellationRequested) {
				monitor.ReportError (GettextCatalog.GetString ("Cancelled"), null);
				monitor.Dispose ();
				return false;
			}
			
			string genFileName;
			try {
				
				bool broken = false;
				
				if (result.UnhandledException != null) {
					broken = true;
					string msg = GettextCatalog.GetString ("The '{0}' code generator crashed", file.Generator);
					result.Errors.Add (new CompilerError (file.Name, 0, 0, "", msg + ": " + result.UnhandledException.Message));
					monitor.ReportError (msg, result.UnhandledException);
					LoggingService.LogError (msg, result.UnhandledException);
				}

				genFileName = result.GeneratedFilePath.IsNullOrEmpty?
					null : result.GeneratedFilePath.ToRelative (file.FilePath.ParentDirectory);
				
				if (!string.IsNullOrEmpty (genFileName)) {
					bool validName = genFileName.IndexOfAny (new [] { '/', '\\' }) < 0
						&& FileService.IsValidFileName (genFileName);
					
					if (!broken && !validName) {
						broken = true;
						string msg = GettextCatalog.GetString ("The '{0}' code generator output invalid filename '{1}'",
						                                       file.Generator, result.GeneratedFilePath);
						result.Errors.Add (new CompilerError (file.Name, 0, 0, "", msg));
						monitor.ReportError (msg, null);
					}
				}
				
				if (result.Errors.Count > 0) {
					DispatchService.GuiDispatch (delegate {
						foreach (CompilerError err in result.Errors)
							TaskService.Errors.Add (new TaskListEntry (file.FilePath, err.ErrorText, err.Column, err.Line,
								err.IsWarning? TaskSeverity.Warning : TaskSeverity.Error,
								TaskPriority.Normal, file.Project.ParentSolution, file));
					});
				}
				
				if (broken)
					return true;

				if (!runMultipleFiles) {
					if (result.Success)
						monitor.ReportSuccess ("Generated file successfully.");
					else if (result.SuccessWithWarnings)
						monitor.ReportSuccess ("Warnings in file generation.");
					else
						monitor.ReportError ("Errors in file generation.", null);
				}
			} finally {
				if (!runMultipleFiles)
					monitor.Dispose ();
			}

			if (result.GeneratedFilePath.IsNullOrEmpty || !File.Exists (result.GeneratedFilePath))
				return true;

			// broadcast a change event so text editors etc reload the file
			FileService.NotifyFileChanged (result.GeneratedFilePath);

			// add file to project, update file properties, etc
			Gtk.Application.Invoke (async delegate {
				bool projectChanged = false;
				if (genFile == null) {
					genFile = file.Project.AddFile (result.GeneratedFilePath, result.OverrideBuildAction);
					projectChanged = true;
				} else if (result.GeneratedFilePath != genFile.FilePath) {
					genFile.Name = result.GeneratedFilePath;
					projectChanged = true;
				}

				if (file.LastGenOutput != genFileName) {
					file.LastGenOutput = genFileName;
					projectChanged = true;
				}

				if (genFile.DependsOn != file.FilePath.FileName) {
					genFile.DependsOn = file.FilePath.FileName;
					projectChanged = true;
				}

				if (projectChanged)
					await IdeApp.ProjectOperations.SaveAsync (file.Project);
			});

			return true;
		}
		//Reader
		public async Task<object> ReadFile (string fileName, ProgressMonitor monitor)
		{
			if (fileName == null || monitor == null)
				return null;

			var sol = new Solution (true);
			sol.FileName = fileName;
			sol.FileFormat = format;

			try {
				monitor.BeginTask (string.Format (GettextCatalog.GetString ("Loading solution: {0}"), fileName), 1);
				monitor.BeginStep ();
				await sol.OnBeginLoad ();
				var projectLoadMonitor = monitor as ProjectLoadProgressMonitor;
				if (projectLoadMonitor != null)
					projectLoadMonitor.CurrentSolution = sol;
				await Task.Factory.StartNew (() => {
					sol.ReadSolution (monitor);
				});
			} catch (Exception ex) {
				monitor.ReportError (GettextCatalog.GetString ("Could not load solution: {0}", fileName), ex);
				sol.OnEndLoad ().Wait ();
				sol.NotifyItemReady ();
				monitor.EndTask ();
				throw;
			}
			await sol.OnEndLoad ();
			sol.NotifyItemReady ();
			monitor.EndTask ();
			return sol;
		}
		protected override void OnWriteProject (ProgressMonitor monitor, MonoDevelop.Projects.MSBuild.MSBuildProject msproject)
		{
			base.OnWriteProject (monitor, msproject);

			if (data == null)
				return;

			msproject.SetMonoDevelopProjectExtension ("MonoDevelop.Autotools.MakefileInfo", data.Write ());

			if (!data.SupportsIntegration)
				return;
			
			try {
				data.UpdateMakefile (monitor);
			} catch (Exception e) {
				LoggingService.LogError (GettextCatalog.GetString ("Error saving to Makefile ({0}) for project {1}",
					data.AbsoluteMakefileName, Project.Name, e));
				monitor.ReportError (GettextCatalog.GetString (
					"Error saving to Makefile ({0}) for project {1}", data.AbsoluteMakefileName, Project.Name), e);
			}
		}
Beispiel #13
0
		static void WriteSummaryResults (ProgressMonitor monitor, int succeeded, int warnings, int errors)
		{
			monitor.Log.WriteLine ();

			int total = succeeded + warnings + errors;

			//this might not be correct for languages where pluralization affects the other arguments
			//but gettext doesn't really have an answer for sentences with multiple plurals
			monitor.Log.WriteLine (
				GettextCatalog.GetPluralString (
					"{0} file processed total. {1} generated successfully, {2} with warnings, {3} with errors",
					"{0} files processed total. {1} generated successfully, {2} with warnings, {3} with errors",
					total,
					total, succeeded, warnings, errors)
			);
			//ends the root task
			monitor.EndTask ();

			if (errors > 0)
				monitor.ReportError (GettextCatalog.GetString ("Errors in file generation."), null);
			else if (warnings > 0)
				monitor.ReportSuccess (GettextCatalog.GetString ("Warnings in file generation."));
			else
				monitor.ReportSuccess (GettextCatalog.GetString ("Generated files successfully."));

			monitor.Dispose ();
		}
		internal static void TransferFilesInternal (ProgressMonitor monitor, Project sourceProject, FilePath sourcePath, Project targetProject,
		                           FilePath targetPath, bool removeFromSource, bool copyOnlyProjectFiles)
		{
			// When transfering directories, targetPath is the directory where the source
			// directory will be transfered, including the destination directory or file name.
			// For example, if sourcePath is /a1/a2/a3 and targetPath is /b1/b2, the
			// new folder or file will be /b1/b2
			
			if (targetProject == null)
				throw new ArgumentNullException ("targetProject");

			if (!targetPath.IsChildPathOf (targetProject.BaseDirectory))
				throw new ArgumentException ("Invalid project folder: " + targetPath);

			if (sourceProject != null && !sourcePath.IsChildPathOf (sourceProject.BaseDirectory))
				throw new ArgumentException ("Invalid project folder: " + sourcePath);
				
			if (copyOnlyProjectFiles && sourceProject == null)
				throw new ArgumentException ("A source project must be specified if copyOnlyProjectFiles is True");
			
			bool sourceIsFolder = Directory.Exists (sourcePath);

			bool movingFolder = removeFromSource && sourceIsFolder && (
				!copyOnlyProjectFiles ||
				ContainsOnlyProjectFiles (sourcePath, sourceProject));

			// We need to remove all files + directories from the source project
			// but when dealing with the VCS addins we need to process only the
			// files so we do not create a 'file' in the VCS which corresponds
			// to a directory in the project and blow things up.
			List<ProjectFile> filesToRemove = null;
			List<ProjectFile> filesToMove = null;
			try {
				//get the real ProjectFiles
				if (sourceProject != null) {
					if (sourceIsFolder) {
						var virtualPath = sourcePath.ToRelative (sourceProject.BaseDirectory);
						// Grab all the child nodes of the folder we just dragged/dropped
						filesToRemove = sourceProject.Files.GetFilesInVirtualPath (virtualPath).ToList ();
						// Add the folder itself so we can remove it from the source project if its a Move operation
						var folder = sourceProject.Files.FirstOrDefault (f => f.ProjectVirtualPath == virtualPath);
						if (folder != null)
							filesToRemove.Add (folder);
					} else {
						filesToRemove = new List<ProjectFile> ();
						var pf = sourceProject.Files.GetFileWithVirtualPath (sourceProject.GetRelativeChildPath (sourcePath));
						if (pf != null)
							filesToRemove.Add (pf);
					}
				}
				//get all the non-project files and create fake ProjectFiles
				if (!copyOnlyProjectFiles || sourceProject == null) {
					var col = new List<ProjectFile> ();
					GetAllFilesRecursive (sourcePath, col);
					if (sourceProject != null) {
						var names = new HashSet<string> (filesToRemove.Select (f => sourceProject.BaseDirectory.Combine (f.ProjectVirtualPath).ToString ()));
						foreach (var f in col)
							if (names.Add (f.Name))
							    filesToRemove.Add (f);
					} else {
						filesToRemove = col;
					}
				}
			} catch (Exception ex) {
				monitor.ReportError (GettextCatalog.GetString ("Could not get any file from '{0}'.", sourcePath), ex);
				return;
			}
			
			// Strip out all the directories to leave us with just the files.
			filesToMove = filesToRemove.Where (f => f.Subtype != Subtype.Directory).ToList ();
			
			// If copying a single file, bring any grouped children along
			ProjectFile sourceParent = null;
			if (filesToMove.Count == 1 && sourceProject != null) {
				var pf = filesToMove[0];
				if (pf != null && pf.HasChildren) {
					foreach (ProjectFile child in pf.DependentChildren) {
						filesToRemove.Add (child);
						filesToMove.Add (child);
					}
				}
				sourceParent = pf;
			}
			
			// Ensure that the destination folder is created, even if no files
			// are copied
			
			try {
				if (sourceIsFolder && !Directory.Exists (targetPath) && !movingFolder)
					FileService.CreateDirectory (targetPath);
			} catch (Exception ex) {
				monitor.ReportError (GettextCatalog.GetString ("Could not create directory '{0}'.", targetPath), ex);
				return;
			}

			// Transfer files
			// If moving a folder, do it all at once
			
			if (movingFolder) {
				try {
					FileService.MoveDirectory (sourcePath, targetPath);
				} catch (Exception ex) {
					monitor.ReportError (GettextCatalog.GetString ("Directory '{0}' could not be moved.", sourcePath), ex);
					return;
				}
			}

			if (removeFromSource)
				monitor.BeginTask (GettextCatalog.GetString ("Moving files..."), filesToMove.Count);
			else
				monitor.BeginTask (GettextCatalog.GetString ("Copying files..."), filesToMove.Count);
			
			ProjectFile targetParent = null;
			foreach (ProjectFile file in filesToMove) {
				bool fileIsLink = file.Project != null && file.IsLink;
				
				var sourceFile = fileIsLink
					? file.Project.BaseDirectory.Combine (file.ProjectVirtualPath)
					: file.FilePath;
				
				FilePath newFile;
				if (sourceIsFolder)
					newFile = targetPath.Combine (sourceFile.ToRelative (sourcePath));
				else if (sourceFile == sourcePath)
					newFile = targetPath;
				else if (sourceFile.ParentDirectory != targetPath.ParentDirectory)
					newFile = targetPath.ParentDirectory.Combine (sourceFile.ToRelative (sourcePath.ParentDirectory));
				else
					newFile = GetTargetCopyName (sourceFile, false);
				
				if (!movingFolder && !fileIsLink) {
					try {
						FilePath fileDir = newFile.ParentDirectory;
						if (!Directory.Exists (fileDir) && !file.IsLink)
							FileService.CreateDirectory (fileDir);
						if (removeFromSource) {
							// File.Move() does not have an overwrite argument and will fail if the destFile path exists, however, the user
							// has already chosen to overwrite the destination file.
							if (File.Exists (newFile))
								File.Delete (newFile);

							FileService.MoveFile (sourceFile, newFile);
						} else
							FileService.CopyFile (sourceFile, newFile);
					} catch (Exception ex) {
						if (removeFromSource)
							monitor.ReportError (GettextCatalog.GetString ("File '{0}' could not be moved.", sourceFile), ex);
						else
							monitor.ReportError (GettextCatalog.GetString ("File '{0}' could not be copied.", sourceFile), ex);
						monitor.Step (1);
						continue;
					}
				}
				
				if (sourceProject != null) {
					if (fileIsLink) {
						var linkFile = (ProjectFile) file.Clone ();
						if (movingFolder) {
							var abs = linkFile.Link.ToAbsolute (sourceProject.BaseDirectory);
							var relSrc = abs.ToRelative (sourcePath);
							var absTarg = relSrc.ToAbsolute (targetPath);
							linkFile.Link = absTarg.ToRelative (targetProject.BaseDirectory);
						} else {
							linkFile.Link = newFile.ToRelative (targetProject.BaseDirectory);
						}
						targetProject.Files.Add (linkFile);
					} else if (targetProject.Files.GetFile (newFile) == null) {
						ProjectFile projectFile = (ProjectFile) file.Clone ();
						projectFile.Name = newFile;
						targetProject.Files.Add (projectFile);
						if (targetParent == null) {
							if (file == sourceParent)
								targetParent = projectFile;
						} else if (sourceParent != null) {
							if (projectFile.DependsOn == sourceParent.Name)
								projectFile.DependsOn = targetParent.Name;
						}
					}
				}
				
				monitor.Step (1);
			}
			
			if (removeFromSource) {
				// Remove all files and directories under 'sourcePath'
				foreach (var v in filesToRemove)
					sourceProject.Files.Remove (v);
			}

			// Moving or copying an empty folder. A new folder object has to be added to the project.
			if (sourceIsFolder && !targetProject.Files.GetFilesInVirtualPath (targetPath).Any ()) {
				var folderFile = new ProjectFile (targetPath) { Subtype = Subtype.Directory };
				targetProject.Files.Add (folderFile);
			}
			
			var pfolder = sourcePath.ParentDirectory;
			
			// If this was the last item in the folder, make sure we keep
			// a reference to the folder, so it is not deleted from the tree.
			if (removeFromSource && sourceProject != null && pfolder.CanonicalPath != sourceProject.BaseDirectory.CanonicalPath && pfolder.IsChildPathOf (sourceProject.BaseDirectory)) {
				pfolder = pfolder.ToRelative (sourceProject.BaseDirectory);
				if (!sourceProject.Files.GetFilesInVirtualPath (pfolder).Any () && sourceProject.Files.GetFileWithVirtualPath (pfolder) == null) {
					var folderFile = new ProjectFile (sourceProject.BaseDirectory.Combine (pfolder));
					folderFile.Subtype = Subtype.Directory;
					sourceProject.Files.Add (folderFile);
				}
			}
			
			monitor.EndTask ();
		}
		public BuildResult Build (ProgressMonitor monitor, ConfigurationSelector configuration)
		{
			BuildResult results = new BuildResult ("", 0, 0);
			
			string moFileName  = GetOutFile (configuration);
			string moDirectory = Path.GetDirectoryName (moFileName);
			if (!Directory.Exists (moDirectory))
				Directory.CreateDirectory (moDirectory);
			
			var pb = new ProcessArgumentBuilder ();
			pb.AddQuoted (PoFile);
			pb.Add ("-o");
			pb.AddQuoted (moFileName);
			
			ProcessWrapper process = null;
			try {
				process = Runtime.ProcessService.StartProcess (GetTool ("msgfmt"), pb.ToString (),
					parentProject.BaseDirectory, monitor.Log, monitor.Log, null);
			} catch (System.ComponentModel.Win32Exception) {
				var msg = GettextCatalog.GetString ("Did not find msgfmt. Please ensure that gettext tools are installed.");
				monitor.ReportError (msg, null);
				results.AddError (msg);
				return results;
			}
			
			process.WaitForOutput ();

			if (process.ExitCode == 0) {
				monitor.Log.WriteLine (GettextCatalog.GetString ("Translation {0}: Compilation succeeded.", IsoCode));
			} else {
				string message = GettextCatalog.GetString ("Translation {0}: Compilation failed. See log for details.", IsoCode);
				monitor.Log.WriteLine (message);
				results.AddError (PoFile, 1, 1, "", message);
				results.FailedBuildCount = 1;
			}
			return results;
		}
		async Task ExecuteSolutionItemAsync (ProgressMonitor monitor, IBuildTarget entry, ExecutionContext context)
		{
			try {
				OnBeforeStartProject ();
				await entry.Execute (monitor, context, IdeApp.Workspace.ActiveConfiguration);
			} catch (Exception ex) {
				monitor.ReportError (GettextCatalog.GetString ("Execution failed."), ex);
				LoggingService.LogError ("Execution failed", ex);
			} finally {
				monitor.Dispose ();
			}
		}
		async Task<BuildResult> BuildSolutionItemAsync (IBuildTarget entry, ProgressMonitor monitor, ITimeTracker tt, bool skipPrebuildCheck = false, OperationContext operationContext = null)
		{
			BuildResult result = null;
			try {
				if (!skipPrebuildCheck) {
					tt.Trace ("Pre-build operations");
					result = DoBeforeCompileAction ();
				}

				//wait for any custom tools that were triggered by the save, since the build may depend on them
				await MonoDevelop.Ide.CustomTools.CustomToolService.WaitForRunningTools (monitor);

				if (skipPrebuildCheck || result.ErrorCount == 0) {
					tt.Trace ("Building item");
					result = await entry.Build (monitor, IdeApp.Workspace.ActiveConfiguration, true, operationContext);
				}
			} catch (Exception ex) {
				monitor.ReportError (GettextCatalog.GetString ("Build failed."), ex);
				if (result == null)
					result = new BuildResult ();
				result.AddError ("Build failed. See the build log for details.");
				if (result.SourceTarget == null)
					result.SourceTarget = entry;
			} finally {
				tt.Trace ("Done building");
			}

			BuildDone (monitor, result, entry, tt);	// BuildDone disposes the monitor

			return result;
		}
		static void RetryUntilSuccess (ProgressMonitor monitor, Action<GitCredentialsType> func)
		{
			bool retry;
			using (var tfsSession = new TfsSmartSession ()) {
				do {
					var credType = tfsSession.Disposed ? GitCredentialsType.Normal : GitCredentialsType.Tfs;
					try {
						func (credType);
						GitCredentials.StoreCredentials (credType);
						retry = false;
					} catch (AuthenticationException) {
						GitCredentials.InvalidateCredentials (credType);
						retry = true;
					} catch (VersionControlException e) {
						GitCredentials.InvalidateCredentials (credType);
						if (monitor != null)
							monitor.ReportError (e.Message, null);
						retry = false;
					} catch (UserCancelledException) {
						GitCredentials.StoreCredentials (credType);
						retry = false;
					} catch (LibGit2SharpException e) {
						GitCredentials.InvalidateCredentials (credType);

						if (!tfsSession.Disposed) {
							retry = true;
							tfsSession.Dispose ();
							continue;
						}

						string message;
						// TODO: Remove me once https://github.com/libgit2/libgit2/pull/3137 goes in.
						if (string.Equals (e.Message, "early EOF", StringComparison.OrdinalIgnoreCase))
							message = "Unable to authorize credentials for the repository.";
						else if (string.Equals (e.Message, "Received unexpected content-type", StringComparison.OrdinalIgnoreCase))
							message = "Not a valid git repository.";
						else
							message = e.Message;

						if (monitor != null)
							monitor.ReportError (message, null);
						retry = false;
					}
				} while (retry);
			}
		}
		protected override void OnReadProject (ProgressMonitor monitor, MonoDevelop.Projects.MSBuild.MSBuildProject msproject)
		{
			base.OnReadProject (monitor, msproject);
			var ext = msproject.GetMonoDevelopProjectExtension ("MonoDevelop.Autotools.MakefileInfo");
			if (ext == null)
				return;

			data = MakefileData.Read (ext);
			if (data == null)
				return;

			monitor.BeginTask (GettextCatalog.GetString ("Updating project from Makefile"), 1);
			try { 
				data.OwnerProject = Project;
				if (data.SupportsIntegration)
					data.UpdateProject (monitor, false);
				monitor.Step (1);
			} catch (Exception e) {
				monitor.ReportError (GettextCatalog.GetString (
					"\tError loading Makefile for project {0}", Project.Name), e);
			} finally {
				monitor.EndTask ();
			}
		}
		//FIXME: Check whether autogen.sh is required or not
		protected async override Task<BuildResult> OnBuild (ProgressMonitor monitor, ConfigurationSelector configuration, OperationContext operationContext)
		{
			if (data == null || !data.SupportsIntegration || String.IsNullOrEmpty (data.BuildTargetName))
				return await base.OnBuild (monitor, configuration, operationContext);

			//FIXME: Gen autofoo ? autoreconf?

			string output = String.Empty;
			int exitCode = 0;
			monitor.BeginTask (GettextCatalog.GetString ("Building {0}", Project.Name), 1);
			try
			{
				string baseDir = Project.BaseDirectory;
				string args = string.Format ("-j {0} {1}", data.ParallelProcesses, data.BuildTargetName);
	
				using (var swOutput = new StringWriter ()) {
					using (var chainedOutput = new LogTextWriter ()) {
						chainedOutput.ChainWriter (monitor.Log);
						chainedOutput.ChainWriter (swOutput);

						using (ProcessWrapper process = Runtime.ProcessService.StartProcess ("make",
								args,
								baseDir, 
								chainedOutput, 
								chainedOutput,
							null)) {

							await process.Task;

							chainedOutput.UnchainWriter (monitor.Log);
							chainedOutput.UnchainWriter (swOutput);

							exitCode = process.ExitCode;
							output = swOutput.ToString ();
							monitor.Step ( 1 );
						}
					}
				}
			}
			catch ( Exception e )
			{
				monitor.ReportError ( GettextCatalog.GetString ("Project could not be built: "), e );
				return null;
			}
			finally 
			{
				monitor.EndTask ();
			}

			TempFileCollection tf = new TempFileCollection ();
			Regex regexError = data.GetErrorRegex (false);
			Regex regexWarning = data.GetWarningRegex (false);

			BuildResult cr = ParseOutput (tf, output, Project.BaseDirectory, regexError, regexWarning);
			if (exitCode != 0 && cr.FailedBuildCount == 0)
				cr.AddError (GettextCatalog.GetString ("Build failed. See Build Output panel."));

			return cr;
		}
		protected async override Task OnExecute (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration)
		{
			if (data == null || !data.SupportsIntegration || String.IsNullOrEmpty (data.ExecuteTargetName)) {
				await base.OnExecute (monitor, context, configuration);
				return;
			}

			OperationConsole console = context.ConsoleFactory.CreateConsole ();
			monitor.BeginTask (GettextCatalog.GetString ("Executing {0}", Project.Name), 1);
			try
			{
				ProcessWrapper process = Runtime.ProcessService.StartProcess ("make",
					data.ExecuteTargetName,
					Project.BaseDirectory,
					console.Out,
					console.Error,
					null);

				await process.Task;

				monitor.Log.WriteLine (GettextCatalog.GetString ("The application exited with code: {0}", process.ExitCode));
				monitor.Step (1);
			} catch (Exception e) {
				monitor.ReportError (GettextCatalog.GetString ("Project could not be executed: "), e);
				return;
			} finally {
				monitor.EndTask ();
				console.Dispose ();
			}
		}
		protected async override Task<BuildResult> OnClean (ProgressMonitor monitor, ConfigurationSelector configuration, OperationContext operationContext)
		{
			if (data == null || !data.SupportsIntegration || String.IsNullOrEmpty (data.CleanTargetName)) {
				return await base.OnClean (monitor, configuration, operationContext); 
			}

			monitor.BeginTask ( GettextCatalog.GetString( "Cleaning project"), 1);
			try
			{
				string baseDir = Project.BaseDirectory;
	
				ProcessWrapper process = Runtime.ProcessService.StartProcess ( "make", 
						data.CleanTargetName,
						baseDir, 
						monitor.Log, 
						monitor.Log, 
						null );

				await process.Task;

				if ( process.ExitCode > 0 )
					throw new Exception ( GettextCatalog.GetString ("An unspecified error occurred while running '{0}'", "make " + data.CleanTargetName) );

				monitor.Step ( 1 );
			}
			catch ( Exception e )
			{
				monitor.ReportError ( GettextCatalog.GetString ("Project could not be cleaned: "), e );
				var res = new BuildResult ();
				res.AddError (GettextCatalog.GetString ("Project could not be cleaned: ") + e.Message);
				return res;
			}
			finally 
			{
				monitor.EndTask ();
			}
			monitor.ReportSuccess ( GettextCatalog.GetString ( "Project successfully cleaned"));
			return BuildResult.CreateSuccess ();
		}
		async Task<BuildResult> CleanAsync (IBuildTarget entry, ProgressMonitor monitor, ITimeTracker tt, bool isRebuilding, OperationContext operationContext)
		{
			BuildResult res = null;
			try {
				tt.Trace ("Cleaning item");
				res = await entry.Clean (monitor, IdeApp.Workspace.ActiveConfiguration, operationContext);
			} catch (Exception ex) {
				monitor.ReportError (GettextCatalog.GetString ("Clean failed."), ex);
			} finally {
				tt.Trace ("Done cleaning");
			}
			
			if (isRebuilding) {
				if (EndClean != null) {
					OnEndClean (monitor, tt);
				}
			} else {
				CleanDone (monitor, entry, tt);
			}
			return res;
		}
		/// <summary>
		/// Validates the xml against known schemas.
		/// </summary>		
		public static XmlDocument ValidateXml (ProgressMonitor monitor, string xml, string fileName)
		{
			monitor.BeginTask (GettextCatalog.GetString ("Validating XML..."), 1);
			bool error = false;
			XmlDocument doc = null;
			StringReader stringReader = new StringReader (xml);
			
			XmlReaderSettings settings = new XmlReaderSettings ();
			settings.ValidationFlags = XmlSchemaValidationFlags.ProcessIdentityConstraints
					| XmlSchemaValidationFlags.ProcessInlineSchema
					| XmlSchemaValidationFlags.ProcessSchemaLocation
					| XmlSchemaValidationFlags.ReportValidationWarnings;
			settings.ValidationType = ValidationType.Schema;
			settings.DtdProcessing = DtdProcessing.Parse;
			
			ValidationEventHandler validationHandler = delegate (object sender, System.Xml.Schema.ValidationEventArgs args) {
				if (args.Severity == XmlSeverityType.Warning) {
					monitor.Log.WriteLine (args.Message);
					AddTask (fileName, args.Exception.Message, args.Exception.LinePosition, args.Exception.LineNumber,TaskSeverity.Warning);
				} else {
					AddTask (fileName, args.Exception.Message, args.Exception.LinePosition, args.Exception.LineNumber,TaskSeverity.Error);
					monitor.Log.WriteLine (args.Message);
					error = true;
				}	
			};
			settings.ValidationEventHandler += validationHandler;
			
			try {
				foreach (XmlSchemaCompletionData sd in XmlSchemaManager.SchemaCompletionDataItems)
					settings.Schemas.Add (sd.Schema);
				settings.Schemas.Compile ();
				
				XmlReader reader = XmlReader.Create (stringReader, settings);
				doc = new XmlDocument();
				doc.Load (reader);
				
			} catch (XmlSchemaException ex) {
				monitor.ReportError (ex.Message, ex);
				AddTask (fileName, ex.Message, ex.LinePosition, ex.LineNumber,TaskSeverity.Error);
				error = true;
			}
			catch (XmlException ex) {
				monitor.ReportError (ex.Message, ex);
				AddTask (fileName, ex.Message, ex.LinePosition, ex.LineNumber,TaskSeverity.Error);
				error = true;
			}
			finally {
				if (stringReader != null)
					stringReader.Dispose ();
				settings.ValidationEventHandler -= validationHandler;
			}
			
			if (error) {
				monitor.Log.WriteLine (GettextCatalog.GetString ("Validation failed."));
				TaskService.ShowErrors ();
			} else {
				monitor.Log.WriteLine  (GettextCatalog.GetString ("XML is valid."));
			}
			
			monitor.EndTask ();
			return error? null: doc;
		}
		void BuildDone (ProgressMonitor monitor, BuildResult result, IBuildTarget entry, ITimeTracker tt)
		{
			TaskListEntry[] tasks = null;
			tt.Trace ("Begin reporting build result");
			try {
				if (result != null) {
					lastResult = result;
					monitor.Log.WriteLine ();
					monitor.Log.WriteLine (GettextCatalog.GetString ("---------------------- Done ----------------------"));
					
					tt.Trace ("Updating task service");
					tasks = new TaskListEntry [result.Errors.Count];
					for (int n=0; n<tasks.Length; n++) {
						tasks [n] = new TaskListEntry (result.Errors [n]);
						tasks [n].Owner = this;
					}

					TaskService.Errors.AddRange (tasks);
					TaskService.Errors.ResetLocationList ();
					IdeApp.Workbench.ActiveLocationList = TaskService.Errors;
					
					tt.Trace ("Reporting result");
					
					string errorString = GettextCatalog.GetPluralString("{0} error", "{0} errors", result.ErrorCount, result.ErrorCount);
					string warningString = GettextCatalog.GetPluralString("{0} warning", "{0} warnings", result.WarningCount, result.WarningCount);

					if (monitor.CancellationToken.IsCancellationRequested) {
						monitor.ReportError (GettextCatalog.GetString ("Build canceled."), null);
					} else if (result.ErrorCount == 0 && result.WarningCount == 0 && lastResult.FailedBuildCount == 0) {
						monitor.ReportSuccess (GettextCatalog.GetString ("Build successful."));
					} else if (result.ErrorCount == 0 && result.WarningCount > 0) {
						monitor.ReportWarning(GettextCatalog.GetString("Build: ") + errorString + ", " + warningString);
					} else if (result.ErrorCount > 0) {
						monitor.ReportError(GettextCatalog.GetString("Build: ") + errorString + ", " + warningString, null);
					} else {
						monitor.ReportError(GettextCatalog.GetString("Build failed."), null);
					}
					tt.Trace ("End build event");
					OnEndBuild (monitor, lastResult.FailedBuildCount == 0, lastResult, entry as SolutionFolderItem);
				} else {
					tt.Trace ("End build event");
					OnEndBuild (monitor, false);
				}
				
				tt.Trace ("Showing results pad");
				
				try {
					Pad errorsPad = IdeApp.Workbench.GetPad<MonoDevelop.Ide.Gui.Pads.ErrorListPad> ();
					switch (IdeApp.Preferences.ShowErrorPadAfterBuild.Value) {
					case BuildResultStates.Always:
						if (!errorsPad.Visible)
							errorsPad.IsOpenedAutomatically = true;
						errorsPad.Visible = true;
						errorsPad.BringToFront ();
						break;
					case BuildResultStates.Never:
						break;
					case BuildResultStates.OnErrors:
						if (TaskService.Errors.Any (task => task.Severity == TaskSeverity.Error))
							goto case BuildResultStates.Always;
						goto case BuildResultStates.Never;
					case BuildResultStates.OnErrorsOrWarnings:
						if (TaskService.Errors.Any (task => task.Severity == TaskSeverity.Error || task.Severity == TaskSeverity.Warning))
							goto case BuildResultStates.Always;
						goto case BuildResultStates.Never;
					}
				} catch {}
				
				if (tasks != null) {
					TaskListEntry jumpTask = null;
					switch (IdeApp.Preferences.JumpToFirstErrorOrWarning.Value) {
					case JumpToFirst.Error:
						jumpTask = tasks.FirstOrDefault (t => t.Severity == TaskSeverity.Error && TaskStore.IsProjectTaskFile (t));
						break;
					case JumpToFirst.ErrorOrWarning:
						jumpTask = tasks.FirstOrDefault (t => (t.Severity == TaskSeverity.Error || t.Severity == TaskSeverity.Warning) && TaskStore.IsProjectTaskFile (t));
						break;
					}
					if (jumpTask != null) {
						tt.Trace ("Jumping to first result position");
						jumpTask.JumpToPosition ();
					}
				}
				
			} finally {
				monitor.Dispose ();
				tt.End ();
			}
		}
		/// <summary>
		/// Validates the schema.
		/// </summary>		
		public static XmlSchema ValidateSchema (ProgressMonitor monitor, string xml, string fileName)
		{
			monitor.BeginTask (GettextCatalog.GetString ("Validating schema..."), 1);
			bool error = false;
			XmlSchema schema = null;
			try {
				StringReader stringReader = new StringReader (xml);
				XmlTextReader xmlReader = new XmlTextReader (stringReader);
				xmlReader.XmlResolver = null;
				
				ValidationEventHandler callback = delegate (object source, ValidationEventArgs args) {
					if (args.Severity == XmlSeverityType.Warning) {
						monitor.ReportWarning (args.Message);
					} else {
						monitor.ReportError (args.Message, args.Exception);
						error = true;
					}
					AddTask (fileName, args.Message, args.Exception.LinePosition, args.Exception.LineNumber,
					    (args.Severity == XmlSeverityType.Warning)? TaskSeverity.Warning : TaskSeverity.Error);
				};
				schema = XmlSchema.Read (xmlReader, callback);
				XmlSchemaSet sset = new XmlSchemaSet ();
				sset.Add (schema);
				sset.ValidationEventHandler += callback;
				sset.Compile ();
			} 
			catch (XmlSchemaException ex) {
				monitor.ReportError (ex.Message, ex);
				AddTask (fileName, ex.Message, ex.LinePosition, ex.LineNumber,TaskSeverity.Error);
				error = true;
			}
			catch (XmlException ex) {
				monitor.ReportError (ex.Message, ex);
				AddTask (fileName, ex.Message, ex.LinePosition, ex.LineNumber,TaskSeverity.Error);
				error = true;
			}
			
			if (error) {
				monitor.Log.WriteLine (GettextCatalog.GetString ("Validation failed."));
				TaskService.ShowErrors ();
			} else {
				monitor.Log.WriteLine  (GettextCatalog.GetString ("Schema is valid."));
			}
			
			monitor.EndTask ();
			return error? null: schema;
		}
		protected async override Task OnExecute (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration, SolutionItemRunConfiguration runConfiguration)
		{
			//check XSP is available

			var cfg = GetConfiguration (configuration);
			var cmd = CreateExecutionCommand (configuration, cfg);
			var browserExcTarget = context.ExecutionTarget as BrowserExecutionTarget;

			OperationConsole console = null;

			bool isXsp = true; //FIXME: fix this when it might not be true - should delegate to the ExecutionHandler

			try {
				//HACK: check XSP exists first, because error UX is cleaner w/o displaying a blank console pad.
				if (isXsp) {
					try {
						AspNetExecutionHandler.GetXspPath ((AspNetExecutionCommand)cmd);
					} catch (UserException ex) {
						MessageService.ShowError (
							GettextCatalog.GetString ("Could not launch ASP.NET web server"),
						    ex.Message);
						throw;
					}
				}

				console = context.ConsoleFactory.CreateConsole (monitor.CancellationToken);

				// The running Port value is now captured in the XspBrowserLauncherConsole object
				string url = String.Format ("http://{0}", XspParameters.Address);


				if (isXsp) {
					console = new XspBrowserLauncherConsole (console, delegate (string port) {
						if (browserExcTarget != null)
							browserExcTarget.DesktopApp.Launch (String.Format("{0}:{1}", url, port));
						else
							BrowserLauncher.LaunchDefaultBrowser (String.Format("{0}:{1}", url, port));
					});
				}

				monitor.Log.WriteLine (GettextCatalog.GetString ("Running web server..."));

				var op = context.ExecutionHandler.Execute (cmd, console);

				if (!isXsp) {
					if (browserExcTarget != null)
						browserExcTarget.DesktopApp.Launch (url);
					else
						BrowserLauncher.LaunchDefaultBrowser (url);
				}

				using (monitor.CancellationToken.Register (op.Cancel))
					await op.Task;

				monitor.Log.WriteLine (GettextCatalog.GetString ("The web server exited with code: {0}", op.ExitCode));

			} catch (Exception ex) {
				if (!(ex is UserException)) {
					LoggingService.LogError ("Could not launch ASP.NET web server.", ex);
				}
				monitor.ReportError (GettextCatalog.GetString ("Could not launch web server."), ex);
			} finally {
				if (console != null)
					console.Dispose ();
			}
		}
		public static XslCompiledTransform ValidateStylesheet (ProgressMonitor monitor, string xml, string fileName)
		{
			monitor.BeginTask (GettextCatalog.GetString ("Validating stylesheet..."), 1);
			bool error = true;
			XslCompiledTransform xslt = null;
			
			try {
				StringReader reader = new StringReader (xml);
				XPathDocument doc = new XPathDocument (reader);
				xslt = new XslCompiledTransform ();
				xslt.Load (doc, null, new XmlUrlResolver ());
				error = false;
			} catch (XsltCompileException ex) {
				monitor.ReportError (ex.Message, ex);
				AddTask (fileName, ex.Message, ex.LinePosition, ex.LineNumber,TaskSeverity.Error);
			}
			catch (XsltException ex) {
				monitor.ReportError (ex.Message, ex);
				AddTask (fileName, ex.Message, ex.LinePosition, ex.LineNumber,TaskSeverity.Error);
			}
			catch (XmlException ex) {
				monitor.ReportError (ex.Message, ex);
				AddTask (fileName, ex.Message, ex.LinePosition, ex.LineNumber,TaskSeverity.Error);
			}
			
			if (error) {
				monitor.Log.WriteLine (GettextCatalog.GetString ("Validation failed."));
				TaskService.ShowErrors ();
			} else {
				monitor.Log.WriteLine (GettextCatalog.GetString ("Stylesheet is valid."));
			}
			return error? null: xslt;
		}
		static async Task<bool> MigrateProject (ProgressMonitor monitor, SolutionItemExtensionNode st, MSBuildProject p, string fileName, string language)
		{
			var projectLoadMonitor = GetProjectLoadProgressMonitor (monitor);
			if (projectLoadMonitor == null) {
				// projectLoadMonitor will be null when running through md-tool, but
				// this is not fatal if migration is not required, so just ignore it. --abock
				if (!st.IsMigrationRequired)
					return false;

				LoggingService.LogError (Environment.StackTrace);
				monitor.ReportError ("Could not open unmigrated project and no migrator was supplied", null);
				throw new UserException ("Project migration failed");
			}
			
			var migrationType = st.MigrationHandler.CanPromptForMigration
				? await st.MigrationHandler.PromptForMigration (projectLoadMonitor, p, fileName, language)
				: projectLoadMonitor.ShouldMigrateProject ();
			if (migrationType == MigrationType.Ignore) {
				if (st.IsMigrationRequired) {
					monitor.ReportError (string.Format ("{1} cannot open the project '{0}' unless it is migrated.", Path.GetFileName (fileName), BrandingService.ApplicationName), null);
					throw new UserException ("The user choose not to migrate the project");
				} else
					return false;
			}
			
			var baseDir = (FilePath) Path.GetDirectoryName (fileName);
			if (migrationType == MigrationType.BackupAndMigrate) {
				var backupDirFirst = baseDir.Combine ("backup");
				string backupDir = backupDirFirst;
				int i = 0;
				while (Directory.Exists (backupDir)) {
					backupDir = backupDirFirst + "-" + i.ToString ();
					if (i++ > 20) {
						throw new Exception ("Too many backup directories");
					}
				}
				Directory.CreateDirectory (backupDir);
				foreach (var file in st.MigrationHandler.FilesToBackup (fileName))
					File.Copy (file, Path.Combine (backupDir, Path.GetFileName (file)));
			}

			if (!await st.MigrationHandler.Migrate (projectLoadMonitor, p, fileName, language))
				throw new UserException ("Project migration failed");

			return true;
		}
		protected async override Task DoExecute (ProgressMonitor monitor, ExecutionContext context, ConfigurationSelector configuration)
		{
			DotNetProjectConfiguration dotNetProjectConfig = GetConfiguration (configuration) as DotNetProjectConfiguration;
			if (dotNetProjectConfig == null) {
				monitor.ReportError (GettextCatalog.GetString ("Configuration '{0}' not found in project '{1}'", configuration, Name), null);
				return;
			}

			monitor.Log.WriteLine (GettextCatalog.GetString ("Running {0} ...", dotNetProjectConfig.CompiledOutputName));

			ExecutionCommand executionCommand = CreateExecutionCommand (configuration, dotNetProjectConfig);
			if (context.ExecutionTarget != null)
				executionCommand.Target = context.ExecutionTarget;

			if (!context.ExecutionHandler.CanExecute (executionCommand)) {
				monitor.ReportError (GettextCatalog.GetString ("Can not execute \"{0}\". The selected execution mode is not supported for .NET projects.", dotNetProjectConfig.CompiledOutputName), null);
				return;
			}

			try {
				await ProjectExtension.OnExecuteCommand (monitor, context, configuration, executionCommand);
			} catch (Exception ex) {
				LoggingService.LogError (string.Format ("Cannot execute \"{0}\"", dotNetProjectConfig.CompiledOutputName), ex);
				monitor.ReportError (GettextCatalog.GetString ("Cannot execute \"{0}\"", dotNetProjectConfig.CompiledOutputName), ex);
			}
		}