/// <summary> /// Reverts an individual component /// </summary> /// <param name="dwSvc">The watermark service to use</param> /// <param name="name">The name of the component</param> /// <param name="version">The version of the component</param> internal void RevertComponent(DownloadWatermarkService dwSvc, string name, string version) { var dFac = new DownloaderFactory(); IDependencyDownloaderWatermark wm = null; var wmName = name; var wmVersion = version; try { wm = dwSvc.Load(name, version); if (null == wm) { // TODO: might consider logging this to a trace file Debug.Fail( string.Format( "Unable to load a watermark for component {0}@{1}. This situation should never occur due to the fact that the same method is reading and writing the watermarks", name, version)); } // Read name and version information from watermark (saving can convert name and version back to hashes). if (wm.Tags.ContainsKey("name")) { wmName = wm.Tags["name"]; } if (wm.Tags.ContainsKey("version")) { wmVersion = wm.Tags["version"]; } var cleaner = dFac.GetDownloader(wm.DownloadType); Logger.Instance().Log(TraceLevel.Info, "{0}: Cleaning component {1}#{2} ...", CommandType, wmName, wmVersion); cleaner.RevertDownload(wm); dwSvc.Delete(wm); } catch { if (null != wm) { dwSvc.Save(wm, name, version); } } if (!_silentMode) { _logger.LogMsg(string.Format(" * Component {0} (Version:{1}) cleaned.", wmName, wmVersion)); } Logger.Instance().Log(TraceLevel.Info, "{0}: Component {1}#{2} successfully cleaned", CommandType, wmName, wmVersion); }
/// <summary> /// Determines the source, target location and worker settings and initializes download workers according to their type. /// </summary> /// <param name="dws">The downloader wartermark service.</param> /// <param name="component">The component node in graph to start download from.</param> /// <param name="recursive">Indicates if the dependencies should be fetched recursively or not.</param> /// <param name="force">If set to <c>true</c> it indicates that the get operation is forced and all files have to be overwritten. Otherwise false.</param> private void DownloadComponent(DownloadWatermarkService dws, IComponent component, bool recursive, bool force) { var df = new DownloaderFactory(); var componentAlreadyDownloaded = false; var settings = new Settings <DownloaderValidSettings>(); IDependencyDownloader worker; string destLocation; string targetLocation; bool removeTempFiles = false; Logger.Instance().Log(TraceLevel.Info, "{0}: Downloading component {1}#{2} ...", CommandType, component.Name, component.Version); // Create worker and settings according to type if (component.Type.Equals(ComponentType.FileShare)) { var fileShareRootPath = component.GetFieldValue(DependencyProviderValidSettingName.FileShareRootPath); destLocation = Path.Combine(fileShareRootPath, component.Name.Path, component.Version.Version); var relativeTargetPath = component.GetFieldValue(DependencyProviderValidSettingName.RelativeOutputPath); targetLocation = relativeTargetPath == null ? Path.GetFullPath(Path.Combine(_defaultDownloadFolder, _defaultRelativeOutputPath)) : Path.GetFullPath(Path.Combine(_defaultDownloadFolder, relativeTargetPath)); LoadFilterSettings(component, settings); } else if (component.Type.Equals(ComponentType.VNextBuildResult)) { var url = component.GetFieldValue(DependencyProviderValidSettingName.BuildTeamProjectCollectionUrl); if (!Uri.IsWellFormedUriString(url, UriKind.Absolute)) { Logger.Instance().Log( TraceLevel.Error, "{0}: Invalid BuildTeamProjectCollectionUrl setting '{1}' was found for component {2}#{3}", CommandType, url, component.Name, component.Version); throw new DependencyServiceException( string.Format( " ! Invalid download information was found for build result control component {0} (BuildTeamProjectCollectionUrl setting)", component.Name.GetName())); } // Connect to tfs server var tpc = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(new Uri(url)); tpc.EnsureAuthenticated(); // Connect to version control service var versionControl = tpc.GetService <VersionControlServer>(); if (versionControl == null) { Logger.Instance().Log(TraceLevel.Error, "{0}: Connection to version control server failed for component {1}#{2}", CommandType, component.Name, component.Version); throw new DependencyServiceException(string.Format(" ! Could not connect to TFS version control server for team project collection {0}", component.GetFieldValue(DependencyProviderValidSettingName.BuildTeamProjectCollectionUrl))); } var tpcUrl = new Uri(url); var connection = new VssConnection(tpcUrl, new VssClientCredentials(true)); var client = connection.GetClient <BuildHttpClient>(); var builds = client.GetBuildsAsync(project: component.Name.TeamProject, type: DefinitionType.Build).Result; var buildResult = builds.FirstOrDefault(r => r.BuildNumber == component.Version.BuildNumber); if (buildResult == null) { Logger.Instance().Log(TraceLevel.Error, "{0}: No vnext build result could not be determined for component {1}#{2}", CommandType, component.Name, component.Version); throw new DependencyServiceException(string.Format(" ! Could not determine build result component {0}", component.Name.GetName())); } var artifacts = client.GetArtifactsAsync(component.Name.TeamProject, buildResult.Id).Result; destLocation = Path.Combine(Path.GetTempPath(), "VNextDM_" + Guid.NewGuid()); Directory.CreateDirectory(destLocation); removeTempFiles = true; foreach (var artifact in artifacts) { if (artifact.Resource.Type == "FilePath") { var sourceDirName = $"{artifact.Resource.Data}/{artifact.Name}"; DirectoryCopy(sourceDirName, destLocation, true); } else { var content = client.GetArtifactContentZipAsync(component.Name.TeamProject, buildResult.Id, artifact.Name); using (var zipArchive = new ZipArchive(content.Result)) { zipArchive.ExtractToDirectory(destLocation); } } } var relativeTargetPath = component.GetFieldValue(DependencyProviderValidSettingName.RelativeOutputPath); targetLocation = relativeTargetPath == null ? Path.GetFullPath(Path.Combine(_defaultDownloadFolder, _defaultRelativeOutputPath)) : Path.GetFullPath(Path.Combine(_defaultDownloadFolder, relativeTargetPath)); LoadFilterSettings(component, settings); } else if (component.Type.Equals(ComponentType.BuildResult)) { if (!Uri.IsWellFormedUriString(component.GetFieldValue(DependencyProviderValidSettingName.BuildTeamProjectCollectionUrl), UriKind.Absolute)) { Logger.Instance().Log( TraceLevel.Error, "{0}: Invalid BuildTeamProjectCollectionUrl setting '{1}' was found for component {2}#{3}", CommandType, component.GetFieldValue(DependencyProviderValidSettingName.BuildTeamProjectCollectionUrl), component.Name, component.Version); throw new DependencyServiceException( string.Format( " ! Invalid download information was found for build result control component {0} (BuildTeamProjectCollectionUrl setting)", component.Name.GetName())); } // Connect to tfs server var tpc = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(new Uri(component.GetFieldValue(DependencyProviderValidSettingName.BuildTeamProjectCollectionUrl))); tpc.EnsureAuthenticated(); // Connect to version control service var versionControl = tpc.GetService <VersionControlServer>(); if (versionControl == null) { Logger.Instance().Log(TraceLevel.Error, "{0}: Connection to version control server failed for component {1}#{2}", CommandType, component.Name, component.Version); throw new DependencyServiceException(string.Format(" ! Could not connect to TFS version control server for team project collection {0}", component.GetFieldValue(DependencyProviderValidSettingName.BuildTeamProjectCollectionUrl))); } // Connect to build server var buildServer = tpc.GetService <IBuildServer>(); if (buildServer == null) { Logger.Instance().Log(TraceLevel.Error, "{0}: Connection to build server failed for component {1}#{2}", CommandType, component.Name, component.Version); throw new DependencyServiceException(string.Format(" ! Could not connect to TFS build server for team project collection {0}", component.GetFieldValue(DependencyProviderValidSettingName.BuildTeamProjectCollectionUrl))); } var buildDef = buildServer.GetBuildDefinition(component.Name.TeamProject, component.Name.BuildDefinition); var buildDetailSpec = buildServer.CreateBuildDetailSpec(buildDef); buildDetailSpec.BuildNumber = component.Version.BuildNumber; buildDetailSpec.InformationTypes = new string[] { }; var buildResult = buildServer.QueryBuilds(buildDetailSpec); if (buildResult == null || buildResult.Builds == null || buildResult.Builds.Length == 0) { Logger.Instance().Log(TraceLevel.Error, "{0}: No build result could not be determined for component {1}#{2}", CommandType, component.Name, component.Version); throw new DependencyServiceException(string.Format(" ! Could not determine drop location for build result component {0}", component.Name.GetName())); } // Determine source location var dropLocation = buildResult.Builds[0].DropLocation; // TODO dga: Is this a bug? it returns localhost for the computer name while we are not running this code on the server (I guess)? if (string.IsNullOrEmpty(dropLocation)) { Logger.Instance().Log(TraceLevel.Error, "{0}: Drop location could not be determined for component {1}#{2}", CommandType, component.Name, component.Version); throw new DependencyServiceException(string.Format("! Could not determine drop location for build result component {0}", component.Name.GetName())); } destLocation = dropLocation; var relativeTargetPath = component.GetFieldValue(DependencyProviderValidSettingName.RelativeOutputPath); targetLocation = relativeTargetPath == null ? Path.GetFullPath(Path.Combine(_defaultDownloadFolder, _defaultRelativeOutputPath)) : Path.GetFullPath(Path.Combine(_defaultDownloadFolder, relativeTargetPath)); LoadFilterSettings(component, settings); } else if (component.Type.Equals(ComponentType.SourceControl)) { if (!Uri.IsWellFormedUriString(component.GetFieldValue(DependencyProviderValidSettingName.WorkspaceTeamProjectCollectionUrl), UriKind.Absolute)) { Logger.Instance().Log( TraceLevel.Error, "{0}: Invalid WorkspaceTeamProjectCollectionUrl setting '{1}' was found for component {2}#{3}", CommandType, component.GetFieldValue(DependencyProviderValidSettingName.WorkspaceTeamProjectCollectionUrl), component.Name, component.Version); throw new DependencyServiceException( string.Format( " ! Invalid download information was found for source control component {0} (WorkspaceTeamProjectCollectionUrl setting)", component.Name.GetName())); } var workspaceName = component.GetFieldValue(DependencyProviderValidSettingName.WorkspaceName); if (string.IsNullOrEmpty(workspaceName)) { Logger.Instance().Log(TraceLevel.Error, "{0}: WorkspaceName setting was not specified for component {1}#{2}", CommandType, component.Name, component.Version); throw new DependencyServiceException( string.Format( " ! Invalid download information was found for source control component {0} (WorkspaceName setting)", component.Name.GetName())); } var workspaceOwner = component.GetFieldValue(DependencyProviderValidSettingName.WorkspaceOwner); if (string.IsNullOrEmpty(workspaceOwner)) { Logger.Instance().Log(TraceLevel.Error, "{0}: WorkspaceOwner setting was not specified for component {1}#{2}", CommandType, component.Name, component.Version); throw new DependencyServiceException( string.Format( " ! Invalid download information was found for source control component {0} (WorkspaceOwner setting)", component.Name.GetName())); } destLocation = component.Name.ToString(); settings.AddSetting(new KeyValuePair <DownloaderValidSettings, string>(DownloaderValidSettings.VersionString, component.Version.ToString())); var relativeTargetPath = component.GetFieldValue(DependencyProviderValidSettingName.RelativeOutputPath); targetLocation = Path.GetFullPath( relativeTargetPath == null ? Path.Combine(_defaultDownloadFolder, "..", VersionControlPath.GetFileName(component.Name.ToString())) : Path.Combine(_defaultDownloadFolder, relativeTargetPath)); } else if (component.Type.Equals(ComponentType.SourceControlCopy)) { destLocation = component.Name.ToString(); settings.AddSetting(new KeyValuePair <DownloaderValidSettings, string>(DownloaderValidSettings.VersionString, component.Version.ToString())); var relativeTargetPath = component.GetFieldValue(DependencyProviderValidSettingName.RelativeOutputPath); targetLocation = Path.GetFullPath( relativeTargetPath == null ? Path.Combine(_defaultDownloadFolder, "..", VersionControlPath.GetFileName(component.Name.ToString())) : Path.Combine(_defaultDownloadFolder, relativeTargetPath)); LoadFilterSettings(component, settings); } else if (component.Type.Equals(ComponentType.BinaryRepository)) { var repositoryTeamProject = component.GetFieldValue(DependencyProviderValidSettingName.BinaryRepositoryTeamProject); if (string.IsNullOrEmpty(repositoryTeamProject)) { Logger.Instance().Log(TraceLevel.Error, "{0}: BinaryRepositoryTeamProject setting was not specified for component {1}#{2}", CommandType, component.Name, component.Version); throw new DependencyServiceException( string.Format( " ! Invalid download information was found for binary repository component {0} (BinaryRepositoryTeamProject setting)", component.Name.GetName())); } destLocation = VersionControlPath.Combine(VersionControlPath.Combine(VersionControlPath.Combine(VersionControlPath.RootFolder, repositoryTeamProject), component.Name.GetName()), component.Version.GetVersion()); settings.AddSetting(new KeyValuePair <DownloaderValidSettings, string>(DownloaderValidSettings.VersionString, VersionSpec.Latest.DisplayString)); var relativeOutputPath = component.GetFieldValue(DependencyProviderValidSettingName.RelativeOutputPath); targetLocation = Path.GetFullPath( relativeOutputPath == null ? Path.Combine(_defaultDownloadFolder, _defaultRelativeOutputPath) : Path.Combine(_defaultDownloadFolder, relativeOutputPath)); LoadFilterSettings(component, settings); } else if (component.Type.Equals(ComponentType.Subversion)) { destLocation = string.Format("{0}", component.Name); settings.AddSetting(new KeyValuePair <DownloaderValidSettings, string>(DownloaderValidSettings.VersionString, component.Version.ToString())); var relativeTargetPath = component.GetFieldValue(DependencyProviderValidSettingName.RelativeOutputPath); targetLocation = relativeTargetPath == null ? Path.GetFullPath(Path.Combine(_defaultDownloadFolder, _defaultRelativeOutputPath)) : Path.GetFullPath(Path.Combine(_defaultDownloadFolder, relativeTargetPath)); LoadFilterSettings(component, settings); } else { Logger.Instance().Log(TraceLevel.Error, "{0}: Unknown dependency type '{1}' was found in dependency graph", CommandType, component.Type.GetType()); throw new DependencyServiceException(" ! Invalid dependency node found in graph!"); } //Determine Multi-Site path for BuildResult and FileShare-Provider if (component.Type.Equals(ComponentType.FileShare) || (component.Type.Equals(ComponentType.BuildResult))) { destLocation = DetermineMultiSiteSourceLocation(destLocation); } if (string.IsNullOrEmpty(destLocation)) { Logger.Instance().Log(TraceLevel.Error, "{0}: Source location was not set for component {1}#{2}", CommandType, component.Name, component.Version); throw new DependencyServiceException(string.Format(" ! Error occured while preparing to download component {0} (Source location was not set)", component.Name.GetName())); } if (string.IsNullOrEmpty(targetLocation)) { Logger.Instance().Log(TraceLevel.Error, "{0}: Target location was not set for component {1}#{2}", CommandType, component.Name, component.Version); throw new DependencyServiceException(string.Format(" ! Error occured while preparing to download component {0} (Destination location was not set)", component.Name.GetName())); } // Download files try { IDependencyDownloaderWatermark wm = null; try { worker = df.GetDownloader(component); wm = dws.Load(component.Name.GetName(), component.Version.GetVersion()) ?? new DownloaderWatermark(worker); worker.Download(destLocation, targetLocation, wm, force, settings); } finally { if (null != wm) { dws.Save(wm, component.Name.GetName(), component.Version.GetVersion()); } if (removeTempFiles) { Directory.Delete(destLocation, true); } } } catch (Exception e) { if (e is DependencyServiceException) { throw; } // ReSharper disable RedundantIfElseBlock else if (e is ComponentAlreadyDownloadedException) // ReSharper restore RedundantIfElseBlock { componentAlreadyDownloaded = true; } else { Logger.Instance().Log(TraceLevel.Error, "{0}: Exception {1} occured while downloading files: {2}", CommandType, e, e.Message); throw new DependencyServiceException(string.Format(" ! Download of component {0} failed ({1})", component.Name.GetName(), e.Message)); } } // Log download if (!_silentMode) { _logger.LogMsg( !componentAlreadyDownloaded ? string.Format( " * Component {0} (Version:{1}) downloaded to target directory {2}", component.Name.GetName(), component.Version.GetVersion(), targetLocation) : string.Format( " * Skipped component {0} (Version:{1}). Already present in target directory {2}", component.Name.GetName(), component.Version.GetVersion(), targetLocation)); } Logger.Instance().Log( TraceLevel.Info, !componentAlreadyDownloaded ? "{0}: Component {1}#{2} successfully downloaded to target directory {3}" : "{0}: Component {1}#{2} download was skipped. Already present in target directory {3}", CommandType, component.Name, component.Version, targetLocation); }