/// <summary>
        /// Copies an existing file or directory at the specified absolute path into the target directory
        /// </summary>
        /// <param name="newPath">A path describing the new location of the copied file or directory</param>
        /// <param name="existingPath">The location of the existing file or directory on the disk</param>
        /// <returns></returns>
        public DirectoryBuilder AddExisting(StoragePath newPath, StoragePath existingPath)
        {
            this.existing.Add(new Tuple <StoragePath, StoragePath>(newPath, existingPath));

            return(this);
        }
        /// <summary>
        /// Runs all operations on the target directory asynchronously
        /// </summary>
        public async Task BuildAsync()
        {
            if (!Directory.Exists(this.RootDirectory.ToString()))
            {
                Directory.CreateDirectory(this.RootDirectory.ToString());
            }

            // Delete files and folders
            foreach (var item in this.deletions)
            {
                if (File.Exists(item.ToString()))
                {
                    File.Delete(item.ToString());
                }
                else
                {
                    this.DeleteDirectoryCore(item, new StoragePath());
                }
            }

            // Build existing directories
            foreach (var item in this.existing)
            {
                AppendDirectoryCore(item.Item2, item.Item1);
            }
            this.existing.Clear();

            // Read all zip files
            foreach (var item in this.zips)
            {
                using (item) {
                    foreach (var entry in item.Entries)
                    {
                        var stream = entry.Open();
                        this.AppendFile(entry.FullName, () => stream);
                    }
                }
            }
            this.zips.Clear();

            // Build directories
            foreach (var item in this.directories)
            {
                string dir = this.RootDirectory.Combine(item).ToString();

                if (!Directory.Exists(dir))
                {
                    Directory.CreateDirectory(dir);
                }
            }
            ;
            this.directories.Clear();

            // Build files
            foreach (var item in this.filesToBuild)
            {
                async Task WriteFile(string p, FileMode mode)
                {
                    using (FileStream writer = new FileStream(p, mode)) {
                        using (var reader = item.Stream) {
                            await reader.CopyToAsync(writer);
                        }

                        await writer.FlushAsync();
                    }
                }

                StoragePath path = this.RootDirectory + item.Path;
                string      dir  = path.ParentDirectory.ToString();

                if (!Directory.Exists(dir))
                {
                    Directory.CreateDirectory(dir);
                }

                bool targetExists = File.Exists(path.ToString());
                if (this.ConflictResolution == NameConflictOption.ThrowException && targetExists)
                {
                    throw new IOException($"The file '{Path.GetFileName(path.ToString())}' already exists");
                }
                else if (this.ConflictResolution == NameConflictOption.Skip && targetExists)
                {
                    continue;
                }
                else if (this.ConflictResolution == NameConflictOption.Rename && targetExists)
                {
                    await WriteFile(ResolveFileName(path.ToString()), FileMode.Create);
                }
                else
                {
                    await WriteFile(path.ToString(), FileMode.Create);
                }
            }
            ;
            this.filesToBuild.Clear();
        }
 /// <summary>
 /// Creates a new DirectoryBuilder that will place items in the specified directory
 /// and uses the specified conflict resolution
 /// </summary>
 /// <param name="directory">The target directory</param>
 /// <param name="conflictResolution">The method that will be used to resolve naming conflicts</param>
 public DirectoryBuilder(StoragePath directory, NameConflictOption conflictResolution = NameConflictOption.ThrowException)
 {
     this.RootDirectory      = directory;
     this.ConflictResolution = conflictResolution;
 }
        /// <summary>
        /// Extracts the contents of the specified archive to the output directory
        /// </summary>
        /// <param name="zip">The zip archive to extract</param>
        public DirectoryBuilder ExtractZip(StoragePath extractDirectory, StoragePath zipPath)
        {
            this.existingZips.Add(new Tuple <StoragePath, StoragePath>(extractDirectory, zipPath));

            return(this);
        }
        /// <summary>
        /// Extracts the contents of the specified archive to the output directory
        /// </summary>
        /// <param name="zip">The zip archive to extract</param>
        public DirectoryBuilder ExtractZip(StoragePath extractDirectory, ZipArchive zip)
        {
            this.zips.Add(new Tuple <StoragePath, ZipArchive>(extractDirectory, zip));

            return(this);
        }
 public DirectoryBuilder Delete(StoragePath relativePath)
 {
     this.deletions.Add(relativePath);
     return(this);
 }
 /// <summary>
 /// Places a new file with the specified relative path and contents into the target directory
 /// Example relative paths include "foo.txt", "/directory/foo.txt", and "/directory/other/foo.txt"
 /// </summary>
 /// <param name="relativePath">The relative path to the new file, starting in the DirectoryBuilder's target directory</param>
 /// <param name="contents">The string contents to place into the new file</param>
 public DirectoryBuilder AddFile(StoragePath relativePath, string contents)
 {
     return(this.AddFile(relativePath, contents, Encoding.UTF8));
 }
 /// <summary>
 /// Places a new file with the specified relative path into the target directory
 /// Example relative paths include "foo.txt", "/directory/foo.txt", and "/directory/other/foo.txt"
 /// </summary>
 /// <param name="relativePath">The relative path to the new file, starting in the DirectoryBuilder's target directory</param>
 public DirectoryBuilder AddFile(StoragePath relativePath)
 {
     return(this.AddFile(relativePath, string.Empty));
 }