#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 System.Text; using Microsoft.Win32; using NAnt.Core; using NAnt.Core.Attributes; using NAnt.Core.Types; namespace Nuclex.NAnt.Tasks { /// Invokes the 7-Zip file compression utility public static class SevenZip { #region class ErrorCapturer /// Captures the error message reported by 7-Zip, if any private class ErrorCapturer { /// Called when 7-Zip outputs data to the stderr stream /// Process that is outputting data /// Contains the data that was sent to stderr public void SevenZipErrorDataReceived( object sender, DataReceivedEventArgs arguments ) { processLine(arguments.Data); Debug.WriteLine("stderr: " + arguments.Data); } /// Called when 7-Zip outputs data to the stdout stream /// Process that is outputting data /// Contains the data that was sent to stdout public void SevenZipOutputDataReceived( object sender, DataReceivedEventArgs arguments ) { processLine(arguments.Data); Debug.WriteLine("stdout: " + arguments.Data); } /// The error message if an error has occured public string ErrorMessage { get { return this.errorMessage.ToString(); } } /// Whether an error has occured at all public bool ErrorOccured { get { return this.gotError; } } /// Processes a single line from 7-Zip's output /// Line the 7-Zip executable has printed private void processLine(string line) { if(string.IsNullOrEmpty(line)) { if(this.gotError) { this.errorComplete = true; } } else if(this.gotError) { if(!this.errorComplete) { if(this.errorMessage == null) { this.errorMessage = new StringBuilder(); this.errorMessage.AppendLine(); } this.errorMessage.AppendLine(line); } } else { int errorIndex = line.IndexOf( "error", StringComparison.InvariantCultureIgnoreCase ); if(errorIndex != -1) { this.gotError = true; } } } /// True if an error has occured private bool gotError; /// Whether the error message is complete private bool errorComplete; /// The suspected error message from 7-Zip private StringBuilder errorMessage; } #endregion // class ErrorCapturer /// Runs the 7-Zip executable /// Working directory in which to start 7-Zip /// Command line arguments to pass to 7-Zip public static void Run(string workingDirectory, string commandLine) { ErrorCapturer errorCapturer = new ErrorCapturer(); // Configure the startup options for the 7-Zip process Process sevenZip = new Process(); sevenZip.StartInfo.Arguments = commandLine; sevenZip.StartInfo.CreateNoWindow = true; sevenZip.StartInfo.FileName = Helpers.SevenZipLocator.Location; sevenZip.StartInfo.WorkingDirectory = workingDirectory; sevenZip.StartInfo.WindowStyle = ProcessWindowStyle.Hidden; sevenZip.StartInfo.RedirectStandardOutput = true; sevenZip.StartInfo.RedirectStandardError = true; sevenZip.StartInfo.UseShellExecute = false; sevenZip.OutputDataReceived += new DataReceivedEventHandler( errorCapturer.SevenZipOutputDataReceived ); sevenZip.ErrorDataReceived += new DataReceivedEventHandler( errorCapturer.SevenZipErrorDataReceived ); // Start the 7-Zip process and wait for it to end sevenZip.Start(); sevenZip.BeginOutputReadLine(); sevenZip.BeginErrorReadLine(); sevenZip.WaitForExit(); // Check if 7-Zip failed and throw an exception if it did int exitCode = sevenZip.ExitCode; if(exitCode != 0) { throw new InvalidOperationException(errorCapturer.ErrorMessage ?? "unknown error"); } } } } // namespace Nuclex.NAnt.Tasks