Skip to content

Commit

Permalink
keep folder structure for copyfiles tasks
Browse files Browse the repository at this point in the history
add unit test

yet it is not possible to test behavior without to change fixture

change overloads for default value

fix comments

add tests for WithFilePaths and WithStrings

fix whitespace

use IFileSystem instead of System.File.IO

reomve unused param

change logic for getting common path

fix copy log message

remove unnecessary casting

update version

add old overloads without preseverFolderStructure

fix spelling
  • Loading branch information
martinscholz83 committed Oct 26, 2016
1 parent ad97ab2 commit 8232e43
Show file tree
Hide file tree
Showing 13 changed files with 194 additions and 29 deletions.
43 changes: 43 additions & 0 deletions src/Cake.Common.Tests/Unit/IO/FileAliasesTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,20 @@ public void Should_Throw_If_Any_File_Do_Not_Exist()
Assert.Equal("The file '/Working/file2.txt' does not exist.", result?.Message);
}

[Fact]
public void Should_Keep_Folder_Structure()
{
// Given
var fixture = new FileCopyFixture();

// When
FileAliases.CopyFiles(fixture.Context, fixture.SourceFilePaths, "./target");

// Then
fixture.TargetFiles[0].Received(1).Copy(Arg.Any<FilePath>(), true);
fixture.TargetFiles[1].Received(1).Copy(Arg.Any<FilePath>(), true);
}

[Fact]
public void Should_Copy_Files()
{
Expand Down Expand Up @@ -401,6 +415,21 @@ public void Should_Throw_If_Any_File_Do_Not_Exist()
Assert.Equal("The file '/Working/file2.txt' does not exist.", result?.Message);
}

[Fact]
public void Should_Keep_Folder_Structure()
{
// Given
var fixture = new FileCopyFixture();
var filePaths = fixture.SourceFilePaths.Select(x => x.FullPath);

// When
FileAliases.CopyFiles(fixture.Context, filePaths, "./target");

// Then
fixture.TargetFiles[0].Received(1).Copy(Arg.Any<FilePath>(), true);
fixture.TargetFiles[1].Received(1).Copy(Arg.Any<FilePath>(), true);
}

[Fact]
public void Should_Copy_Files()
{
Expand Down Expand Up @@ -492,6 +521,20 @@ public void Should_Throw_If_Any_File_Do_Not_Exist()
Assert.Equal("The file '/Working/file2.txt' does not exist.", result?.Message);
}

[Fact]
public void Should_Keep_Folder_Structure()
{
// Given
var fixture = new FileCopyFixture();

// When
FileAliases.CopyFiles(fixture.Context, "*", "./target", true);

// Then
fixture.TargetFiles[0].Received(1).Copy(Arg.Any<FilePath>(), true);
fixture.TargetFiles[1].Received(1).Copy(Arg.Any<FilePath>(), true);
}

[Fact]
public void Should_Copy_Files()
{
Expand Down
2 changes: 1 addition & 1 deletion src/Cake.Common.Tests/project.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": "0.17.0-*",
"version": "0.16.2-*",
"buildOptions": {
"platform": "AnyCpu",
"additionalArguments": [
Expand Down
74 changes: 71 additions & 3 deletions src/Cake.Common/IO/FileAliases.cs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ public static void CopyFile(this ICakeContext context, FilePath filePath, FilePa
[CakeAliasCategory("Copy")]
public static void CopyFiles(this ICakeContext context, string pattern, DirectoryPath targetDirectoryPath)
{
FileCopier.CopyFiles(context, pattern, targetDirectoryPath);
FileCopier.CopyFiles(context, pattern, targetDirectoryPath, false);
}

/// <summary>
Expand All @@ -120,7 +120,7 @@ public static void CopyFiles(this ICakeContext context, string pattern, Director
[CakeAliasCategory("Copy")]
public static void CopyFiles(this ICakeContext context, IEnumerable<FilePath> filePaths, DirectoryPath targetDirectoryPath)
{
FileCopier.CopyFiles(context, filePaths, targetDirectoryPath);
FileCopier.CopyFiles(context, filePaths, targetDirectoryPath, false);
}

/// <summary>
Expand Down Expand Up @@ -148,7 +148,75 @@ public static void CopyFiles(this ICakeContext context, IEnumerable<string> file
throw new ArgumentNullException(nameof(filePaths));
}
var paths = filePaths.Select(p => new FilePath(p));
FileCopier.CopyFiles(context, paths, targetDirectoryPath);
FileCopier.CopyFiles(context, paths, targetDirectoryPath, false);
}

/// <summary>
/// Copies all files matching the provided pattern to a new location.
/// </summary>
/// <param name="context">The context.</param>
/// <param name="pattern">The pattern.</param>
/// <param name="targetDirectoryPath">The target directory path.</param>
/// <param name="preserveFolderStructure">Keep the folder structure.</param>
/// <example>
/// <code>
/// CopyFiles("Cake.*", "./publish");
/// </code>
/// </example>
[CakeMethodAlias]
[CakeAliasCategory("Copy")]
public static void CopyFiles(this ICakeContext context, string pattern, DirectoryPath targetDirectoryPath, bool preserveFolderStructure)
{
FileCopier.CopyFiles(context, pattern, targetDirectoryPath, preserveFolderStructure);
}

/// <summary>
/// Copies existing files to a new location.
/// </summary>
/// <param name="context">The context.</param>
/// <param name="filePaths">The file paths.</param>
/// <param name="targetDirectoryPath">The target directory path.</param>
/// <param name="preserveFolderStructure">Keep the folder structure.</param>
/// <example>
/// <code>
/// var files = GetFiles("./**/Cake.*");
/// CopyFiles(files, "destination");
/// </code>
/// </example>
[CakeMethodAlias]
[CakeAliasCategory("Copy")]
public static void CopyFiles(this ICakeContext context, IEnumerable<FilePath> filePaths, DirectoryPath targetDirectoryPath, bool preserveFolderStructure)
{
FileCopier.CopyFiles(context, filePaths, targetDirectoryPath, preserveFolderStructure);
}

/// <summary>
/// Copies existing files to a new location.
/// </summary>
/// <param name="context">The context.</param>
/// <param name="filePaths">The file paths.</param>
/// <param name="targetDirectoryPath">The target directory path.</param>
/// <param name="preserveFolderStructure">Keep the folder structure.</param>
/// <example>
/// <code>
/// CreateDirectory("destination");
/// var files = new [] {
/// "Cake.exe",
/// "Cake.pdb"
/// };
/// CopyFiles(files, "destination");
/// </code>
/// </example>
[CakeMethodAlias]
[CakeAliasCategory("Copy")]
public static void CopyFiles(this ICakeContext context, IEnumerable<string> filePaths, DirectoryPath targetDirectoryPath, bool preserveFolderStructure)
{
if (filePaths == null)
{
throw new ArgumentNullException(nameof(filePaths));
}
var paths = filePaths.Select(p => new FilePath(p));
FileCopier.CopyFiles(context, paths, targetDirectoryPath, preserveFolderStructure);
}

/// <summary>
Expand Down
86 changes: 70 additions & 16 deletions src/Cake.Common/IO/FileCopier.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using Cake.Core;
using Cake.Core.Diagnostics;
using Cake.Core.IO;
Expand Down Expand Up @@ -56,41 +57,42 @@ public static void CopyFile(ICakeContext context, FilePath filePath, FilePath ta
throw new DirectoryNotFoundException(message);
}

CopyFileCore(context, filePath, targetFilePath);
CopyFileCore(context, filePath, targetFilePath, null);
}

public static void CopyFiles(ICakeContext context, string pattern, DirectoryPath targetDirectoryPath)
public static void CopyFiles(ICakeContext context, string pattern, DirectoryPath targetDirectoryPath, bool preserverFolderStructure)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
throw new ArgumentNullException("context");
}
if (pattern == null)
{
throw new ArgumentNullException(nameof(pattern));
throw new ArgumentNullException("pattern");
}
var files = context.GetFiles(pattern);

if (files.Count == 0)
{
context.Log.Verbose("The provided pattern did not match any files.");
return;
}
CopyFiles(context, files, targetDirectoryPath);
CopyFiles(context, files, targetDirectoryPath, preserverFolderStructure);
}

public static void CopyFiles(ICakeContext context, IEnumerable<FilePath> filePaths, DirectoryPath targetDirectoryPath)
public static void CopyFiles(ICakeContext context, IEnumerable<FilePath> filePaths, DirectoryPath targetDirectoryPath, bool preserverFolderStructure)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
throw new ArgumentNullException("context");
}
if (filePaths == null)
{
throw new ArgumentNullException(nameof(filePaths));
throw new ArgumentNullException("filePaths");
}
if (targetDirectoryPath == null)
{
throw new ArgumentNullException(nameof(targetDirectoryPath));
throw new ArgumentNullException("targetDirectoryPath");
}

var absoluteTargetDirectoryPath = targetDirectoryPath.MakeAbsolute(context.Environment);
Expand All @@ -103,14 +105,47 @@ public static void CopyFiles(ICakeContext context, IEnumerable<FilePath> filePat
throw new DirectoryNotFoundException(message);
}

// Iterate all files and copy them.
foreach (var filePath in filePaths)
if (preserverFolderStructure)
{
var commonPath = string.Empty;
List<string> separatedPath = filePaths
.First(str => str.ToString().Length == filePaths.Max(st2 => st2.ToString().Length)).ToString()
.Split(new string[] { "/" }, StringSplitOptions.RemoveEmptyEntries)
.ToList();

foreach (string pathSegment in separatedPath)
{
if (commonPath.Length == 0 && filePaths.All(str => str.ToString().StartsWith(pathSegment)))
{
commonPath = pathSegment;
}
else if (filePaths.All(str => str.ToString().StartsWith(commonPath + "/" + pathSegment)))
{
commonPath += "/" + pathSegment;
}
else
{
break;
}
}

// Iterate all files and copy them.
foreach (var filePath in filePaths)
{
CopyFileCore(context, filePath, absoluteTargetDirectoryPath.GetFilePath(filePath), context.DirectoryExists(commonPath) ? commonPath : null);
}
}
else
{
CopyFileCore(context, filePath, absoluteTargetDirectoryPath.GetFilePath(filePath));
// Iterate all files and copy them.
foreach (var filePath in filePaths)
{
CopyFileCore(context, filePath, absoluteTargetDirectoryPath.GetFilePath(filePath), null);
}
}
}

private static void CopyFileCore(ICakeContext context, FilePath filePath, FilePath targetFilePath)
private static void CopyFileCore(ICakeContext context, FilePath filePath, FilePath targetFilePath, string commonPath)
{
var absoluteFilePath = filePath.MakeAbsolute(context.Environment);

Expand All @@ -124,9 +159,28 @@ private static void CopyFileCore(ICakeContext context, FilePath filePath, FilePa

// Copy the file.
var absoluteTargetPath = targetFilePath.MakeAbsolute(context.Environment);
context.Log.Verbose("Copying file {0} to {1}", absoluteFilePath.GetFilename(), absoluteTargetPath);
var file = context.FileSystem.GetFile(absoluteFilePath);
file.Copy(absoluteTargetPath, true);

if (!string.IsNullOrEmpty(commonPath))
{
// Get the parent folder structure and create it.
var newRelativeFolderPath = context.Directory(commonPath).Path.GetRelativePath(filePath.GetDirectory());
var newTargetPath = targetFilePath.GetDirectory().Combine(newRelativeFolderPath);
var newAbsoluteTargetPath = newTargetPath.CombineWithFilePath(filePath.GetFilename());
context.Log.Verbose("Copying file {0} to {1}", absoluteFilePath.GetFilename(), newAbsoluteTargetPath);

if (!context.DirectoryExists(newTargetPath))
{
context.CreateDirectory(newTargetPath);
}

file.Copy(newAbsoluteTargetPath, true);
}
else
{
context.Log.Verbose("Copying file {0} to {1}", absoluteFilePath.GetFilename(), absoluteTargetPath);
file.Copy(absoluteTargetPath, true);
}
}
}
}
}
2 changes: 1 addition & 1 deletion src/Cake.Common/project.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": "0.17.0-*",
"version": "0.16.2-*",
"description": "Provides aliases (extension methods on Cake context) that support CI, build, unit tests, zip, signing, etc. for Cake.",
"copyright": "Copyright (c) .NET Foundation and contributors",
"authors": [
Expand Down
2 changes: 1 addition & 1 deletion src/Cake.Core.Tests/project.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": "0.17.0-*",
"version": "0.16.2-*",
"dependencies": {
"dotnet-test-xunit": "2.2.0-preview2-build1029",
"Cake.Core": {
Expand Down
2 changes: 1 addition & 1 deletion src/Cake.Core/project.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": "0.17.0-*",
"version": "0.16.2-*",
"description": "The Cake core library.",
"copyright": "Copyright (c) .NET Foundation and contributors",
"authors": [
Expand Down
2 changes: 1 addition & 1 deletion src/Cake.NuGet.Tests/project.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": "0.17.0-*",
"version": "0.16.2-*",
"buildOptions": {
"platform": "AnyCpu",
"additionalArguments": [
Expand Down
2 changes: 1 addition & 1 deletion src/Cake.NuGet/project.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": "0.17.0-*",
"version": "0.16.2-*",
"dependencies": {
"Cake.Core": {
"target": "project"
Expand Down
2 changes: 1 addition & 1 deletion src/Cake.Testing.Xunit/project.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": "0.17.0-*",
"version": "0.16.2-*",
"configurations": {
"Release": {
"buildOptions": {
Expand Down
2 changes: 1 addition & 1 deletion src/Cake.Testing/project.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": "0.17.0-*",
"version": "0.16.2-*",
"description": "Contains testing utilities for Cake.",
"copyright": "Copyright (c) .NET Foundation and contributors",
"authors": [
Expand Down
2 changes: 1 addition & 1 deletion src/Cake.Tests/project.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": "0.17.0-*",
"version": "0.16.2-*",
"dependencies": {
"dotnet-test-xunit": "2.2.0-preview2-build1029",
"Cake": {
Expand Down
2 changes: 1 addition & 1 deletion src/Cake/project.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": "0.17.0-*",
"version": "0.16.2-*",
"buildOptions": {
"emitEntryPoint": true,
"xmlDoc": true,
Expand Down

0 comments on commit 8232e43

Please sign in to comment.