Skip to content

Commit

Permalink
Adds folder structure overload for CopyFiles alias
Browse files Browse the repository at this point in the history
* fixes # 899
  • Loading branch information
martinscholz83 authored and devlead committed Oct 27, 2016
1 parent 0fbf9d9 commit 12fd0ed
Show file tree
Hide file tree
Showing 3 changed files with 184 additions and 19 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
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);
}
}
}
}
}

0 comments on commit 12fd0ed

Please sign in to comment.