#region CPL License
/*
Nuclex.NAnt.Tasks
Copyright (C) 2009 Nuclex Development Labs
This library is free software; you can redistribute it and/or
modify it under the terms of the IBM Common Public License as
published by the IBM Corporation; either version 1.0 of the
License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
IBM Common Public License for more details.
You should have received a copy of the IBM Common Public
License along with this library
*/
#endregion
using System;
using System.Collections.Generic;
using System.IO;
using System.Diagnostics;
using Microsoft.Win32;
using NAnt.Core;
using NAnt.Core.Attributes;
using NAnt.Core.Types;
namespace Nuclex.NAnt.Tasks {
/// Task for compressing files into a 7-Zip archive
[TaskName("sevenzip-compress")]
public class SevenZipCompressTask : Task {
/// Initializes a new 7-Zip task
public SevenZipCompressTask() {
this.fileSets = new FileSetCollection();
this.compressionLevel = 5;
}
/// Archive to create or to extract files from
[TaskAttribute("archive", Required = true), StringValidator(AllowEmpty = false)]
public FileInfo Archive {
get { return this.archive; }
set { this.archive = value; }
}
/// Password with which to protect the archive
[TaskAttribute("password", Required = false), StringValidator(AllowEmpty = false)]
public string Password {
get { return this.password; }
set { this.password = value; }
}
/// Files that will be compressed
[BuildElementArray("fileset")]
public FileSetCollection FileSets {
get { return this.fileSets; }
set { this.fileSets = value; }
}
///
/// Desired level of compression. Possible values are 0 (STORE only)
/// to 9 (highest). The default is 5
///
[TaskAttribute("level"), Int32Validator(0, 9)]
public int CompressionLevel {
get { return this.compressionLevel; }
set { this.compressionLevel = value; }
}
/// Executes the task
protected override void ExecuteTask() {
this.Log(
Level.Info,
"Compressing {0} files to '{1}'.",
this.fileSets.FileCount,
this.archive.FullName
);
// This will currently fail if more than one fileset is specified because
// 7-Zip does not support updating archives yet. Hopefully this will be
// fixed in a future version.
for(int fileSetIndex = 0; fileSetIndex < this.fileSets.Count; ++fileSetIndex) {
FileSet fileSet = this.fileSets[fileSetIndex];
string fileList = createListOfFilesToCompress(fileSet);
try {
string commandLine = string.Format(
"a -mx{0} -y \"{1}\" @\"{2}\"",
this.compressionLevel.ToString(),
this.archive,
fileList
);
if(!string.IsNullOrEmpty(this.password)) {
commandLine += " -p\"" + this.password + "\"";
}
SevenZip.Run(fileSet.BaseDirectory.FullName, commandLine);
}
catch(InvalidOperationException exception) {
throw new BuildException(
"Error during 7-Zip compression operation: " + exception.Message,
this.Location
);
}
finally {
//Console.WriteLine(fileList);
File.Delete(fileList);
}
}
}
/// Creates a list of the files that need to be compressed
///
/// File set whose file names will be written into a temporary text file
///
/// The path to a temporary text file containing the list of files
///
/// The caller is responsible for deleting the returned file again when it
/// is no longer needed.
///
private string createListOfFilesToCompress(FileSet fileSet) {
// This generates a temporary filename and writes an actual empty file to
// disk which ensures that noone else can get a temp file with this name.
string tempFile = Path.GetTempFileName();
// Make sure the temporary file is deleted again if anything goes wrong
try {
using(
FileStream tempFileStream = new FileStream(
tempFile, FileMode.Truncate, FileAccess.Write, FileShare.None
)
) {
StreamWriter writer = new StreamWriter(tempFileStream);
// Write the relative paths of all files in the file set into our
// temporary text file
for(int fileIndex = 0; fileIndex < fileSet.FileNames.Count; ++fileIndex) {
writer.WriteLine(
PathHelper.MakeRelative(
fileSet.BaseDirectory.FullName, fileSet.FileNames[fileIndex]
)
);
}
writer.Flush();
}
}
catch(Exception) {
File.Delete(tempFile);
throw;
}
// Nothing went wrong, leave the temporary file in place and return its path
return tempFile;
}
/// Archive to create or to extract files from
private FileInfo archive;
/// Desired compression level
private int compressionLevel;
/// Files that will be compressed
private FileSetCollection fileSets;
/// Password the archive will be protected with
private string password;
}
} // namespace Nuclex.NAnt.Tasks