diff --git a/git-bin.Tests/CommandFactoryTest.cs b/git-bin.Tests/CommandFactoryTest.cs index 231d007..7d9703e 100644 --- a/git-bin.Tests/CommandFactoryTest.cs +++ b/git-bin.Tests/CommandFactoryTest.cs @@ -22,7 +22,7 @@ public void GetShowUsageCommand_InvokesShowUsageFactory() return null; }; - var target = new CommandFactory(factory, null, null, null, null, null); + var target = new CommandFactory(factory, null, null, null, null, null, null, null); target.GetShowUsageCommand(); Assert.IsTrue(wasShowUsageCommandFactoryCalled); @@ -34,7 +34,7 @@ public void GetCommand_InvalidCommandArgument_ReturnsShowUsageCommand() var showUsageCommand = new ShowUsageCommand(); Func factory = () => showUsageCommand; - var target = new CommandFactory(factory, null, null, null, null, null); + var target = new CommandFactory(factory, null, null, null, null, null, null, null); var command = target.GetCommand(new []{"invalid"}); Assert.AreSame(showUsageCommand, command); @@ -46,7 +46,7 @@ public void GetCommand_NoCommandArgument_ReturnsShowUsageCommand() var showUsageCommand = new ShowUsageCommand(); Func factory = () => showUsageCommand; - var target = new CommandFactory(factory, null, null, null, null, null); + var target = new CommandFactory(factory, null, null, null, null, null, null, null); var command = target.GetCommand(new string[0]); Assert.AreSame(showUsageCommand, command); @@ -58,7 +58,7 @@ public void GetCommand_CleanCommandArgument_ReturnsCleanCommand() var cleanCommand = new CleanCommand(null, null, new []{"abc"}); Func factory = x => cleanCommand; - var target = new CommandFactory(null, null, factory, null, null, null); + var target = new CommandFactory(null, null, null, factory, null, null, null, null); var command = target.GetCommand(new[] { CommandFactory.CleanArgument }); Assert.AreSame(cleanCommand, command); @@ -78,7 +78,7 @@ public void GetCommand_CleanCommandArgument_PassesTailOfArgumentArray() return null; }; - var target = new CommandFactory(null, null, factory, null, null, null); + var target = new CommandFactory(null, null, null, factory, null, null, null, null); target.GetCommand(inputArguments); Assert.IsTrue(wasInvoked); @@ -90,7 +90,7 @@ public void GetCommand_SmudgeCommandArgument_ReturnsSmudgeCommand() var smudgeCommand = new SmudgeCommand(null, null, new string[0]); Func factory = x => smudgeCommand; - var target = new CommandFactory(null, null, null, factory, null, null); + var target = new CommandFactory(null, null, null, null, factory, null, null, null); var command = target.GetCommand(new[] { CommandFactory.SmudgeArgument }); Assert.AreSame(smudgeCommand, command); @@ -99,10 +99,10 @@ public void GetCommand_SmudgeCommandArgument_ReturnsSmudgeCommand() [Test] public void GetCommand_PushCommandArgument_ReturnsPushCommand() { - var pushCommand = new PushCommand(null, null, null); + var pushCommand = new PushCommand(null, null, new string[0]); Func factory = x => pushCommand; - var target = new CommandFactory(null, null, null, null, factory, null); + var target = new CommandFactory(null, null, null, null, null, factory, null, null); var command = target.GetCommand(new[] { CommandFactory.PushArgument }); Assert.AreSame(pushCommand, command); @@ -122,10 +122,22 @@ public void GetCommand_PushCommandArgument_PassesTailOfArgumentArray() return null; }; - var target = new CommandFactory(null, null, null, null, factory, null); + var target = new CommandFactory(null, null, null, null, null, factory, null, null); target.GetCommand(inputArguments); Assert.IsTrue(wasInvoked); } + + [Test] + public void GetCommand_ClearCommandArgument_ReturnsClearCommand() + { + var clearCommand = new ClearCommand(null, new []{"-n"}); + Func factory = x => clearCommand; + + var target = new CommandFactory(null, null, null, null, null, null, null, factory); + var command = target.GetCommand(new[] { CommandFactory.ClearArgument }); + + Assert.AreSame(clearCommand, command); + } } } diff --git a/git-bin.Tests/Commands/ClearCommandTest.cs b/git-bin.Tests/Commands/ClearCommandTest.cs new file mode 100644 index 0000000..9e9fd41 --- /dev/null +++ b/git-bin.Tests/Commands/ClearCommandTest.cs @@ -0,0 +1,42 @@ +using GitBin; +using GitBin.Commands; +using Moq; +using NUnit.Framework; + +namespace git_bin.Tests.Commands +{ + [TestFixture] + public class ClearCommandTest + { + private Mock _cacheManager; + + [SetUp] + public void SetUp() + { + _cacheManager = new Mock(MockBehavior.Strict); + } + + [Test] + public void Execute_Force_CallsClearCache() + { + _cacheManager.Setup(x => x.ClearCache()).Verifiable(); + + var target = new ClearCommand(_cacheManager.Object, new[] {"-f"}); + target.Execute(); + + _cacheManager.Verify(); + } + + [Test] + public void Execute_DryRun_DoesNotClearCache() + { + // mock is strict, so calling ClearCache will throw + _cacheManager.Setup(x => x.ListFiles()).Returns(new GitBinFileInfo[0]); + + var target = new ClearCommand(_cacheManager.Object, new[] { "-n" }); + target.Execute(); + + Assert.Pass(); + } + } +} \ No newline at end of file diff --git a/git-bin.Tests/Commands/StatusCommandTest.cs b/git-bin.Tests/Commands/StatusCommandTest.cs deleted file mode 100644 index 5616d98..0000000 --- a/git-bin.Tests/Commands/StatusCommandTest.cs +++ /dev/null @@ -1,54 +0,0 @@ -using GitBin; -using GitBin.Commands; -using GitBin.Remotes; -using Moq; -using NUnit.Framework; - -namespace git_bin.Tests.Commands -{ - [TestFixture] - public class StatusCommandTest - { - private Mock _cacheManager; - private Mock _remote; - - [SetUp] - public void SetUp() - { - _cacheManager = new Mock(); - _remote = new Mock(); - } - - [Test] - public void GetHumanReadableSize_LessThanOrEqualTo1K_StringIsBytes() - { - var zero = StatusCommand.GetHumanReadableSize(0); - var fifty = StatusCommand.GetHumanReadableSize(50); - var kilobyte = StatusCommand.GetHumanReadableSize(1024); - - Assert.AreEqual("0B", zero); - Assert.AreEqual("50B", fifty); - Assert.AreEqual("1k", kilobyte); - } - - [Test] - public void GetHumanReadableSize_Between1KAnd1MInclusive_StringIsKB() - { - var ninePointEight = StatusCommand.GetHumanReadableSize(10035); - var megabyte = StatusCommand.GetHumanReadableSize(1024*1024); - - Assert.AreEqual("9.8k", ninePointEight); - Assert.AreEqual("1M", megabyte); - } - - [Test] - public void GetHumanReadableSize_Between1Mand1GInclusive_StringIsMB() - { - var fourPointTwo = StatusCommand.GetHumanReadableSize(4404019); - var gigabyte = StatusCommand.GetHumanReadableSize(1024*1024*1024); - - Assert.AreEqual("4.2M", fourPointTwo); - Assert.AreEqual("1G", gigabyte); - } - } -} \ No newline at end of file diff --git a/git-bin.Tests/GitBinFileInfoUtilsTest.cs b/git-bin.Tests/GitBinFileInfoUtilsTest.cs new file mode 100644 index 0000000..83466a3 --- /dev/null +++ b/git-bin.Tests/GitBinFileInfoUtilsTest.cs @@ -0,0 +1,44 @@ +using GitBin; +using GitBin.Commands; +using GitBin.Remotes; +using Moq; +using NUnit.Framework; + +namespace git_bin.Tests +{ + [TestFixture] + public class GitBinFileInfoUtilsTest + { + [Test] + public void GetHumanReadableSize_LessThanOrEqualTo1K_StringIsBytes() + { + var zero = GitBinFileInfoUtils.GetHumanReadableSize(0); + var fifty = GitBinFileInfoUtils.GetHumanReadableSize(50); + var kilobyte = GitBinFileInfoUtils.GetHumanReadableSize(1024); + + Assert.AreEqual("0B", zero); + Assert.AreEqual("50B", fifty); + Assert.AreEqual("1k", kilobyte); + } + + [Test] + public void GetHumanReadableSize_Between1KAnd1MInclusive_StringIsKB() + { + var ninePointEight = GitBinFileInfoUtils.GetHumanReadableSize(10035); + var megabyte = GitBinFileInfoUtils.GetHumanReadableSize(1024 * 1024); + + Assert.AreEqual("9.8k", ninePointEight); + Assert.AreEqual("1M", megabyte); + } + + [Test] + public void GetHumanReadableSize_Between1Mand1GInclusive_StringIsMB() + { + var fourPointTwo = GitBinFileInfoUtils.GetHumanReadableSize(4404019); + var gigabyte = GitBinFileInfoUtils.GetHumanReadableSize(1024 * 1024 * 1024); + + Assert.AreEqual("4.2M", fourPointTwo); + Assert.AreEqual("1G", gigabyte); + } + } +} \ No newline at end of file diff --git a/git-bin.Tests/git-bin.Tests.csproj b/git-bin.Tests/git-bin.Tests.csproj index a4e9c7e..08e1185 100644 --- a/git-bin.Tests/git-bin.Tests.csproj +++ b/git-bin.Tests/git-bin.Tests.csproj @@ -56,9 +56,10 @@ + - + diff --git a/git-bin/ApplicationRegistrations.cs b/git-bin/ApplicationRegistrations.cs index d2b3fc9..3f0867b 100644 --- a/git-bin/ApplicationRegistrations.cs +++ b/git-bin/ApplicationRegistrations.cs @@ -22,7 +22,9 @@ public static void Register(IBuilder builder) builder.RegisterFactory(); builder.RegisterFactory(); + builder.RegisterFactory(); builder.RegisterFactory(); + builder.RegisterFactory(); builder.RegisterFactory(); builder.RegisterFactory(); builder.RegisterFactory(); diff --git a/git-bin/CacheManager.cs b/git-bin/CacheManager.cs index a370b51..9442dc3 100644 --- a/git-bin/CacheManager.cs +++ b/git-bin/CacheManager.cs @@ -10,8 +10,9 @@ public interface ICacheManager byte[] ReadFileFromCache(string filename); void WriteFileToCache(string filename, byte[] contents, int contentLength); void WriteFileToCache(string filename, Stream stream); - string[] GetFilenamesNotInCache(IEnumerable filenamesToCheck); GitBinFileInfo[] ListFiles(); + void ClearCache(); + string[] GetFilenamesNotInCache(IEnumerable filenamesToCheck); string GetPathForFile(string filename); } @@ -75,6 +76,14 @@ public GitBinFileInfo[] ListFiles() return gitBinFileInfos.ToArray(); } + public void ClearCache() + { + foreach (var file in ListFiles()) + { + File.Delete(GetPathForFile(file.Name)); + } + } + public string[] GetFilenamesNotInCache(IEnumerable filenamesToCheck) { var filenamesInCache = ListFiles().Select(fi => fi.Name); diff --git a/git-bin/CommandFactory.cs b/git-bin/CommandFactory.cs index 458a64a..dc16680 100644 --- a/git-bin/CommandFactory.cs +++ b/git-bin/CommandFactory.cs @@ -14,31 +14,38 @@ public class CommandFactory : ICommandFactory { public const string VersionArgument = "--version"; public const string CleanArgument = "clean"; + public const string ClearArgument = "clear"; public const string SmudgeArgument = "smudge"; public const string PushArgument = "push"; public const string StatusArgument = "status"; private readonly Func _showUsageCommandFactory; private readonly Func _versionCommandFactory; + private readonly Func _printCommandFactory; private readonly Func _cleanCommandFactory; private readonly Func _smudgeCommandFactory; private readonly Func _pushCommandFactory; private readonly Func _statusCommandFactory; + private readonly Func _clearCommandFactory; public CommandFactory( Func showUsageCommandFactory, Func versionCommandFactory, + Func printCommandFactory, Func cleanCommandFactory, Func smudgeCommandFactory, Func pushCommandFactory, - Func statusCommandFactory) + Func statusCommandFactory, + Func clearCommandFactory) { _showUsageCommandFactory = showUsageCommandFactory; _versionCommandFactory = versionCommandFactory; + _printCommandFactory = printCommandFactory; _cleanCommandFactory = cleanCommandFactory; _smudgeCommandFactory = smudgeCommandFactory; _pushCommandFactory = pushCommandFactory; _statusCommandFactory = statusCommandFactory; + _clearCommandFactory = clearCommandFactory; } public ICommand GetCommand(string[] args) @@ -51,23 +58,32 @@ public ICommand GetCommand(string[] args) try { - if (commandArgument == VersionArgument) - return _versionCommandFactory(); + switch (commandArgument) + { + case VersionArgument: + return _versionCommandFactory(); - if (commandArgument == CleanArgument) - return _cleanCommandFactory(argsTail); + case CleanArgument: + return _cleanCommandFactory(argsTail); - if (commandArgument == SmudgeArgument) - return _smudgeCommandFactory(argsTail); + case ClearArgument: + return _clearCommandFactory(argsTail); - if (commandArgument == PushArgument) - return _pushCommandFactory(argsTail); + case SmudgeArgument: + return _smudgeCommandFactory(argsTail); - if (commandArgument == StatusArgument) - return _statusCommandFactory(argsTail); + case PushArgument: + return _pushCommandFactory(argsTail); + + case StatusArgument: + return _statusCommandFactory(argsTail); + } } - catch (ArgumentException) + catch (ArgumentException e) { + if (!string.IsNullOrEmpty(e.Message)) + return _printCommandFactory(e.Message); + return GetShowUsageCommand(); } diff --git a/git-bin/Commands/ClearCommand.cs b/git-bin/Commands/ClearCommand.cs new file mode 100644 index 0000000..2822e53 --- /dev/null +++ b/git-bin/Commands/ClearCommand.cs @@ -0,0 +1,57 @@ +using System; + +namespace GitBin.Commands +{ + public class ClearCommand : ICommand + { + public const string DryRunArgument = "-n"; + public const string ForceArgument = "-f"; + + private readonly ICacheManager _cacheManager; + private readonly bool _isDryRun; + + public ClearCommand( + ICacheManager cacheManager, + string[] args) + { + if (!TryParseArguments(args, out _isDryRun)) + throw new ArgumentException(string.Format("clear command requires either {0} or {1}", DryRunArgument, ForceArgument)); + + _cacheManager = cacheManager; + } + + public void Execute() + { + if (_isDryRun) + { + GitBinConsole.WriteLine("clear dry run: would remove " + + GitBinFileInfoUtils.GetHumanReadableSize(_cacheManager.ListFiles())); + } + else + { + _cacheManager.ClearCache(); + } + } + + private bool TryParseArguments(string[] args, out bool isDryRun) + { + isDryRun = true; + + if (args.Length != 1) + return false; + + switch (args[0]) + { + case DryRunArgument: + return true; + + case ForceArgument: + isDryRun = false; + return true; + + default: + return false; + } + } + } +} \ No newline at end of file diff --git a/git-bin/Commands/PrintCommand.cs b/git-bin/Commands/PrintCommand.cs new file mode 100644 index 0000000..254e297 --- /dev/null +++ b/git-bin/Commands/PrintCommand.cs @@ -0,0 +1,17 @@ +namespace GitBin.Commands +{ + public class PrintCommand : ICommand + { + private readonly string _message; + + public PrintCommand(string message) + { + _message = message; + } + + public void Execute() + { + GitBinConsole.WriteLine(_message); + } + } +} \ No newline at end of file diff --git a/git-bin/Commands/ShowUsageCommand.cs b/git-bin/Commands/ShowUsageCommand.cs index 1af8774..fb9de88 100644 --- a/git-bin/Commands/ShowUsageCommand.cs +++ b/git-bin/Commands/ShowUsageCommand.cs @@ -11,8 +11,7 @@ public void Execute() GitBinConsole.WriteNoPrefix(Environment.NewLine); GitBinConsole.WriteLineNoPrefix("List of available commands:"); GitBinConsole.WriteLineNoPrefix(" clean Clean filter. Should only be used with .gitattributes filtering"); -// GitBinConsole.WriteLineNoPrefix(" gc Clean up unnecessary files in the local cache directory"); -// GitBinConsole.WriteLineNoPrefix(" init Install helper hooks"); + GitBinConsole.WriteLineNoPrefix(" clear Remove all files in the local cache directory. Requires -n or -f"); GitBinConsole.WriteLineNoPrefix(" push Upload changed files to the remote file repository"); GitBinConsole.WriteLineNoPrefix(" smudge Smudge filter. Should only be used with .gitattributes filtering"); GitBinConsole.WriteLineNoPrefix(" status Display status of the local cache. [-r], include the remote repo"); diff --git a/git-bin/Commands/StatusCommand.cs b/git-bin/Commands/StatusCommand.cs index 17f224c..f104e1e 100644 --- a/git-bin/Commands/StatusCommand.cs +++ b/git-bin/Commands/StatusCommand.cs @@ -8,12 +8,11 @@ namespace GitBin.Commands public class StatusCommand : ICommand { public const string ShowRemoteArgument = "-r"; - private static string[] Suffixes = new[] {"B", "k", "M", "G", "T", "P", "E"}; private readonly ICacheManager _cacheManager; private readonly IRemote _remote; private readonly bool _shouldShowRemote; - private GitBinFileInfo[] _filesInLocalCache; + private readonly GitBinFileInfo[] _filesInLocalCache; public StatusCommand( ICacheManager cacheManager, @@ -31,7 +30,7 @@ public class StatusCommand : ICommand } else { - throw new ArgumentException(); + throw new ArgumentException("status command only has one valid option: " + ShowRemoteArgument); } } @@ -53,51 +52,24 @@ public void Execute() private void PrintStatusAboutCache() { - var sizeOfCache = _filesInLocalCache.Sum(fi => fi.Size); - GitBinConsole.WriteLineNoPrefix("Local cache:"); GitBinConsole.WriteLineNoPrefix(" items: {0}", _filesInLocalCache.Length); - GitBinConsole.WriteLineNoPrefix(" size: {0}", GetHumanReadableSize(sizeOfCache)); + GitBinConsole.WriteLineNoPrefix(" size: {0}", GitBinFileInfoUtils.GetHumanReadableSize(_filesInLocalCache)); } private void PrintStatusAboutRemote() { var remoteFiles = _remote.ListFiles(); - var sizeOfRemote = remoteFiles.Sum(fi => fi.Size); - GitBinConsole.WriteLineNoPrefix("Remote repo:"); + GitBinConsole.WriteLineNoPrefix("\nRemote repo:"); GitBinConsole.WriteLineNoPrefix(" items: {0}", remoteFiles.Length); - GitBinConsole.WriteLineNoPrefix(" size: {0}", GetHumanReadableSize(sizeOfRemote)); + GitBinConsole.WriteLineNoPrefix(" size: {0}", GitBinFileInfoUtils.GetHumanReadableSize(remoteFiles)); var filesToPush = _filesInLocalCache.Except(remoteFiles).ToList(); - var sizeOfFilesToPush = filesToPush.Sum(fi => fi.Size); - GitBinConsole.WriteLineNoPrefix("To push:"); + GitBinConsole.WriteLineNoPrefix("\nTo push:"); GitBinConsole.WriteLineNoPrefix(" items: {0}", filesToPush.Count); - GitBinConsole.WriteLineNoPrefix(" size: {0}", GetHumanReadableSize(sizeOfFilesToPush)); - } - - public static string GetHumanReadableSize(long numberOfBytes) - { - int suffixIndex = 0; - int increment = 1024; - double scaledNumberOfBytes = numberOfBytes; - - if (numberOfBytes > 0) - { - while (scaledNumberOfBytes >= increment) - { - suffixIndex++; - scaledNumberOfBytes /= increment; - } - - if (Math.Abs(scaledNumberOfBytes - 0) < 0.1) - { - scaledNumberOfBytes = 1; - } - } - - return string.Format("{0}{1}", scaledNumberOfBytes.ToString("0.#"), Suffixes[suffixIndex]); + GitBinConsole.WriteLineNoPrefix(" size: {0}", GitBinFileInfoUtils.GetHumanReadableSize(filesToPush)); } } } \ No newline at end of file diff --git a/git-bin/GitBinFileInfoUtils.cs b/git-bin/GitBinFileInfoUtils.cs new file mode 100644 index 0000000..811bf2e --- /dev/null +++ b/git-bin/GitBinFileInfoUtils.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace GitBin +{ + public static class GitBinFileInfoUtils + { + private static string[] Suffixes = new[] { "B", "k", "M", "G", "T", "P", "E" }; + + public static string GetHumanReadableSize(IEnumerable fileInfos) + { + var totalSize = fileInfos.Sum(fi => fi.Size); + + return GetHumanReadableSize(totalSize); + } + + public static string GetHumanReadableSize(long numberOfBytes) + { + int suffixIndex = 0; + int increment = 1024; + double scaledNumberOfBytes = numberOfBytes; + + if (numberOfBytes > 0) + { + while (scaledNumberOfBytes >= increment) + { + suffixIndex++; + scaledNumberOfBytes /= increment; + } + + if (Math.Abs(scaledNumberOfBytes - 0) < 0.1) + { + scaledNumberOfBytes = 1; + } + } + + return String.Format("{0}{1}", scaledNumberOfBytes.ToString("0.#"), Suffixes[suffixIndex]); + } + } +} \ No newline at end of file diff --git a/git-bin/git-bin.csproj b/git-bin/git-bin.csproj index 3e5a0e6..4dc9d22 100644 --- a/git-bin/git-bin.csproj +++ b/git-bin/git-bin.csproj @@ -57,9 +57,12 @@ + + +