#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