Da gibt es mehrere Möglichkeiten, dies implementieren könnte, ich bin meine eigene Frage mit den Ergebnissen der Beantwortung ich m jetzt dank den Antworten von Wcoenen und Rob.
Dies ist die benutzerdefinierte MSBuild-Aufgabe:
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;
}
}
paar Dinge zu beachten:
- Ich habe Kürze Dokumentation weggelassen.
- MSBuildHelper.Log ist nur ein einfacher Wrapper für ITask.BuildEngine.LogMessageEvent, um NullReferenceException laufende Unit-Tests abzufangen.
- Noch Raum für Verbesserungen, z.B. Verwenden von ITaskItem anstelle von String für Eigenschaften, Regex zum Vergleich.
- Die Vergleichslogik mag ein wenig komisch aussehen, aber die Dateitabelle macht funky Sachen mit Verzeichnispräfix, und ich wollte auch den Randfall vermeiden, wo eine Datei gelöscht und eine neue Datei hinzugefügt werden kann, also die Anzahl der Dateien richtig, aber die msi Inhalt falsch sind :)
Hier werden die entsprechenden Unit-Tests sind Voraussetzung ist, dass Sie Test.msi in Ihrem Testprojekt haben, die in das Ausgabeverzeichnis kopiert wird.
[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);
}
}
}
ich das nicht überstimmen werden, da es tatsächlich funktionieren kann, wenn WinRAR COM strukturierte Speicherdatei lesen kann (die eine MSI-Datei ist das, was), aber es ist definitiv nicht der Weg, um eine Dateianzahl zu nehmen, schauen bei Rob Menschings Antwort meiner Meinung nach. Wenn Sie nur die Dateien extrahieren möchten, können Sie eine Admin-Installation über eine Eingabeaufforderung ausführen: setup.exe/a für eine EXE-Datei oder msiexec/a YourMsiName.msi für eine MSI-Datei. –