/// <summary> /// Returns the names of the files in a plugin package. /// </summary> /// <param name="packagePath"></param> /// <returns></returns> internal static List <string> FilesInPackage(string packagePath) { List <string> files = new List <string>(); string fileType = Path.GetExtension(packagePath); if (fileType == ".xml") { var pkg = PackageDef.FromXml(packagePath); return(pkg.Files.Select(f => f.FileName).ToList()); } try { using (var fileStream = File.OpenRead(packagePath)) using (var zip = new ZipArchive(fileStream, ZipArchiveMode.Read)) { foreach (var part in zip.Entries) { if (part.Name == "[Content_Types].xml" || part.Name == ".rels" || part.FullName.StartsWith("package/services/metadata/core-properties")) { continue; // skip strange extra files that are created by System.IO.Packaging.Package (TAP 7.x) } string path = Uri.UnescapeDataString(part.FullName); files.Add(path); } } } catch (InvalidDataException) { log.Error($"Could not unpackage '{packagePath}'."); throw; } return(files); }
/// <summary> /// Load the input as a PackageDef, saves it again and compares the saved output to the original input /// </summary> /// <param name="input"></param> private static void LoadSaveCompare(string input, string expectedOutput) { PackageDef pkg; byte[] inputArray = System.Text.Encoding.ASCII.GetBytes(input); using (MemoryStream inputStream = new MemoryStream(inputArray)) { pkg = PackageDef.FromXml(inputStream); } string output = ""; using (Stream str = new MemoryStream()) { pkg.SaveTo(str); using (StreamReader reader = new StreamReader(str)) { reader.BaseStream.Seek(0, 0); output = reader.ReadToEnd(); } } XDocument inputDoc = XDocument.Parse(expectedOutput); XDocument outputDoc = XDocument.Parse(output); AssertElementEquals(inputDoc.Root, outputDoc.Root); AssertElementEquals(outputDoc.Root, inputDoc.Root); }
public void CheckDependencies_AllDepsInstalled() { var xseries = PackageDef.FromXml(PackageDef.GetDefaultPackageMetadataPath("XSeries")); //var test2 = PackageDef.FromXmlFile(PackageDef.GetDefaultPackageMetadataPath("Test2")); File.Copy(PackageDef.GetDefaultPackageMetadataPath("CheckDependencies_AllDepsInstalled"), "CheckDependencies_AllDepsInstalled.xml", true); PackageDef.ValidateXml("CheckDependencies_AllDepsInstalled.xml"); var alldeps = PackageDef.FromXml("CheckDependencies_AllDepsInstalled.xml"); //var tree = DependencyAnalyzer.BuildAnalyzerContext(new List<PackageDef> { xseries, test2, alldeps }); //Assert.AreEqual(tree.BrokenPackages.Count, 1); //PackageDependencyExt.CheckDependencies(inputFilename); }
public void LoadPackageFile() { var packageString = Resources.GetEmbedded("ExamplePackage.xml"); PackageDef package; using (var str = new MemoryStream(Encoding.UTF8.GetBytes(packageString))) { package = PackageDef.FromXml(str); } Assert.AreEqual(package.Dependencies.Count, 1); Assert.AreEqual("Tap", package.Dependencies[0].Name); Assert.AreEqual(package.Files.Count, 2); Assert.IsNotNull(package.Description); }
public void CheckDependencies_MissingDep() { string inputFilename = "Packages/CheckDependencies_MissingDep/package.xml"; //PackageDependencyExt.CheckDependencies(inputFilename); var xseries = PackageDef.FromXml(PackageDef.GetDefaultPackageMetadataPath("XSeries")); PackageDef.ValidateXml(inputFilename); var missing = PackageDef.FromXml(inputFilename); var tree = DependencyAnalyzer.BuildAnalyzerContext(new List <PackageDef> { xseries, missing }); Assert.IsTrue(tree.GetIssues(missing).Any(issue => issue.IssueType == DependencyIssueType.Missing)); //Assert.Fail("CheckDependencies should have thrown an exception"); }
static PackageDef loadPackageDef(string file) { try { using (var f = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read)) return(PackageDef.FromXml(f)); } catch (Exception e) { log.Warning("Unable to read package file '{0}'. Moving it to '.broken'", file); log.Debug(e); var brokenfile = file + ".broken"; if (File.Exists(brokenfile)) { File.Delete(brokenfile); } File.Move(file, brokenfile); } return(null); }
public void SaveTo_Simple() { string inputFilename = "Packages/Package/package.xml"; // this package contains the old XML Schema URL string outputFileContent = ""; PackageDef pkg = PackageDef.FromXml(inputFilename); using (Stream str = new MemoryStream()) { pkg.SaveTo(str); using (StreamReader reader = new StreamReader(str)) { reader.BaseStream.Seek(0, 0); outputFileContent = reader.ReadToEnd(); } } string inputContent = File.ReadAllText(inputFilename); // check that the package now contains the new XML Schema URL StringAssert.Contains("xmlns=\"http://opentap.io/schemas/package\"", outputFileContent); }
/// <summary> /// Load from an XML package definition file. /// This file is not expected to have info about the plugins in it, so this method will enumerate the plugins inside each dll by loading them. /// </summary> /// <param name="xmlFilePath">The Package Definition xml file. Usually named package.xml</param> /// <param name="projectDir">Directory used byt GitVersionCalculator to expand any $(GitVersion) macros in the XML file.</param> /// <returns></returns> public static PackageDef FromInputXml(string xmlFilePath, string projectDir) { PackageDef.ValidateXml(xmlFilePath); var pkgDef = PackageDef.FromXml(xmlFilePath); if (pkgDef.Files.Any(f => f.HasCustomData <UseVersionData>() && f.HasCustomData <SetAssemblyInfoData>())) { throw new InvalidDataException("A file cannot specify <SetAssemblyInfo/> and <UseVersion/> at the same time."); } pkgDef.Files = expandGlobEntries(pkgDef.Files); var excludeAdd = pkgDef.Files.Where(file => file.IgnoredDependencies != null).SelectMany(file => file.IgnoredDependencies).Distinct().ToList(); List <Exception> exceptions = new List <Exception>(); foreach (PackageFile item in pkgDef.Files) { string fullPath = Path.GetFullPath(item.FileName); if (!File.Exists(fullPath)) { string fileName = Path.GetFileName(item.FileName); if (File.Exists(fileName) && item.SourcePath == null) { // this is to support building everything to the root folder. This way the developer does not have to specify SourcePath. log.Warning("Specified file '{0}' was not found, using file '{1}' as source instead. Consider setting SourcePath to remove this warning.", item.FileName, fileName); item.SourcePath = fileName; } else { exceptions.Add(new FileNotFoundException("Missing file for package.", fullPath)); } } } if (exceptions.Count > 0) { throw new AggregateException("Missing files", exceptions); } pkgDef.Date = DateTime.UtcNow; // Copy to output directory first foreach (var file in pkgDef.Files) { if (file.RelativeDestinationPath != file.FileName) { try { var destPath = Path.GetFullPath(file.RelativeDestinationPath); if (!File.Exists(destPath)) { Directory.CreateDirectory(Path.GetDirectoryName(destPath)); ProgramHelper.FileCopy(file.FileName, destPath); } } catch { // Catching here. The files might be used by themselves } } } var searcher = new PluginSearcher(PluginSearcher.Options.IncludeSameAssemblies); searcher.Search(Directory.GetCurrentDirectory()); List <AssemblyData> assemblies = searcher.Assemblies.ToList(); // Enumerate plugins if this has not already been done. if (!pkgDef.Files.SelectMany(pfd => pfd.Plugins).Any()) { EnumeratePlugins(pkgDef, assemblies); } log.Info("Updating package version."); pkgDef.updateVersion(projectDir); log.Info("Package version is {0}", pkgDef.Version); pkgDef.findDependencies(excludeAdd, assemblies); return(pkgDef); }
private void waitForPackageFilesFree(string tapDir, List <string> PackagePaths) { // ignore tap.exe as it is not meant to be overwritten. bool exclude(string filename) => filename.ToLower() == "tap" || filename.ToLower() == "tap.exe"; List <FileInfo> filesInUse = new List <FileInfo>(); foreach (string packageFileName in PackagePaths) { foreach (string file in PluginInstaller.FilesInPackage(packageFileName)) { string fullPath = Path.Combine(tapDir, file); string filename = Path.GetFileName(file); if (exclude(filename)) { continue; } if (IsFileLocked(new FileInfo(fullPath))) { filesInUse.Add(new FileInfo(fullPath)); } } } // Check if the files that are in use are used by any other package var packages = PackagePaths.Select(p => p.EndsWith("TapPackage") ? PackageDef.FromPackage(p) : PackageDef.FromXml(p)); var remainingInstalledPlugins = new Installation(tapDir).GetPackages().Where(i => packages.Any(p => p.Name == i.Name) == false); var filesToRemain = remainingInstalledPlugins.SelectMany(p => p.Files).Select(f => f.RelativeDestinationPath).Distinct(StringComparer.InvariantCultureIgnoreCase); filesInUse = filesInUse.Where(f => filesToRemain.Contains(f.Name, StringComparer.InvariantCultureIgnoreCase) == false).ToList(); if (filesInUse.Count > 0) { log.Info("Following files cannot be modified because they are in use:"); foreach (var file in filesInUse) { log.Info("- " + file.FullName); var loaded_asm = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(x => x.IsDynamic == false && x.Location == file.FullName); if (loaded_asm != null) { throw new InvalidOperationException($"The file '{file.FullName}' is being used by this process."); } } var allProcesses = Process.GetProcesses().Where(p => p.ProcessName.ToLowerInvariant().Contains("opentap") && p.ProcessName.ToLowerInvariant().Contains("vshost") == false && p.ProcessName != Assembly.GetExecutingAssembly().GetName().Name).ToArray(); if (allProcesses.Any()) { // The file could be locked by someone other than OpenTAP processes. We should not assume it's OpenTAP holding the file. log.Warning(Environment.NewLine + "To continue, try closing applications that could be using the files."); foreach (var process in allProcesses) { log.Warning("- " + process.ProcessName); } } log.Warning(Environment.NewLine + "Waiting for files to become unlocked..."); while (isPackageFilesInUse(tapDir, PackagePaths, exclude)) { if (cancellationToken.IsCancellationRequested) { return; } if (!isTapRunning()) { OnError(new IOException("One or more plugin files are in use. View log for more information.")); } Thread.Sleep(300); } } }
internal bool RunCommand(string command, bool force, bool modifiesPackageFiles) { var verb = System.Globalization.CultureInfo.CurrentCulture.TextInfo.ToTitleCase(command.ToLower()) + "ed"; try { if (modifiesPackageFiles) { waitForPackageFilesFree(TapDir, PackagePaths); } if (cancellationToken.IsCancellationRequested) { log.Debug("Received abort while waiting for package files to be unlocked."); return(false); } double progressPercent = 10; OnProgressUpdate((int)progressPercent, ""); PluginInstaller pi = new PluginInstaller(); foreach (string fileName in PackagePaths) { PackageDef pkg = PackageDef.FromXml(fileName); OnProgressUpdate((int)progressPercent, string.Format("Running command '{0}' on '{1}'", command, pkg.Name)); Stopwatch timer = Stopwatch.StartNew(); var res = pi.ExecuteAction(pkg, command, force, TapDir); if (res == ActionResult.Error) { OnProgressUpdate(100, "Done"); return(false); } else if (res == ActionResult.NothingToDo) { log.Info(string.Format("Tried to {0} {1}, but there was nothing to do.", command, pkg.Name)); } else { log.Info(timer, string.Format("{1} {0} version {2}.", pkg.Name, verb, pkg.Version)); } progressPercent += (double)80 / PackagePaths.Count(); } OnProgressUpdate(90, ""); if (DoSleep) { Thread.Sleep(100); } OnProgressUpdate(100, "Done"); Thread.Sleep(50); // Let Eventhandler get the last OnProgressUpdate } catch (Exception ex) { OnError(ex); return(false); } new Installation(TapDir).AnnouncePackageChange(); return(true); }