#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