protected static async Task CopyFilesAsync(IFileOperationsExecuter fileOps, string sourceDirectory, string targetDirectory, bool keepInternals = false) { if (!await fileOps.DirectoryExistsAsync(sourceDirectory).ConfigureAwait(false)) { return; } char separator = fileOps.DirectorySeparator; var infos = await fileOps.GetFileSystemInfosAsync(sourceDirectory, keepInternals?MaskingContext.IncludeAll : new MaskingContext(new[] { "**" }, new[] { "**" + separator + ".git**", ".git**" })).ConfigureAwait(false); var directoriesToCreate = infos.OfType <SlimDirectoryInfo>().Select(d => CombinePaths(targetDirectory, d.FullName.Substring(sourceDirectory.Length), separator)).ToArray(); var relativeFileNames = infos.OfType <SlimFileInfo>().Select(f => f.FullName.Substring(sourceDirectory.Length).TrimStart(separator)).ToArray(); await fileOps.CreateDirectoryAsync(targetDirectory).ConfigureAwait(false); foreach (string folder in directoriesToCreate) { await fileOps.CreateDirectoryAsync(folder).ConfigureAwait(false); } await fileOps.FileCopyBatchAsync( sourceDirectory, relativeFileNames, targetDirectory, relativeFileNames, true, true ).ConfigureAwait(false); }
private async Task TransferFileAsync(IFileOperationsExecuter sourceFileOps, SlimFileInfo sourceFile, IFileOperationsExecuter targetFileOps, SlimFileSystemInfo target, string targetDirectory) { if (target == null) { if (this.VerboseLogging) { this.LogDebug($"{sourceFile.Name} does not exist in {targetDirectory}."); } } var targetFile = target as SlimFileInfo; if (targetFile != null) { this.LogDebug($"{sourceFile.Name} already exists in {targetDirectory}."); this.LogDebug($"Source timestamp: {sourceFile.LastWriteTimeUtc}, Target timestamp: {targetFile.LastWriteTimeUtc}"); this.LogDebug($"Source size: {sourceFile.Size}, Target size: {targetFile.Size}"); if (sourceFile.LastWriteTimeUtc == targetFile.LastWriteTimeUtc && sourceFile.Size == targetFile.Size) { this.LogDebug($"Size and timestamp are the same; skipping {sourceFile.Name}..."); return; } } else if (target != null) { this.LogDebug($"{sourceFile.Name} is a file in {sourceFile.DirectoryName}, but a directory in {targetDirectory}."); this.LogDebug($"Deleting directory {target.FullName}..."); await targetFileOps.DeleteDirectoriesAsync(new[] { target.FullName }).ConfigureAwait(false); } else { if (!string.IsNullOrEmpty(targetDirectory)) { await targetFileOps.CreateDirectoryAsync(targetDirectory).ConfigureAwait(false); } } var targetFileName = PathEx.Combine(targetDirectory, sourceFile.Name).Replace(sourceFileOps.DirectorySeparator, targetFileOps.DirectorySeparator); this.LogDebug($"Transferring {sourceFile.Name} to {targetDirectory}..."); using (var sourceStream = await sourceFileOps.OpenFileAsync(sourceFile.FullName, FileMode.Open, FileAccess.Read).ConfigureAwait(false)) using (var targetStream = await targetFileOps.OpenFileAsync(targetFileName, FileMode.Create, FileAccess.Write).ConfigureAwait(false)) { await sourceStream.CopyToAsync(targetStream).ConfigureAwait(false); } }
private async Task CopyDirectoryAsync(IFileOperationsExecuter fileOps, string sourcePath, string targetPath, IOperationExecutionContext context) { if (!await fileOps.DirectoryExistsAsync(sourcePath).ConfigureAwait(false)) { this.LogWarning($"Source directory {sourcePath} does not exist."); return; } var infos = await fileOps.GetFileSystemInfosAsync( sourcePath, new MaskingContext(this.Includes, this.Excludes) ).ConfigureAwait(false); var files = infos.OfType <SlimFileInfo>(); foreach (var file in files) { context.CancellationToken.ThrowIfCancellationRequested(); var targetFileName = PathEx.Combine(targetPath, file.FullName.Substring(sourcePath.Length).TrimStart('/', '\\')); if (this.VerboseLogging) { this.LogDebug($"Copying {file.FullName} to {targetFileName}..."); } try { if (!this.Overwrite && await fileOps.FileExistsAsync(targetFileName).ConfigureAwait(false)) { this.LogError($"Target file {targetFileName} already exists and overwrite is set to false."); continue; } await fileOps.CreateDirectoryAsync(file.DirectoryName).ConfigureAwait(false); await fileOps.CopyFileAsync(file.FullName, targetFileName, this.Overwrite).ConfigureAwait(false); this.filesCopied++; } catch (Exception ex) { this.LogError($"Cannot copy {file.FullName}: {ex.Message}"); } } var dirs = infos.OfType <SlimDirectoryInfo>(); foreach (var dir in dirs) { context.CancellationToken.ThrowIfCancellationRequested(); var targetDir = PathEx.Combine(targetPath, dir.FullName.Substring(sourcePath.Length).TrimStart('/', '\\')); if (this.VerboseLogging) { this.LogDebug($"Creating directory {targetDir}..."); } await fileOps.CreateDirectoryAsync(targetDir).ConfigureAwait(false); this.directoriesCopied++; } }
private async Task LockRegistryAsync(IFileOperationsExecuter fileOps, CancellationToken cancellationToken) { var fileName = fileOps.CombinePath(this.RegistryRoot, ".lock"); var lockDescription = "Locked by " + SDK.ProductName; var lockToken = Guid.NewGuid().ToString(); TryAgain: var fileInfo = await getFileInfoAsync().ConfigureAwait(false); string lastToken = null; while (fileInfo.Item1 != null && DateTime.UtcNow - fileInfo.Item1.LastWriteTimeUtc <= new TimeSpan(0, 0, 10)) { if ((lastToken == null || !string.Equals(lastToken, fileInfo.Item3)) && fileInfo.Item3 != null) { this.logger?.LogDebug("Package registry is locked: " + fileInfo.Item2); lastToken = fileInfo.Item3; } await Task.Delay(500, cancellationToken).ConfigureAwait(false); fileInfo = await getFileInfoAsync().ConfigureAwait(false); } // ensure registry root exists await fileOps.CreateDirectoryAsync(this.RegistryRoot).ConfigureAwait(false); try { // write out the lock info using (var lockStream = await fileOps.OpenFileAsync(fileName, FileMode.Create, FileAccess.Write).ConfigureAwait(false)) using (var writer = new StreamWriter(lockStream, InedoLib.UTF8Encoding)) { writer.WriteLine(lockDescription); writer.WriteLine(lockToken); } // verify that we acquired the lock using (var lockStream = await fileOps.OpenFileAsync(fileName, FileMode.Open, FileAccess.Read).ConfigureAwait(false)) using (var reader = new StreamReader(lockStream, InedoLib.UTF8Encoding)) { if (reader.ReadLine() != lockDescription) { goto TryAgain; } if (reader.ReadLine() != lockToken) { goto TryAgain; } } } catch (IOException ex) { this.logger?.LogDebug("Locking package registry failed: " + ex.Message); // file may be in use by other process goto TryAgain; } // at this point, lock is acquired provided everyone is following the rules this.LockToken = lockToken; async Task <(SlimFileInfo, string, string)> getFileInfoAsync() { try { var info = await fileOps.GetFileInfoAsync(fileName).ConfigureAwait(false); string description = null, token = null; try { using (var lockStream = await fileOps.OpenFileAsync(fileName, FileMode.Open, FileAccess.Read).ConfigureAwait(false)) using (var reader = new StreamReader(lockStream, InedoLib.UTF8Encoding)) { description = await reader.ReadLineAsync().ConfigureAwait(false); token = await reader.ReadLineAsync().ConfigureAwait(false); } } catch (IOException) { } return(info, description, token); } catch (FileNotFoundException) { return(null, null, null); } catch (DirectoryNotFoundException) { return(null, null, null); } } }