-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add command line arguments and make behavior configurable.
You can now turn any step on or off (whether to copy new files, whether to update existing files, whether to delete extra remaining files). You can choose two new steps: delete changed files or delete identical files. Who knows where it can be useful.
- Loading branch information
1 parent
b8ea605
commit d61ff81
Showing
8 changed files
with
439 additions
and
72 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,203 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
|
||
namespace GuiLabs.FileUtilities | ||
{ | ||
public class Arguments | ||
{ | ||
private string[] args; | ||
|
||
public string Source { get; set; } | ||
public string Destination { get; set; } | ||
public string Pattern { get; set; } = "*"; | ||
|
||
public bool CopyLeftOnlyFiles { get; private set; } = true; | ||
public bool UpdateChangedFiles { get; private set; } = true; | ||
public bool DeleteRightOnlyFiles { get; private set; } = true; | ||
public bool CopyEmptyDirectories { get; private set; } = true; | ||
public bool DeleteRightOnlyDirectories { get; private set; } = true; | ||
public bool DeleteSameFiles { get; private set; } | ||
public bool DeleteChangedFiles { get; private set; } | ||
public bool WhatIf { get; set; } | ||
public bool Quiet { get; set; } | ||
public bool Help { get; set; } | ||
|
||
public string Error { get; set; } = ""; | ||
|
||
public Arguments() | ||
{ | ||
args = new string[0]; | ||
} | ||
|
||
public Arguments(params string[] args) | ||
{ | ||
this.args = args; | ||
Parse(); | ||
} | ||
|
||
private void Parse() | ||
{ | ||
var switches = new List<string>(); | ||
var paths = new List<string>(); | ||
|
||
foreach (var arg in args) | ||
{ | ||
if (arg.StartsWith("/") || arg.StartsWith("-")) | ||
{ | ||
switches.Add(arg.Substring(1).ToLowerInvariant()); | ||
} | ||
else | ||
{ | ||
paths.Add(TrimQuotes(arg)); | ||
} | ||
} | ||
|
||
if (switches.Any()) | ||
{ | ||
if (switches.Where(s => s != "q" && s != "whatif").Any()) | ||
{ | ||
// if any of c, u, d, ds or dc are specified, they're in explicit mode, assume all defaults false | ||
CopyLeftOnlyFiles = false; | ||
UpdateChangedFiles = false; | ||
DeleteRightOnlyFiles = false; | ||
CopyEmptyDirectories = false; | ||
DeleteRightOnlyDirectories = false; | ||
} | ||
|
||
foreach (var key in switches) | ||
{ | ||
switch (key) | ||
{ | ||
case "c": | ||
CopyLeftOnlyFiles = true; | ||
break; | ||
case "u": | ||
UpdateChangedFiles = true; | ||
break; | ||
case "cu": | ||
CopyLeftOnlyFiles = true; | ||
UpdateChangedFiles = true; | ||
break; | ||
case "d": | ||
DeleteRightOnlyFiles = true; | ||
break; | ||
case "cd": | ||
CopyLeftOnlyFiles = true; | ||
DeleteRightOnlyFiles = true; | ||
break; | ||
case "cud": | ||
CopyLeftOnlyFiles = true; | ||
UpdateChangedFiles = true; | ||
DeleteRightOnlyFiles = true; | ||
break; | ||
case "ds": | ||
DeleteSameFiles = true; | ||
break; | ||
case "dc": | ||
DeleteChangedFiles = true; | ||
break; | ||
case "q": | ||
Quiet = true; | ||
Log.Quiet = true; | ||
break; | ||
case "h": | ||
case "help": | ||
case "?": | ||
Help = true; | ||
Error = "Help argument cannot be combined with any other arguments"; | ||
return; | ||
case "whatif": | ||
WhatIf = true; | ||
if (switches.Count == 1) | ||
{ | ||
// if whatif is the only switch, assume the defaults | ||
CopyLeftOnlyFiles = true; | ||
UpdateChangedFiles = true; | ||
DeleteRightOnlyFiles = true; | ||
CopyEmptyDirectories = true; | ||
DeleteRightOnlyDirectories = true; | ||
} | ||
|
||
break; | ||
default: | ||
Error += "Unrecognized argument: " + key + Environment.NewLine; | ||
return; | ||
} | ||
} | ||
} | ||
|
||
if (Quiet && WhatIf) | ||
{ | ||
Error = "-q and -whatif are incompatible. Choose one or the other."; | ||
return; | ||
} | ||
|
||
if (DeleteChangedFiles && UpdateChangedFiles) | ||
{ | ||
Error = "Incompatible options: -u and -dc (can't update and delete changed files at the same time"; | ||
return; | ||
} | ||
|
||
if (paths.Count < 2) | ||
{ | ||
Error = "Two paths need to be specified (source and destination)"; | ||
return; | ||
} | ||
|
||
if (paths.Count > 3) | ||
{ | ||
Error = "Unable to process extra argument: " + paths[3]; | ||
return; | ||
} | ||
|
||
if (paths.Count == 3) | ||
{ | ||
var patterns = paths.Where(p => p.Contains("*") || p.Contains("?")).ToArray(); | ||
if (patterns.Length != 1) | ||
{ | ||
Error = $"Expected exactly one file pattern, {patterns.Length} was specified"; | ||
return; | ||
} | ||
|
||
if (paths[2] != patterns[0]) | ||
{ | ||
Error = "File pattern should be specified after Source and Destination arguments"; | ||
return; | ||
} | ||
|
||
Pattern = paths[2]; | ||
} | ||
|
||
if (Pattern != "*") | ||
{ | ||
// when we're not comparing all files, don't synchronize directories | ||
CopyEmptyDirectories = false; | ||
DeleteRightOnlyDirectories = false; | ||
} | ||
|
||
if (!CopyLeftOnlyFiles) | ||
{ | ||
CopyEmptyDirectories = false; | ||
} | ||
|
||
if (!DeleteRightOnlyFiles) | ||
{ | ||
DeleteRightOnlyDirectories = false; | ||
} | ||
|
||
Source = paths[0]; | ||
Destination = paths[1]; | ||
} | ||
|
||
private static string TrimQuotes(string path) | ||
{ | ||
if (path.Length > 2 && path[0] == '"' && path[path.Length - 1] == '"') | ||
{ | ||
path = path.Substring(1, path.Length - 2); | ||
} | ||
|
||
return path; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
using System.IO; | ||
|
||
namespace GuiLabs.FileUtilities | ||
{ | ||
public class FileSystem | ||
{ | ||
public static void CopyFile(string source, string destination, bool speculative) | ||
{ | ||
if (speculative) | ||
{ | ||
Log.WriteLine($"Would copy {source} to {destination}"); | ||
} | ||
else | ||
{ | ||
Log.WriteLine($"Copy {source} to {destination}"); | ||
var destinationFolder = Path.GetDirectoryName(destination); | ||
Directory.CreateDirectory(destinationFolder); | ||
File.Copy(source, destination, overwrite: true); | ||
} | ||
} | ||
|
||
public static void DeleteFile(string deletedFilePath, bool speculative) | ||
{ | ||
if (speculative) | ||
{ | ||
Log.WriteLine("Would delete " + deletedFilePath); | ||
} | ||
else | ||
{ | ||
Log.WriteLine("Delete " + deletedFilePath); | ||
var attributes = File.GetAttributes(deletedFilePath); | ||
if ((attributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly) | ||
{ | ||
File.SetAttributes(deletedFilePath, attributes & ~FileAttributes.ReadOnly); | ||
} | ||
|
||
File.Delete(deletedFilePath); | ||
} | ||
} | ||
|
||
public static void CreateDirectory(string newFolder, bool speculative) | ||
{ | ||
if (speculative) | ||
{ | ||
Log.WriteLine("Would create " + newFolder); | ||
} | ||
else | ||
{ | ||
Log.WriteLine("Create " + newFolder); | ||
Directory.CreateDirectory(newFolder); | ||
} | ||
} | ||
|
||
public static void DeleteDirectory(string deletedFolderPath, bool speculative) | ||
{ | ||
if (speculative) | ||
{ | ||
Log.WriteLine("Would delete " + deletedFolderPath); | ||
} | ||
else | ||
{ | ||
Log.WriteLine("Delete " + deletedFolderPath); | ||
Directory.Delete(deletedFolderPath, recursive: true); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.