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++;
            }
        }