public void TestApplyRecipeArchive() { using var archiveFile = new TemporaryFile("0install-unit-tests"); typeof(ArchiveExtractorTest).CopyEmbeddedToFile("testArchive.zip", archiveFile); var downloadedFiles = new[] { archiveFile }; var recipe = new Recipe { Steps = { new Archive { MimeType = Archive.MimeTypeZip, Destination = "dest" } } }; using var recipeDir = recipe.Apply(downloadedFiles, new SilentTaskHandler()); new TestRoot { new TestDirectory("dest") { new TestSymlink("symlink", "subdir1/regular"), new TestDirectory("subdir1") { new TestFile("regular") { LastWrite = new DateTime(2000, 1, 1, 12, 0, 0, DateTimeKind.Utc) } }, new TestDirectory("subdir2") { new TestFile("executable") { IsExecutable = true, LastWrite = new DateTime(2000, 1, 1, 12, 0, 0, DateTimeKind.Utc) } } } }.Verify(recipeDir); }
public static TemporaryDirectory DownloadAndApply([NotNull] this Recipe recipe, [NotNull] ITaskHandler handler, [CanBeNull] ICommandExecutor executor = null) { #region Sanity checks if (recipe == null) { throw new ArgumentNullException("recipe"); } if (handler == null) { throw new ArgumentNullException("handler"); } #endregion var downloadedFiles = new List <TemporaryFile>(); try { foreach (var step in recipe.Steps.OfType <DownloadRetrievalMethod>()) { downloadedFiles.Add(step.Download(handler, executor)); } // Apply the recipe return(recipe.Apply(downloadedFiles, handler)); } finally { // Clean up temporary archive files foreach (var downloadedFile in downloadedFiles) { downloadedFile.Dispose(); } } }
public void TestApplyRecipeSingleFile() { using (var singleFile = new TemporaryFile("0install-unit-tests")) using (var archiveFile = new TemporaryFile("0install-unit-tests")) { File.WriteAllText(singleFile, "data"); typeof(ArchiveExtractorTest).CopyEmbeddedToFile("testArchive.zip", archiveFile); var downloadedFiles = new[] { archiveFile, singleFile }; var recipe = new Recipe { Steps = { new Archive { MimeType = Archive.MimeTypeZip }, new SingleFile{ Destination = "subdir2/executable" } } }; using (TemporaryDirectory recipeDir = recipe.Apply(downloadedFiles, new SilentTaskHandler())) { // /subdir2/executable [!X] string path = Path.Combine(recipeDir, "subdir2", "executable"); File.Exists(path).Should().BeTrue(because: "File should exist: " + path); File.ReadAllText(path).Should().Be("data"); File.GetLastWriteTimeUtc(path).ToUnixTime() .Should().Be(0, because: "Single files should be set to Unix epoch"); if (!UnixUtils.IsUnix) { FlagUtils.GetFiles(FlagUtils.XbitFile, recipeDir).Should().BeEmpty(); } } } }
public void TestApplyRecipeArchiv() { using (var archiveFile = new TemporaryFile("0install-unit-tests")) { typeof(ExtractorTest).WriteEmbeddedFile("testArchive.zip", archiveFile); var downloadedFiles = new[] { archiveFile }; var recipe = new Recipe { Steps = { new Archive { MimeType = Archive.MimeTypeZip, Destination = "subDir" } } }; using (TemporaryDirectory recipeDir = recipe.Apply(downloadedFiles, new SilentTaskHandler())) { // /dest/symlink [S] string path = new[] { recipeDir, "subDir", "symlink" }.Aggregate(Path.Combine); Assert.IsTrue(File.Exists(path), "File should exist: " + path); if (!UnixUtils.IsUnix) { CollectionAssert.AreEquivalent(new[] { path }, FlagUtils.GetFiles(FlagUtils.SymlinkFile, recipeDir)); } // /dest/subdir2/executable [deleted] path = new[] { recipeDir, "subDir", "subdir2", "executable" }.Aggregate(Path.Combine); Assert.IsTrue(File.Exists(path), "File should exist: " + path); if (!UnixUtils.IsUnix) { CollectionAssert.AreEquivalent(new[] { path }, FlagUtils.GetFiles(FlagUtils.XbitFile, recipeDir)); } } } }
public void TestApplyRecipeSingleFileOverwrite() { using var singleFile = new TemporaryFile("0install-unit-tests"); using var archiveFile = new TemporaryFile("0install-unit-tests"); File.WriteAllText(singleFile, TestFile.DefaultContents); typeof(ArchiveExtractorTest).CopyEmbeddedToFile("testArchive.zip", archiveFile); var downloadedFiles = new[] { archiveFile, singleFile }; var recipe = new Recipe { Steps = { new Archive { MimeType = Archive.MimeTypeZip }, new SingleFile{ Destination = "subdir2/executable" } } }; using var recipeDir = recipe.Apply(downloadedFiles, new SilentTaskHandler()); new TestRoot { new TestDirectory("subdir2") { new TestFile("executable") { IsExecutable = false, // Executable file was overwritten by a non-executable one LastWrite = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc) } } }.Verify(recipeDir); }
private void ApplyRecipe() { if (Recipe == null && !string.IsNullOrEmpty(RecipeName)) { Recipe = ClassCatalog.GetInstance <IRecipe>(RecipeName, true); if (Recipe == null) { throw new Exception($"The recipe \"{RecipeName}\" could not be found"); } } if (Recipe != null) { _engine.Namespaces.Add(Recipe.GetType().Namespace); // Add the recipe namespace so it's available to modules Recipe.Apply(_engine); } }
public void TestApplyRecipeSingleFileExecutable() { using var singleFile = new TemporaryFile("0install-unit-tests"); File.WriteAllText(singleFile, TestFile.DefaultContents); var recipe = new Recipe { Steps = { new SingleFile { Destination = "executable", Executable = true } } }; using var recipeDir = recipe.Apply(new[] { singleFile }, new SilentTaskHandler()); new TestRoot { new TestFile("executable") { IsExecutable = true, LastWrite = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc) } }.Verify(recipeDir); }
public void TestApplyRecipeRemove() { using (var archiveFile = new TemporaryFile("0install-unit-tests")) { typeof(ArchiveExtractorTest).CopyEmbeddedToFile("testArchive.zip", archiveFile); var downloadedFiles = new[] { archiveFile }; var recipe = new Recipe { Steps = { new Archive { MimeType = Archive.MimeTypeZip }, new RemoveStep { Path = "symlink" }, new RemoveStep { Path = "subdir2" } } }; using (TemporaryDirectory recipeDir = recipe.Apply(downloadedFiles, new SilentTaskHandler())) { if (!UnixUtils.IsUnix) { FlagUtils.GetFiles(FlagUtils.XbitFile, recipeDir).Should().BeEmpty(); FlagUtils.GetFiles(FlagUtils.SymlinkFile, recipeDir).Should().BeEmpty(); } // /symlink [deleted] string path = Path.Combine(recipeDir, "symlink"); File.Exists(path).Should().BeFalse(because: "File should not exist: " + path); // /subdir2 [deleted] path = Path.Combine(recipeDir, "subdir2"); Directory.Exists(path).Should().BeFalse(because: "Directory should not exist: " + path); } } }
public void TestApplyRecipeArchiv() { using (var archiveFile = new TemporaryFile("0install-unit-tests")) { typeof(ExtractorTest).GetEmbedded("testArchive.zip").CopyToFile(archiveFile); var downloadedFiles = new[] {archiveFile}; var recipe = new Recipe {Steps = {new Archive {MimeType = Archive.MimeTypeZip, Destination = "subDir"}}}; using (TemporaryDirectory recipeDir = recipe.Apply(downloadedFiles, new SilentTaskHandler())) { // /dest/symlink [S] string path = new[] {recipeDir, "subDir", "symlink"}.Aggregate(Path.Combine); Assert.IsTrue(File.Exists(path), "File should exist: " + path); if (!UnixUtils.IsUnix) CollectionAssert.AreEquivalent(new[] {path}, FlagUtils.GetFiles(FlagUtils.SymlinkFile, recipeDir)); // /dest/subdir2/executable [deleted] path = new[] {recipeDir, "subDir", "subdir2", "executable"}.Aggregate(Path.Combine); Assert.IsTrue(File.Exists(path), "File should exist: " + path); if (!UnixUtils.IsUnix) CollectionAssert.AreEquivalent(new[] {path}, FlagUtils.GetFiles(FlagUtils.XbitFile, recipeDir)); } } }
public void TestApplyRecipeSingleFile() { using (var singleFile = new TemporaryFile("0install-unit-tests")) using (var archiveFile = new TemporaryFile("0install-unit-tests")) { File.WriteAllText(singleFile, "data"); typeof(ArchiveExtractorTest).CopyEmbeddedToFile("testArchive.zip", archiveFile); var downloadedFiles = new[] {archiveFile, singleFile}; var recipe = new Recipe {Steps = {new Archive {MimeType = Archive.MimeTypeZip}, new SingleFile {Destination = "subdir2/executable"}}}; using (TemporaryDirectory recipeDir = recipe.Apply(downloadedFiles, new SilentTaskHandler())) { // /subdir2/executable [!X] string path = Path.Combine(recipeDir, "subdir2", "executable"); File.Exists(path).Should().BeTrue(because: "File should exist: " + path); File.ReadAllText(path).Should().Be("data"); File.GetLastWriteTimeUtc(path).ToUnixTime() .Should().Be(0, because: "Single files should be set to Unix epoch"); if (!UnixUtils.IsUnix) FlagUtils.GetFiles(FlagUtils.XbitFile, recipeDir).Should().BeEmpty(); } } }
public void TestApplyRecipeArchiv() { using (var archiveFile = new TemporaryFile("0install-unit-tests")) { typeof(ArchiveExtractorTest).CopyEmbeddedToFile("testArchive.zip", archiveFile); var downloadedFiles = new[] { archiveFile }; var recipe = new Recipe { Steps = { new Archive { MimeType = Archive.MimeTypeZip, Destination = "subDir" } } }; using (TemporaryDirectory recipeDir = recipe.Apply(downloadedFiles, new SilentTaskHandler())) { // /dest/symlink [S] string path = Path.Combine(recipeDir, "subDir", "symlink"); File.Exists(path).Should().BeTrue(because: "File should exist: " + path); if (UnixUtils.IsUnix) { FileUtils.IsSymlink(path).Should().BeTrue(); } else { CygwinUtils.IsSymlink(path).Should().BeTrue(); } // /dest/subdir2/executable [deleted] path = Path.Combine(recipeDir, "subDir", "subdir2", "executable"); File.Exists(path).Should().BeTrue(because: "File should exist: " + path); if (!UnixUtils.IsUnix) { FlagUtils.GetFiles(FlagUtils.XbitFile, recipeDir).Should().BeEquivalentTo(path); } } } }
public void TestApplyRecipeRemove() { using var archiveFile = new TemporaryFile("0install-unit-tests"); typeof(ArchiveExtractorTest).CopyEmbeddedToFile("testArchive.zip", archiveFile); var downloadedFiles = new[] { archiveFile }; var recipe = new Recipe { Steps = { new Archive { MimeType = Archive.MimeTypeZip }, new RemoveStep { Path = "symlink" }, new RemoveStep { Path = "subdir2" } } }; using var recipeDir = recipe.Apply(downloadedFiles, new SilentTaskHandler()); new TestRoot { new TestDeletedFile("symlink"), new TestDirectory("subdir1") { new TestFile("regular") { LastWrite = new DateTime(2000, 1, 1, 12, 0, 0, DateTimeKind.Utc) } }, new TestDeletedDirectory("subdir2") }.Verify(recipeDir); }
public void TestApplyRecipeArchiv() { using (var archiveFile = new TemporaryFile("0install-unit-tests")) { typeof(ArchiveExtractorTest).CopyEmbeddedToFile("testArchive.zip", archiveFile); var downloadedFiles = new[] {archiveFile}; var recipe = new Recipe {Steps = {new Archive {MimeType = Archive.MimeTypeZip, Destination = "subDir"}}}; using (TemporaryDirectory recipeDir = recipe.Apply(downloadedFiles, new SilentTaskHandler())) { // /dest/symlink [S] string path = Path.Combine(recipeDir, "subDir", "symlink"); File.Exists(path).Should().BeTrue(because: "File should exist: " + path); if (UnixUtils.IsUnix) FileUtils.IsSymlink(path).Should().BeTrue(); else CygwinUtils.IsSymlink(path).Should().BeTrue(); // /dest/subdir2/executable [deleted] path = Path.Combine(recipeDir, "subDir", "subdir2", "executable"); File.Exists(path).Should().BeTrue(because: "File should exist: " + path); if (!UnixUtils.IsUnix) FlagUtils.GetFiles(FlagUtils.XbitFile, recipeDir).Should().BeEquivalentTo(path); } } }
public void TestApplyRecipeSingleFile() { using (var singleFile = new TemporaryFile("0install-unit-tests")) using (var archiveFile = new TemporaryFile("0install-unit-tests")) { File.WriteAllText(singleFile, "data"); typeof(ExtractorTest).GetEmbedded("testArchive.zip").CopyToFile(archiveFile); var downloadedFiles = new[] {archiveFile, singleFile}; var recipe = new Recipe {Steps = {new Archive {MimeType = Archive.MimeTypeZip}, new SingleFile {Destination = "subdir2/executable"}}}; using (TemporaryDirectory recipeDir = recipe.Apply(downloadedFiles, new SilentTaskHandler())) { // /subdir2/executable [!X] string path = new[] {recipeDir, "subdir2", "executable"}.Aggregate(Path.Combine); Assert.IsTrue(File.Exists(path), "File should exist: " + path); Assert.AreEqual("data", File.ReadAllText(path)); Assert.AreEqual(0, File.GetLastWriteTimeUtc(path).ToUnixTime(), "Single files should be set to Unix epoch"); if (!UnixUtils.IsUnix) Assert.IsEmpty(FlagUtils.GetFiles(FlagUtils.XbitFile, recipeDir)); } } }
public void TestApplyRecipeRename() { using (var archiveFile = new TemporaryFile("0install-unit-tests")) { typeof(ExtractorTest).GetEmbedded("testArchive.zip").CopyToFile(archiveFile); var downloadedFiles = new[] {archiveFile}; var recipe = new Recipe { Steps = { new Archive {MimeType = Archive.MimeTypeZip}, new RenameStep {Source = "symlink", Destination = "subdir3/symlink2"}, new RenameStep {Source = "subdir2/executable", Destination = "subdir2/executable2"} } }; using (TemporaryDirectory recipeDir = recipe.Apply(downloadedFiles, new SilentTaskHandler())) { if (!UnixUtils.IsUnix) { CollectionAssert.AreEquivalent( new[] {new[] {recipeDir, "subdir2", "executable2"}.Aggregate(Path.Combine)}, FlagUtils.GetFiles(FlagUtils.XbitFile, recipeDir)); CollectionAssert.AreEquivalent( new[] {new[] {recipeDir, "subdir3", "symlink2"}.Aggregate(Path.Combine)}, FlagUtils.GetFiles(FlagUtils.SymlinkFile, recipeDir)); } // /symlink [deleted] string path = Path.Combine(recipeDir, "symlink"); Assert.IsFalse(File.Exists(path), "File should not exist: " + path); // /subdir3/symlink2 [S] path = new[] {recipeDir, "subdir3", "symlink2"}.Aggregate(Path.Combine); Assert.IsTrue(File.Exists(path), "Missing file: " + path); if (UnixUtils.IsUnix) Assert.IsTrue(FileUtils.IsSymlink(path), "Not symlink: " + path); // /subdir2/executable [deleted] path = new[] {recipeDir, "subdir2", "executable"}.Aggregate(Path.Combine); Assert.IsFalse(File.Exists(path), "File should not exist: " + path); // /subdir2/executable2 [X] path = new[] {recipeDir, "subdir2", "executable2"}.Aggregate(Path.Combine); Assert.IsTrue(File.Exists(path), "Missing file: " + path); if (UnixUtils.IsUnix) Assert.IsTrue(FileUtils.IsExecutable(path), "Not executable: " + path); } } }
/// <summary> /// Applies a <see cref="Recipe"/> and sends the result to the <see cref="_implementationStore"/>. /// </summary> /// <param name="recipe">The recipe to apply.</param> /// <param name="files">The files downloaded for the <paramref name="recipe"/> steps, order matching the <see cref="DownloadRetrievalMethod"/> steps in <see cref="Recipe.Steps"/>.</param> /// <param name="manifestDigest">The digest the result of the recipe should produce.</param> /// <exception cref="OperationCanceledException">An IO task was canceled from another thread.</exception> /// <exception cref="NotSupportedException">A file format, protocol, etc. is unknown or not supported.</exception> /// <exception cref="IOException">A downloaded file could not be written to the disk or extracted.</exception> /// <exception cref="ImplementationAlreadyInStoreException">There is already an <see cref="Implementation"/> with the specified <paramref name="manifestDigest"/> in the store.</exception> /// <exception cref="UnauthorizedAccessException">Write access to <see cref="IImplementationStore"/> is not permitted.</exception> /// <exception cref="DigestMismatchException">An <see cref="Implementation"/>'s <see cref="Archive"/>s don't match the associated <see cref="ManifestDigest"/>.</exception> private void ApplyRecipe(Recipe recipe, IEnumerable <TemporaryFile> files, ManifestDigest manifestDigest) { using var recipeDir = recipe.Apply(files, Handler, manifestDigest); _implementationStore.AddDirectory(recipeDir, manifestDigest, Handler); }
public void TestApplyRecipeCopyFrom() { using var existingImplDir = new TemporaryDirectory("0install-unit-tests"); using var archiveFile = new TemporaryFile("0install-unit-tests"); new TestRoot { new TestDirectory("source") { new TestFile("file"), new TestFile("executable") { IsExecutable = true }, new TestSymlink("symlink", "target") } }.Build(existingImplDir); typeof(ArchiveExtractorTest).CopyEmbeddedToFile("testArchive.zip", archiveFile); var downloadedFiles = new[] { archiveFile }; var recipe = new Recipe { Steps = { new CopyFromStep { Source = "source", Destination = "dest", Implementation = new Implementation { ManifestDigest = new ManifestDigest(sha1New: "123") } }, new CopyFromStep { Source = "source/file", Destination = "dest/symlink", // Overwrite existing symlink with regular file Implementation = new Implementation { ManifestDigest = new ManifestDigest(sha1New: "123") } } } }; using (FetchHandle.Register(_ => existingImplDir)) { using var recipeDir = recipe.Apply(downloadedFiles, new SilentTaskHandler()); new TestRoot { new TestDirectory("dest") { new TestFile("file"), new TestFile("executable") { IsExecutable = true }, new TestFile("symlink") } }.Verify(recipeDir); } FileUtils.DisableWriteProtection(existingImplDir); Directory.Delete(existingImplDir, recursive: true); }
public void TestApplyRecipeRemove() { using (var archiveFile = new TemporaryFile("0install-unit-tests")) { typeof(ExtractorTest).GetEmbedded("testArchive.zip").CopyToFile(archiveFile); var downloadedFiles = new[] {archiveFile}; var recipe = new Recipe { Steps = { new Archive {MimeType = Archive.MimeTypeZip}, new RemoveStep {Path = "symlink"}, new RemoveStep {Path = "subdir2"} } }; using (TemporaryDirectory recipeDir = recipe.Apply(downloadedFiles, new SilentTaskHandler())) { if (!UnixUtils.IsUnix) { Assert.IsEmpty(FlagUtils.GetFiles(FlagUtils.XbitFile, recipeDir)); Assert.IsEmpty(FlagUtils.GetFiles(FlagUtils.SymlinkFile, recipeDir)); } // /symlink [deleted] string path = Path.Combine(recipeDir, "symlink"); Assert.IsFalse(File.Exists(path), "File should not exist: " + path); // /subdir2 [deleted] path = Path.Combine(recipeDir, "subdir2"); Assert.IsFalse(Directory.Exists(path), "Directory should not exist: " + path); } } }
public void TestApplyRecipeRename() { using (var archiveFile = new TemporaryFile("0install-unit-tests")) { typeof(ExtractorTest).WriteEmbeddedFile("testArchive.zip", archiveFile); var downloadedFiles = new[] { archiveFile }; var recipe = new Recipe { Steps = { new Archive { MimeType = Archive.MimeTypeZip }, new RenameStep { Source = "symlink", Destination = "subdir3/symlink2" }, new RenameStep { Source = "subdir2/executable", Destination = "subdir2/executable2" } } }; using (TemporaryDirectory recipeDir = recipe.Apply(downloadedFiles, new SilentTaskHandler())) { if (!UnixUtils.IsUnix) { CollectionAssert.AreEquivalent( new[] { new[] { recipeDir, "subdir2", "executable2" }.Aggregate(Path.Combine) }, FlagUtils.GetFiles(FlagUtils.XbitFile, recipeDir)); CollectionAssert.AreEquivalent( new[] { new[] { recipeDir, "subdir3", "symlink2" }.Aggregate(Path.Combine) }, FlagUtils.GetFiles(FlagUtils.SymlinkFile, recipeDir)); } // /symlink [deleted] string path = Path.Combine(recipeDir, "symlink"); Assert.IsFalse(File.Exists(path), "File should not exist: " + path); // /subdir3/symlink2 [S] path = new[] { recipeDir, "subdir3", "symlink2" }.Aggregate(Path.Combine); Assert.IsTrue(File.Exists(path), "Missing file: " + path); if (UnixUtils.IsUnix) { Assert.IsTrue(FileUtils.IsSymlink(path), "Not symlink: " + path); } // /subdir2/executable [deleted] path = new[] { recipeDir, "subdir2", "executable" }.Aggregate(Path.Combine); Assert.IsFalse(File.Exists(path), "File should not exist: " + path); // /subdir2/executable2 [X] path = new[] { recipeDir, "subdir2", "executable2" }.Aggregate(Path.Combine); Assert.IsTrue(File.Exists(path), "Missing file: " + path); if (UnixUtils.IsUnix) { Assert.IsTrue(FileUtils.IsExecutable(path), "Not executable: " + path); } } } }
/// <summary> /// Applies a <see cref="Recipe"/> and sends the result to the <see cref="_store"/>. /// </summary> /// <param name="recipe">The recipe to apply.</param> /// <param name="files">The files downloaded for the <paramref name="recipe"/> steps, order matching the <see cref="DownloadRetrievalMethod"/> steps in <see cref="Recipe.Steps"/>.</param> /// <param name="manifestDigest">The digest the result of the recipe should produce.</param> /// <exception cref="OperationCanceledException">An IO task was canceled from another thread.</exception> /// <exception cref="NotSupportedException">A file format, protocal, etc. is unknown or not supported.</exception> /// <exception cref="IOException">A downloaded file could not be written to the disk or extracted.</exception> /// <exception cref="ImplementationAlreadyInStoreException">There is already an <see cref="Implementation"/> with the specified <paramref name="manifestDigest"/> in the store.</exception> /// <exception cref="UnauthorizedAccessException">Write access to <see cref="IStore"/> is not permitted.</exception> /// <exception cref="DigestMismatchException">An <see cref="Implementation"/>'s <see cref="Archive"/>s don't match the associated <see cref="ManifestDigest"/>.</exception> private void ApplyRecipe([NotNull] Recipe recipe, [NotNull, ItemNotNull] IEnumerable <TemporaryFile> files, ManifestDigest manifestDigest) { using (var recipeDir = recipe.Apply(files, Handler, manifestDigest)) _store.AddDirectory(recipeDir, manifestDigest, Handler); }