Puesto que hay múltiples maneras en que podría poner en práctica esto, estoy respondiendo a mi propia pregunta con los resultados que' Ahora estoy usando gracias a las respuestas de wcoenen y Rob.
Esta es la costumbre tarea MSBuild:
public class VerifyMsiFileCount : Task
{
[Required]
public string MsiFile { get; set; }
[Required]
public string Directory { get; set; }
public override bool Execute()
{
Database database = new Database(MsiFile, DatabaseOpenMode.ReadOnly);
IList msiFiles = database.ExecuteQuery("SELECT FileName FROM File", new Record(0));
IList<string> files = new List<string>(
System.IO.Directory.GetFiles(Directory, "*", SearchOption.AllDirectories));
return compareContents(msiFiles, files);
}
bool compareContents(IList msiFiles, IList<string> files)
{
// Always false if count mismatch, but helpful to know which file(s) are missing
bool result = msiFiles.Count == files.Count;
StringBuilder sb = new StringBuilder(msiFiles.Count);
foreach (string msiFile in msiFiles)
{
sb.AppendLine(msiFile.ToUpper());
}
string allMsiFiles = sb.ToString();
// Could be optimized using regex - each non-matched line in allMsiFiles
string filename;
foreach (string file in files)
{
filename = file.ToUpper();
// Strip directory as File table in MSI does funky things with directory prefixing
if (filename.Contains(Path.DirectorySeparatorChar.ToString()))
{
filename = filename.Substring(file.LastIndexOf(Path.DirectorySeparatorChar) + 1);
}
if (!allMsiFiles.Contains(filename))
{
result = false;
MSBuildHelper.Log(this, file + " appears to be missing from MSI File table",
MessageImportance.High);
}
}
return result;
}
}
Un par de cosas a tener en cuenta:
- He dejado de lado la documentación por razones de brevedad.
- MSBuildHelper.Log es simplemente un contenedor simple para ITask.BuildEngine.LogMessageEvent para capturar pruebas de unidad de funcionamiento NullReferenceException.
- Todavía se puede mejorar, como p. utilizando ITaskItem en lugar de cadena para propiedades, expresiones regulares para comparación.
- La lógica de comparación puede parecer un poco extraña, pero la tabla de archivos hace algunas cosas funky con el prefijo de directorio, y también quería evitar el caso límite donde se puede eliminar un archivo y agregar un nuevo archivo, por lo que el conteo de archivos contenidos correctos pero el msi están equivocados :)
Estas son las pruebas unitarias correspondientes, suposición es que tienes Test.msi en su proyecto de prueba que se copia en el directorio de salida.
[TestFixture]
public class VerifyMsiFileCountFixture
{
VerifyMsiFileCount verify;
[SetUp]
public void Setup()
{
verify = new VerifyMsiFileCount();
}
[Test]
[ExpectedException(typeof(InstallerException))]
public void Execute_ThrowsInstallerException_InvalidMsiFilePath()
{
verify.Directory = Environment.CurrentDirectory;
verify.MsiFile = "Bogus";
verify.Execute();
}
[Test]
[ExpectedException(typeof(DirectoryNotFoundException))]
public void Execute_ThrowsDirectoryNotFoundException_InvalidDirectoryPath()
{
verify.Directory = "Bogus";
verify.MsiFile = "Test.msi";
verify.Execute();
}
[Test]
public void Execute_ReturnsTrue_ValidDirectoryAndFile()
{
string directory = Path.Combine(Environment.CurrentDirectory, "Temp");
string file = Path.Combine(directory, "Test.txt");
Directory.CreateDirectory(directory);
File.WriteAllText(file, "Temp");
try
{
verify.Directory = directory;
verify.MsiFile = "Test.msi";
Assert.IsTrue(verify.Execute());
}
finally
{
File.Delete(file);
Directory.Delete(directory);
}
}
[Test]
public void Execute_ReturnsFalse_NoFileDefined()
{
string directory = Path.Combine(Environment.CurrentDirectory, "Temp");
Directory.CreateDirectory(directory);
try
{
verify.Directory = directory;
verify.MsiFile = "Test.msi";
Assert.IsFalse(verify.Execute());
}
finally
{
Directory.Delete(directory);
}
}
[Test]
public void Execute_ReturnsFalse_IncorrectFilename()
{
string directory = Path.Combine(Environment.CurrentDirectory, "Temp");
string file = Path.Combine(directory, "Bogus.txt");
Directory.CreateDirectory(directory);
File.WriteAllText(file, "Temp");
try
{
verify.Directory = directory;
verify.MsiFile = "Test.msi";
Assert.IsFalse(verify.Execute());
}
finally
{
File.Delete(file);
Directory.Delete(directory);
}
}
[Test]
public void Execute_ReturnsFalse_ExtraFileDefined()
{
string directory = Path.Combine(Environment.CurrentDirectory, "Temp");
string file1 = Path.Combine(directory, "Test.txt");
string file2 = Path.Combine(directory, "Bogus.txt");
Directory.CreateDirectory(directory);
File.WriteAllText(file1, "Temp");
File.WriteAllText(file2, "Temp");
try
{
verify.Directory = directory;
verify.MsiFile = "Test.msi";
Assert.IsFalse(verify.Execute());
}
finally
{
File.Delete(file1);
File.Delete(file2);
Directory.Delete(directory);
}
}
}
no votaré esto abajo, ya que en realidad podría funcionar si WinRAR puede leer el archivo de almacenamiento estructurado COM (que es lo que es un archivo MSI), pero definitivamente no es la manera de tomar un número de archivos, mira en la respuesta de Rob Mensching en mi opinión. Si todo lo que desea es extraer los archivos, puede hacer una instalación administrativa desde un símbolo del sistema: setup.exe/a para un archivo exe, o msiexec/a YourMsiName.msi para un archivo MSI. –