public override async Task <PersistedConfiguration> CollectAsync(IOperationCollectionContext context) { var fileOps = context.Agent.GetService <IFileOperationsExecuter>(); var client = new ProGetClient(this.Template.FeedUrl, this.Template.FeedName, this.Template.UserName, this.Template.Password, this); try { var packageId = PackageName.Parse(this.Template.PackageName); var packageInfo = await client.GetPackageInfoAsync(packageId).ConfigureAwait(false); var version = new ProGetPackageVersionSpecifier(this.Template.PackageVersion).GetBestMatch(packageInfo.versions); if (version == null) { this.LogError($"Package {this.Template.PackageName} does not have a version {this.Template.PackageVersion}."); return(null); } this.LogInformation($"Resolved package version is {version}."); if (!await fileOps.DirectoryExistsAsync(this.Template.TargetDirectory).ConfigureAwait(false)) { this.LogInformation(this.Template.TargetDirectory + " does not exist."); return(new ProGetPackageConfiguration { TargetDirectory = this.Template.TargetDirectory }); } var mask = new MaskingContext(this.Template.Includes, this.Template.Excludes); this.LogInformation(this.Template.TargetDirectory + " exists; getting remote file list..."); var remoteFileList = await fileOps.GetFileSystemInfosAsync(this.Template.TargetDirectory, mask).ConfigureAwait(false); var remoteFiles = new Dictionary <string, SlimFileSystemInfo>(remoteFileList.Count, StringComparer.OrdinalIgnoreCase); foreach (var file in remoteFileList) { var relativeName = file.FullName.Substring(this.Template.TargetDirectory.Length).Replace('\\', '/').Trim('/'); if (file is SlimDirectoryInfo) { relativeName += "/"; } remoteFiles.Add(relativeName, file); } remoteFileList = null; // async GC optimization this.LogDebug($"{this.Template.TargetDirectory} contains {remoteFiles.Count} file system entries."); this.LogInformation($"Connecting to {this.Template.FeedUrl} to get metadata for {this.Template.PackageName}:{version}..."); var versionInfo = await client.GetPackageVersionInfoAsync(packageId, version).ConfigureAwait(false); if (versionInfo.fileList == null) { this.LogError("File list is unavailable for this package; it may be an orphaned entry."); return(null); } this.LogDebug($"Package contains {versionInfo.fileList.Length} file system entries."); foreach (var entry in versionInfo.fileList) { var relativeName = entry.name; if (!mask.IsMatch(relativeName)) { continue; } var file = remoteFiles.GetValueOrDefault(relativeName); if (file == null) { this.LogInformation($"Entry {relativeName} is not present in {this.Template.TargetDirectory}."); return(new ProGetPackageConfiguration { TargetDirectory = this.Template.TargetDirectory }); } if (!entry.name.EndsWith("/")) { var fileInfo = (SlimFileInfo)file; if (entry.size != fileInfo.Size || entry.date != fileInfo.LastWriteTimeUtc) { this.LogInformation($"File {relativeName} in {this.Template.TargetDirectory} is different from file in package."); this.LogDebug($"Source info: {entry.size} bytes, {entry.date} timestamp"); this.LogDebug($"Target info: {fileInfo.Size} bytes, {fileInfo.LastWriteTimeUtc} timestamp"); return(new ProGetPackageConfiguration { TargetDirectory = this.Template.TargetDirectory }); } } } if (this.Template.DeleteExtra) { foreach (var name in remoteFiles.Keys) { if (!versionInfo.fileList.Any(entry => entry.name == name)) { this.LogInformation($"File {name} in {this.Template.TargetDirectory} does not exist in package."); return(new ProGetPackageConfiguration { TargetDirectory = this.Template.TargetDirectory }); } } } this.LogInformation($"All package files and directories are present in {this.Template.TargetDirectory}."); return(new ProGetPackageConfiguration { Current = true, TargetDirectory = this.Template.TargetDirectory }); } catch (ProGetException ex) { this.LogError(ex.FullMessage); return(null); } }
public override async Task ExecuteAsync(IOperationExecutionContext context) { var fileOps = context.Agent.GetService <IFileOperationsExecuter>(); var client = new ProGetClient(this.Server, this.FeedName, this.UserName, this.Password, this); try { var packageId = ProGet.PackageName.Parse(this.PackageName); this.LogInformation($"Connecting to {this.Server} to get metadata for {this.PackageName}..."); var packageInfo = await client.GetPackageInfoAsync(packageId).ConfigureAwait(false); var version = new ProGetPackageVersionSpecifier(this.PackageVersion).GetBestMatch(packageInfo.versions); if (version == null) { this.LogError($"Package {this.PackageName} does not have a version {this.PackageVersion}."); return; } this.LogInformation($"Resolved package version is {version}."); var deployInfo = PackageDeploymentData.Create(context, this, "Deployed by Get-Package operation, see URL for more info."); this.LogInformation("Downloading package..."); using (var zip = await client.DownloadPackageAsync(packageId, version, deployInfo).ConfigureAwait(false)) { var dirsCreated = new HashSet <string>(StringComparer.OrdinalIgnoreCase); this.LogDebug("Creating directory: " + this.TargetDirectory); await fileOps.CreateDirectoryAsync(this.TargetDirectory).ConfigureAwait(false); dirsCreated.Add(this.TargetDirectory); foreach (var entry in zip.Entries) { if (!entry.FullName.StartsWith("package/", StringComparison.OrdinalIgnoreCase) || entry.Length <= "package/".Length) { continue; } var relativeName = entry.FullName.Substring("package/".Length); var targetPath = fileOps.CombinePath(this.TargetDirectory, relativeName); if (relativeName.EndsWith("/")) { if (dirsCreated.Add(targetPath)) { await fileOps.CreateDirectoryAsync(targetPath).ConfigureAwait(false); } } else { var dir = PathEx.GetDirectoryName(targetPath); if (dirsCreated.Add(dir)) { await fileOps.CreateDirectoryAsync(dir).ConfigureAwait(false); } using (var targetStream = await fileOps.OpenFileAsync(targetPath, FileMode.Create, FileAccess.Write).ConfigureAwait(false)) using (var sourceStream = entry.Open()) { await sourceStream.CopyToAsync(targetStream).ConfigureAwait(false); } // timestamp in zip file is stored as UTC by convention await fileOps.SetLastWriteTimeAsync(targetPath, entry.LastWriteTime.DateTime).ConfigureAwait(false); } } } } catch (ProGetException ex) { this.LogError(ex.FullMessage); return; } this.LogInformation("Package deployed!"); }