Resume
In MSBuild, to copy a part of subtree, resembling directory structure, you have to write small and simple task.
The problem
I have a directory with files and subdirectories which I want to copy to another location as a part of build process. I do not need all files though. I want to specify necessary subdirectories, file masks and also some excludes.
In NAnt i could easily do it like this:
I turned this script to MSBuild analogue, using Items and Copy task.
As you see it looks much more complicated. And, alas, it doesn't work as expected. The directory structure is not copied. All files from subtree are placed right into the "private" directory.
Google said...
Search gave virtually nothing:
The solution
I didn't want to write my own copying code. Yes, it's simple, but with good testing it anyway would take me a lot of time. So I decided to tweak standard Copy task a bit:
- Create our class, inherited from Microsoft.Build.Tasks.Copy.
- Make a property SourceRoot, which will specify a root directory of source files. As you see, there is no "basedir" attribute in MSBuild.
- Overwrite Execute method:
- It scan SourceFiles collection,
- Strips SourceRoot from the beginning of paths,
- Combine with DestinationFolder path,
- Write into the DestinationFiles collection,
- At the end - call base.Execute.
Surprisingly, it's working. Here is the source code:
using System.IO;
using Microsoft.Build.Framework;
using Microsoft.Build.Tasks;
using Microsoft.Build.Utilities;
namespace sdf.Tasks
{
public class CopySubtree : Copy
{
private ITaskItem _sourceRoot;
public override bool Execute()
{
if( DestinationFiles != null )
{
Log.LogError( "DestinationFiles must not be specified." );
return false;
}
if( DestinationFolder == null )
{
Log.LogError( "DestinationFolder must be specified." );
return false;
}
if( SourceFiles.Length > 0 )
{
DestinationFiles = new ITaskItem[SourceFiles.Length];
string srcRoot = _sourceRoot.GetMetadata( "FullPath" );
for( int i = 0; i < SourceFiles.Length; i++ )
{
ITaskItem srcFile = SourceFiles[i];
string srcPath = srcFile.GetMetadata( "FullPath" );
if( srcPath.StartsWith( srcRoot ) )
{
srcPath = srcPath.Substring( srcRoot.Length + 1 );
srcPath = Path.Combine( DestinationFolder.ItemSpec,
srcPath );
}
DestinationFiles[i] = new TaskItem( srcPath );
srcFile.CopyMetadataTo( DestinationFiles[i] );
}
DestinationFolder = null;
}
return base.Execute();
}
public ITaskItem SourceRoot
{
get { return _sourceRoot; }
set { _sourceRoot = value; }
}
}
}
And fragment of a build file:
...
Posted
мар 02 2006, 06:07
by
Andrew Mayorov