Skip to content

Commit 542352a

Browse files
committed
Adds overwrite option.
1 parent 61b4289 commit 542352a

File tree

8 files changed

+105
-22
lines changed

8 files changed

+105
-22
lines changed

CameraUtility.Tests/TransferFilesCommandsTests.cs

Lines changed: 60 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ public void Copy_directory_copies_all_supported_files()
9696

9797
var filesCount = FilesWithMetadata.Count();
9898
output.Should().EndWith(
99-
$"Found {filesCount} camera files. Processed {filesCount}. Skipped 0. Transferred {filesCount}.\n");
99+
$"Found {filesCount} camera file(s). Processed {filesCount}. Skipped 0. Transferred {filesCount}.\n");
100100

101101

102102
void VerifyDirectoryCreatedAndFileCopied(
@@ -146,7 +146,7 @@ public void Move_directory_copies_all_supported_files()
146146

147147
var filesCount = FilesWithMetadata.Count();
148148
output.Should().EndWith(
149-
$"Found {filesCount} camera files. Processed {filesCount}. Skipped 0. Transferred {filesCount}.\n");
149+
$"Found {filesCount} camera file(s). Processed {filesCount}. Skipped 0. Transferred {filesCount}.\n");
150150

151151

152152
void VerifyDirectoryCreatedAndFileCopied(
@@ -210,7 +210,59 @@ public void Copy_directory_skips_files_which_already_exist_in_the_destination()
210210
output.Should().EndWith(
211211
"Skipped 1 file(s) because they already exist at the destination.\n" +
212212
$"{fileWithMetadata.sourceFile} exists as {fileWithMetadata.expectedDestinationFile}\n\n" +
213-
"Found 1 camera files. Processed 1. Skipped 1. Transferred 0.\n");
213+
"Found 1 camera file(s). Processed 1. Skipped 1. Transferred 0.\n");
214+
}
215+
216+
[Fact]
217+
public void Copy_overwrites_files_which_already_exist_in_the_destination_in_overwrite_mode()
218+
{
219+
/* Arrange */
220+
var fileWithMetadata =
221+
(
222+
sourceFile: $"{SourceDirPath}/IMG_1234.JPG",
223+
exifTags: NewImageFileTags("2010:01:12 13:14:15", "42"),
224+
expectedDestinationDirectory: $"{DestinationDirPath}/2010_01_12",
225+
expectedDestinationFile: $"{DestinationDirPath}/2010_01_12/IMG_20100112_131415420.JPG");
226+
var fixture = new Fixture().Customize(new AutoMoqCustomization());
227+
var fileSystemMock =
228+
fixture
229+
.Freeze<Mock<IFileSystem>>()
230+
.SetupDefaults()
231+
.SetupSourceDirectoryWithFiles(SourceDirPath, new[] {fileWithMetadata.sourceFile});
232+
fileSystemMock
233+
.Setup(fs => fs.Directory.Exists(fileWithMetadata.expectedDestinationDirectory))
234+
.Returns(true);
235+
fileSystemMock
236+
.Setup(fs => fs.File.Exists(fileWithMetadata.expectedDestinationFile))
237+
.Returns(true);
238+
fixture
239+
.Freeze<Mock<IMetadataReader>>()
240+
.SetupMetadata(new[] {(fileWithMetadata.sourceFile, fileWithMetadata.exifTags)});
241+
var consoleTextWriterMock = new StringWriter();
242+
fixture.Inject<TextWriter>(consoleTextWriterMock);
243+
var sut = fixture.Create<Program>();
244+
245+
/* Act */
246+
var result = sut.Execute($"copy {SourceDirPath} {DestinationDirPath} --overwrite".Split());
247+
248+
/* Assert */
249+
result.Should().Be(0);
250+
var output = consoleTextWriterMock.ToString();
251+
var (file, _, _, expectedDestinationFile) = fileWithMetadata;
252+
VerifyDirectoryCreatedAndFileCopied(file, expectedDestinationFile);
253+
output.Should().Contain($"{file} -> {expectedDestinationFile}");
254+
output.Should().EndWith("Found 1 camera file(s). Processed 1. Skipped 0. Transferred 1.\n");
255+
256+
void VerifyDirectoryCreatedAndFileCopied(
257+
string sourceFile,
258+
string destinationFile)
259+
{
260+
fileSystemMock.Verify(fs =>
261+
fs.File.Copy(
262+
sourceFile,
263+
destinationFile,
264+
true));
265+
}
214266
}
215267

216268
[Fact]
@@ -277,7 +329,7 @@ public void Files_are_not_transferred_in_dry_run_mode(
277329

278330
var filesCount = FilesWithMetadata.Count();
279331
output.Should().EndWith(
280-
$"Found {filesCount} camera files. Processed {filesCount}. Skipped 0. Transferred 0.\n");
332+
$"Found {filesCount} camera file(s). Processed {filesCount}. Skipped 0. Transferred 0.\n");
281333
}
282334

283335
[Fact]
@@ -312,7 +364,7 @@ public void First_error_stops_execution()
312364
var output = consoleTextWriterMock.ToString();
313365
output.Should().Be(
314366
$"Failed {SourceDirPath}/IMG_1234.JPG: PROCESSING EXCEPTION\n\n" +
315-
"Found 2 camera files. Processed 1. Skipped 0. Transferred 0.\n");
367+
"Found 2 camera file(s). Processed 1. Skipped 0. Transferred 0.\n");
316368
fileSystemMock.Verify(fs =>
317369
fs.File.Copy(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<bool>()),
318370
Times.Never);
@@ -368,7 +420,7 @@ public void Errors_do_not_stop_execution_in_keep_going_mode()
368420
"Following errors occurred:\n" +
369421
$"{SourceDirPath}/IMG_1234.JPG: PROCESSING EXCEPTION\n" +
370422
$"{SourceDirPath}/IMG_2345.jpg: Metadata not found\n\n" +
371-
"Found 3 camera files. Processed 3. Skipped 0. Transferred 1.\n");
423+
"Found 3 camera file(s). Processed 3. Skipped 0. Transferred 1.\n");
372424
fileSystemMock.Verify(fs =>
373425
fs.File.Copy($"{SourceDirPath}/IMG_1234.JPG", It.IsAny<string>(), It.IsAny<bool>()),
374426
Times.Never);
@@ -426,7 +478,7 @@ public void Cancellation_stops_execution_and_prints_summary()
426478
$"{SourceDirPath}/IMG_1234.JPG -> {DestinationDirPath}/2010_01_12/IMG_20100112_131415420.JPG\n" +
427479
$"Created {DestinationDirPath}/2011_02_13\n" +
428480
$"{SourceDirPath}/IMG_4231.JPEG -> {DestinationDirPath}/2011_02_13/IMG_20110213_141516430.JPEG\n\n" +
429-
"Found 3 camera files. Processed 2. Skipped 0. Transferred 2.\n" +
481+
"Found 3 camera file(s). Processed 2. Skipped 0. Transferred 2.\n" +
430482
"Operation interrupted by user.\n");
431483
fileSystemMock.Verify(fs =>
432484
fs.File.Copy(
@@ -499,7 +551,7 @@ public void Copy_directory_copies_all_supported_files()
499551

500552
var filesCount = FilesWithMetadata.Count();
501553
output.Should().EndWith(
502-
$"Found {filesCount} camera files. Processed {filesCount}. Skipped 0. Transferred {filesCount}.\n");
554+
$"Found {filesCount} camera file(s). Processed {filesCount}. Skipped 0. Transferred {filesCount}.\n");
503555

504556

505557
void VerifyDirectoryCreatedAndFileCopied(

CameraUtility/Commands/ImageFilesTransfer/AbstractTransferImageFilesCommand.cs

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,18 @@ protected AbstractTransferImageFilesCommand(
1818
AddOption(new DryRunOption());
1919
AddOption(new KeepGoingOption());
2020
AddOption(new SkipDateSubdirOption());
21+
AddOption(new OverwriteOption());
2122

22-
Handler = CommandHandler.Create<string, string, bool, bool, bool>(
23-
(srcPath, dstDir, dryRun, keepGoing, skipDateSubdir) =>
23+
Handler = CommandHandler.Create<string, string, bool, bool, bool, bool>(
24+
(srcPath, dstDir, dryRun, keepGoing, skipDateSubdir, overwrite) =>
2425
handler(
2526
new OptionArgs(
2627
new SourcePath(srcPath),
2728
new DestinationDirectory(dstDir),
2829
new DryRun(dryRun),
2930
new KeepGoing(keepGoing),
30-
new SkipDateSubdirectory(skipDateSubdir))));
31+
new SkipDateSubdirectory(skipDateSubdir),
32+
new Overwrite(overwrite))));
3133
}
3234

3335
internal delegate int OptionsHandler(OptionArgs options);
@@ -92,12 +94,24 @@ public SkipDateSubdirOption()
9294
{
9395
}
9496
}
97+
98+
private class OverwriteOption :
99+
Option<bool>
100+
{
101+
public OverwriteOption()
102+
: base(
103+
"--overwrite",
104+
"Transfer files even if they already exist in destination.")
105+
{
106+
}
107+
}
95108

96109
internal sealed record OptionArgs(
97110
SourcePath SourcePath,
98111
DestinationDirectory DestinationDirectory,
99112
DryRun DryRun,
100113
KeepGoing KeepGoing,
101-
SkipDateSubdirectory SkipDateSubdirectory);
114+
SkipDateSubdirectory SkipDateSubdirectory,
115+
Overwrite Overwrite);
102116
}
103117
}

CameraUtility/Commands/ImageFilesTransfer/CameraFileNameConverter.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ internal CameraFileNameConverter(
2626
internal Result<(string destinationDirectory, string destinationFileName)> Convert(
2727
CameraFileTransferer.Args args)
2828
{
29-
var (cameraFilePath, destinationRootDirectory, _, skipDateSubdirectoryOption) = args;
29+
var (cameraFilePath, destinationRootDirectory, _, skipDateSubdirectoryOption, _) = args;
3030
var cameraFileResult = GetCameraFile(cameraFilePath);
3131
if (cameraFileResult.IsFailure)
3232
{

CameraUtility/Commands/ImageFilesTransfer/Execution/CameraFileTransferer.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,15 +39,15 @@ internal Result TransferFile(Args args)
3939
var destinationFilePath =
4040
new CameraFilePath(_fileSystem.Path.Combine(destinationDirectory, destinationFileName));
4141
var destinationAlreadyExists = _fileSystem.File.Exists(destinationFilePath);
42-
if (destinationAlreadyExists)
42+
if (destinationAlreadyExists && !args.Overwrite)
4343
{
4444
OnFileSkipped(this, (args.CameraFilePath, destinationFilePath));
4545
return Result.Success();
4646
}
4747

4848
if (!args.DryRun)
4949
{
50-
_transferFiles(args.CameraFilePath, destinationFilePath);
50+
_transferFiles(args.CameraFilePath, destinationFilePath, args.Overwrite);
5151
}
5252

5353
OnFileTransferred(this, (args.CameraFilePath, destinationFilePath, args.DryRun));
@@ -66,12 +66,13 @@ internal Result TransferFile(Args args)
6666
internal delegate void TransferFiles(
6767
CameraFilePath sourcePath,
6868
CameraFilePath destinationPath,
69-
bool overwrite = false);
69+
bool overwrite);
7070

7171
internal sealed record Args(
7272
CameraFilePath CameraFilePath,
7373
DestinationDirectory DestinationRootDirectory,
7474
DryRun DryRun,
75-
SkipDateSubdirectory SkipDateSubdirectory);
75+
SkipDateSubdirectory SkipDateSubdirectory,
76+
Overwrite Overwrite);
7677
}
7778
}

CameraUtility/Commands/ImageFilesTransfer/Execution/Orchestrator.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,11 @@ int IOrchestrator.Execute(AbstractTransferImageFilesCommand.OptionArgs args)
4040
var transferResult =
4141
_cameraFileTransferer.TransferFile(
4242
new CameraFileTransferer.Args(
43-
cameraFilePath, args.DestinationDirectory, args.DryRun, args.SkipDateSubdirectory));
43+
cameraFilePath,
44+
args.DestinationDirectory,
45+
args.DryRun,
46+
args.SkipDateSubdirectory,
47+
args.Overwrite));
4448
if (transferResult.IsFailure)
4549
{
4650
OnError(this, (cameraFilePath, transferResult.Error));
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
using System.Diagnostics;
2+
using System.Diagnostics.CodeAnalysis;
3+
4+
namespace CameraUtility.Commands.ImageFilesTransfer.Options
5+
{
6+
[DebuggerDisplay("{Value}")]
7+
[SuppressMessage("ReSharper", "UseNameofExpression")]
8+
internal sealed record Overwrite(bool Value) :
9+
TypedOption<bool>(Value);
10+
}

CameraUtility/Commands/ImageFilesTransfer/Output/Report.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ private void PrintSummary()
131131
_textWriter.WriteLine();
132132
Console.ForegroundColor = _errors.Any() ? ConsoleColor.Red : ConsoleColor.Green;
133133
_textWriter.WriteLine(
134-
$"Found {_cameraFilesFound} camera files. " +
134+
$"Found {_cameraFilesFound} camera file(s). " +
135135
$"Processed {_cameraFilesProcessed}. " +
136136
$"Skipped {_cameraFilesSkipped.Count}. " +
137137
$"Transferred {_cameraFilesTransferred}.");

README.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,9 @@ Options: │
112112
-k, --keep-going Try to continue operation when errors for │
113113
individual files occur. │
114114
--skip-date-subdir Do not create date sub-directories in destination │
115-
directory.
115+
directory. │
116+
--overwrite Transfer files even if they already exist in │
117+
destination.
116118
```
117119

118120
The `<src-path>` and `<dst-dir>` are the only required
@@ -169,5 +171,5 @@ etc.
169171

170172
## Things to Do
171173

172-
* Force-overwrite mode.
173-
* List of individual files as input.
174+
* List of multiple individual files as input (currently only a single
175+
file or entire directory is supported)

0 commit comments

Comments
 (0)