コード例 #1
0
 /// <summary>
 /// Imports implementation archives into the <see cref="IStore"/>.
 /// </summary>
 private void ImportArchives()
 {
     foreach (string path in Directory.GetFiles(_contentDir))
     {
         Debug.Assert(path != null);
         var digest = new ManifestDigest();
         digest.ParseID(Path.GetFileNameWithoutExtension(path));
         if (digest.Best != null && !Store.Contains(digest))
         {
             try
             {
                 Store.AddArchives(new[]
                 {
                     new ArchiveFileInfo
                     {
                         Path     = path,
                         MimeType = Archive.GuessMimeType(path)
                     }
                 }, digest, Handler);
             }
             #region Error handling
             catch (ImplementationAlreadyInStoreException)
             {}
             #endregion
         }
     }
 }
コード例 #2
0
    public void ParseIDNoOverwrite()
    {
        var digest = new ManifestDigest("sha1=test");

        digest.TryParse("sha1=test2");
        digest.Sha1.Should().Be("test", because: "Once a digest value has been set, ID values should not overwrite it");
    }
コード例 #3
0
            public void MultipleArchives()
            {
                using var tempFile1 = new TemporaryFile("0install-unit-tests");
                using var tempFile2 = new TemporaryFile("0install-unit-tests");
                var    digest = new ManifestDigest(sha256New: "abc");
                string path1  = tempFile1;
                string path2  = tempFile2;

                StoreMock.Setup(x => x.AddArchives(new[]
                {
                    new ArchiveFileInfo(path1, "mime1")
                    {
                        Extract = "extract1"
                    },
                    new ArchiveFileInfo(path2, "mime2")
                    {
                        Extract = "extract2"
                    }
                }, digest, Handler)).Returns("");

                RunAndAssert(null, ExitCode.OK,
                             "sha256new_" + digest.Sha256New,
                             path1, "extract1", "mime1",
                             path2, "extract2", "mime2");
            }
コード例 #4
0
    /// <summary>
    /// Checks whether an implementation directory matches the expected digest.
    /// Throws <see cref="DigestMismatchException"/> if it does not match.
    /// </summary>
    /// <param name="path">The path of the directory ot check.</param>
    /// <param name="manifestDigest">The expected digest.</param>
    /// <param name="handler">A callback object used when the the user is to be informed about progress.</param>
    /// <exception cref="OperationCanceledException">The user canceled the task.</exception>
    /// <exception cref="NotSupportedException"><paramref name="manifestDigest"/> does not list any supported digests.</exception>
    /// <exception cref="IOException">The directory could not be processed.</exception>
    /// <exception cref="UnauthorizedAccessException">Read access to the directory is not permitted.</exception>
    /// <exception cref="DigestMismatchException">The directory does not match the expected digest</exception>
    public static void Verify(string path, ManifestDigest manifestDigest, ITaskHandler handler)
    {
        #region Sanity checks
        if (string.IsNullOrEmpty(path))
        {
            throw new ArgumentNullException(nameof(path));
        }
        if (handler == null)
        {
            throw new ArgumentNullException(nameof(handler));
        }
        #endregion

        string expectedDigest = manifestDigest.Best ?? throw new NotSupportedException(Resources.NoKnownDigestMethod);
        var    format         = ManifestFormat.FromPrefix(expectedDigest);

        var builder = new ManifestBuilder(format);
        handler.RunTask(new ReadDirectory(path, builder));
        if (Verify(builder.Manifest, expectedDigest) == null)
        {
            string manifestFilePath = Path.Combine(path, Manifest.ManifestFile);
            var    expectedManifest = File.Exists(manifestFilePath) ? Manifest.Load(manifestFilePath, format) : null;
            throw new DigestMismatchException(
                      expectedDigest, actualDigest: builder.Manifest.CalculateDigest(),
                      expectedManifest, actualManifest: builder.Manifest);
        }
    }
コード例 #5
0
        public void TestGetImplementation()
        {
            var digest1         = new ManifestDigest(sha256: "123");
            var implementation1 = new Implementation {
                ManifestDigest = digest1
            };
            var feed1 = new Feed {
                Elements = { implementation1 }
            };
            var digest2         = new ManifestDigest(sha256: "abc");
            var implementation2 = new Implementation {
                ManifestDigest = digest2
            };
            var feed2 = new Feed {
                Elements = { implementation2 }
            };
            var feeds = new[] { feed1, feed2 };

            Feed feed;

            Assert.AreEqual(implementation1, feeds.GetImplementation(digest1, out feed));
            Assert.AreEqual(feed1, feed);

            Assert.AreEqual(implementation2, feeds.GetImplementation(digest2, out feed));
            Assert.AreEqual(feed2, feed);

            Assert.IsNull(feeds.GetImplementation(new ManifestDigest(sha256: "invalid"), out feed), "No implementation should have been found");
            Assert.IsNull(feed, "No feed should have been found");
        }
コード例 #6
0
    public void TryParseInvalid()
    {
        var digest = new ManifestDigest();

        digest.TryParse("invalid");
        digest.AvailableDigests.Should().BeEmpty();
    }
コード例 #7
0
        public void TestGetImplementation()
        {
            var digest1         = new ManifestDigest(sha256: "123");
            var implementation1 = new Implementation {
                ManifestDigest = digest1
            };
            var feed1 = new Feed {
                Elements = { implementation1 }
            };
            var digest2         = new ManifestDigest(sha256: "abc");
            var implementation2 = new Implementation {
                ManifestDigest = digest2
            };
            var feed2 = new Feed {
                Elements = { implementation2 }
            };
            var feeds = new[] { feed1, feed2 };

            Feed feed;

            feeds.GetImplementation(digest1, out feed).Should().Be(implementation1);
            feed.Should().Be(feed1);

            feeds.GetImplementation(digest2, out feed).Should().Be(implementation2);
            feed.Should().Be(feed2);

            feeds.GetImplementation(new ManifestDigest(sha256: "invalid"), out feed).Should().BeNull(because: "No implementation should have been found");
            feed.Should().BeNull(because: "No feed should have been found");
        }
コード例 #8
0
        /// <summary>
        /// Executes a specific <see cref="RetrievalMethod"/>.
        /// </summary>
        /// <param name="retrievalMethod">The retrieval method to execute.</param>
        /// <param name="manifestDigest">The digest the result of the retrieval method should produce.</param>
        /// <exception cref="OperationCanceledException">A download or IO task was canceled from another thread.</exception>
        /// <exception cref="WebException">A file could not be downloaded from the internet.</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="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 Retrieve([NotNull] RetrievalMethod retrievalMethod, ManifestDigest manifestDigest)
        {
            var externalRetrievalMethod = retrievalMethod as ExternalRetrievalMethod;

            if (externalRetrievalMethod != null)
            {
                RunNative(externalRetrievalMethod);
                return;
            }

            // Treat single steps as a Recipes for easier handling
            var recipe = retrievalMethod as Recipe ?? new Recipe {
                Steps = { (IRecipeStep)retrievalMethod }
            };

            try
            {
                Cook(recipe, manifestDigest);
            }
            #region Error handling
            catch (ImplementationAlreadyInStoreException)
            {}
            catch (DigestMismatchException ex)
            {
                // Wrap exception to add context information
                throw new DigestMismatchException("Damaged download: " + retrievalMethod, ex);
            }
            #endregion
        }
コード例 #9
0
        /// <summary>
        /// Calculates the <see cref="ManifestDigest"/>.
        /// </summary>
        /// <param name="handler">A callback object used when the the user needs to be informed about IO tasks.</param>
        /// <exception cref="InvalidOperationException"><see cref="ImplementationDirectory"/> is <c>null</c> or empty.</exception>
        /// <exception cref="OperationCanceledException">The user canceled the task.</exception>
        /// <exception cref="IOException">There was a problem generating the manifest.</exception>
        /// <exception cref="UnauthorizedAccessException">Write access to temporary files was not permitted.</exception>
        public void CalculateDigest(ITaskHandler handler)
        {
            #region Sanity checks
            if (handler == null)
            {
                throw new ArgumentNullException(nameof(handler));
            }
            if (string.IsNullOrEmpty(ImplementationDirectory))
            {
                throw new InvalidOperationException("Implementation directory is not set.");
            }
            #endregion

            var newDigest = new ManifestDigest();

            // Generate manifest for each available format...
            foreach (var generator in ManifestFormat.All.Select(format => new ManifestGenerator(ImplementationDirectory, format)))
            {
                // ... and add the resulting digest to the return value
                handler.RunTask(generator);
                newDigest.ParseID(generator.Manifest.CalculateDigest());
            }

            ManifestDigest = newDigest;
        }
コード例 #10
0
        public override ExitCode Execute()
        {
            var    manifestDigest = new ManifestDigest(AdditionalArgs[0]);
            string path           = AdditionalArgs[1];

            try
            {
                if (File.Exists(path))
                { // One or more archives (combined/overlay)
                    ImplementationStore.Add(manifestDigest, BuildImplementation);
                    return(ExitCode.OK);
                }
                else if (Directory.Exists(path))
                { // A single directory
                    if (AdditionalArgs.Count > 2)
                    {
                        throw new OptionException(Resources.TooManyArguments + Environment.NewLine + AdditionalArgs.Skip(2).JoinEscapeArguments(), null);
                    }
                    ImplementationStore.Add(manifestDigest, builder => Handler.RunTask(new ReadDirectory(Path.GetFullPath(path), builder)));
                    return(ExitCode.OK);
                }
                else
                {
                    throw new FileNotFoundException(string.Format(Resources.FileOrDirNotFound, path), path);
                }
            }
            catch (ImplementationAlreadyInStoreException ex)
            {
                Log.Warn(ex);
                return(ExitCode.NoChanges);
            }
        }
コード例 #11
0
        public override ExitCode Execute()
        {
            ManifestDigest digest;
            string         path = Path.GetFullPath(AdditionalArgs[0]).TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
            string         id   = Path.GetFileName(path);

            try
            {
                digest = new ManifestDigest(id);
            }
            catch (NotSupportedException ex)
            {
                Log.Error(ex);
                return(ExitCode.NotSupported);
            }

            var store = (AdditionalArgs.Count == 2) ? new ImplementationStore(AdditionalArgs[1]) : ImplementationStore;

            try
            {
                store.Add(digest, builder => Handler.RunTask(new ReadDirectory(path, builder)));
                return(ExitCode.OK);
            }
            catch (ImplementationAlreadyInStoreException ex)
            {
                Log.Warn(ex);
                return(ExitCode.NoChanges);
            }
        }
コード例 #12
0
    /// <summary>
    /// Calculates a <see cref="ManifestDigest"/> for a retrieval method. Sets missing properties in the process.
    /// </summary>
    /// <param name="retrievalMethod">The retrieval method.</param>
    /// <param name="executor">Used to modify properties in an undoable fashion.</param>
    /// <param name="handler">A callback object used when the the user is to be informed about progress.</param>
    /// <param name="format">The manifest format. Leave <c>null</c> for default.</param>
    /// <returns>The generated digest.</returns>
    /// <exception cref="OperationCanceledException">The user canceled the task.</exception>
    /// <exception cref="WebException">A file could not be downloaded from the internet.</exception>
    public static ManifestDigest CalculateDigest(this RetrievalMethod retrievalMethod, ICommandExecutor executor, ITaskHandler handler, ManifestFormat?format = null)
    {
        #region Sanity checks
        if (retrievalMethod == null)
        {
            throw new ArgumentNullException(nameof(retrievalMethod));
        }
        if (executor == null)
        {
            throw new ArgumentNullException(nameof(executor));
        }
        if (handler == null)
        {
            throw new ArgumentNullException(nameof(handler));
        }
        #endregion

        var builder = new ManifestBuilder(format ?? ManifestFormat.Sha256New);
        builder.Add(retrievalMethod, executor, handler);

        var digest = new ManifestDigest(builder.Manifest.CalculateDigest());
        if (digest.PartialEquals(ManifestDigest.Empty))
        {
            Log.Warn(Resources.EmptyImplementation);
        }
        return(digest);
    }
コード例 #13
0
    public void TryParseEmptyString()
    {
        var digest = new ManifestDigest();

        digest.TryParse("");
        digest.AvailableDigests.Should().BeEmpty();
    }
コード例 #14
0
    private ImplementationNode?GetImplementationNode(ManifestDigest digest)
    {
        Debug.Assert(_feeds != null);

        try
        {
            var found = _feeds.FindImplementation(digest);
            if (found.HasValue)
            {
                return(new OwnedImplementationNode(digest, found.Value.implementation, new FeedNode(found.Value.feed, _feedCache), _implementationStore));
            }
            else
            {
                return(new OrphanedImplementationNode(digest, _implementationStore));
            }
        }
        #region Error handling
        catch (Exception ex) when(ex is IOException or UnauthorizedAccessException or FormatException)
        {
            Log.Error($"Problem processing '{digest}'.");
            Log.Error(ex);
            return(null);
        }
        #endregion
    }
コード例 #15
0
 public override ExitCode Execute()
 {
     var manifestDigest = new ManifestDigest(AdditionalArgs[0]);
     string path = AdditionalArgs[1];
     try
     {
         if (File.Exists(path))
         { // One or more archives (combined/overlayed)
             Store.AddArchives(GetArchiveFileInfos(), manifestDigest, Handler);
             return ExitCode.OK;
         }
         else if (Directory.Exists(path))
         { // A single directory
             if (AdditionalArgs.Count > 2) throw new OptionException(Resources.TooManyArguments + Environment.NewLine + AdditionalArgs.Skip(2).JoinEscapeArguments(), null);
             Store.AddDirectory(Path.GetFullPath(path), manifestDigest, Handler);
             return ExitCode.OK;
         }
         else throw new FileNotFoundException(string.Format(Resources.FileOrDirNotFound, path), path);
     }
     catch (ImplementationAlreadyInStoreException ex)
     {
         Log.Warn(ex);
         return ExitCode.NoChanges;
     }
 }
コード例 #16
0
        public override ExitCode Execute()
        {
            var manifestDigest = new ManifestDigest(AdditionalArgs[0]);

            try
            {
                string path = AdditionalArgs[1];
                if (Directory.Exists(path))
                {
                    if (AdditionalArgs.Count > 2)
                    {
                        throw new OptionException(Resources.TooManyArguments + Environment.NewLine + AdditionalArgs.Skip(2).JoinEscapeArguments(), null);
                    }
                    ImplementationStore.Add(manifestDigest, builder => Handler.RunTask(new ReadDirectory(Path.GetFullPath(path), builder)));
                    return(ExitCode.OK);
                }

                ImplementationStore.Add(manifestDigest, BuildImplementation);
                return(ExitCode.OK);
            }
            catch (ImplementationAlreadyInStoreException ex)
            {
                Log.Warn(ex.Message, ex);
                return(ExitCode.NoChanges);
            }
        }
コード例 #17
0
        /// <summary>
        /// Gets a GUI element for reporting progress of a <see cref="ITask"/> for a specific implementation. May run multiple in parallel.
        /// </summary>
        /// <param name="taskName">The name of the task to be tracked.</param>
        /// <param name="tag">A digest used to associate the task with a specific implementation.</param>
        /// <remarks>This method must not be called from a background thread.</remarks>
        public IProgress <TaskSnapshot> GetProgressControl(string taskName, ManifestDigest tag)
        {
            #region Sanity checks
            if (string.IsNullOrEmpty(taskName))
            {
                throw new ArgumentNullException(nameof(taskName));
            }
            if (InvokeRequired)
            {
                throw new InvalidOperationException("Method called from a non UI thread.");
            }
            #endregion

            // Hide other stuff
            taskControl.Hide();

            if (_selectionsShown)
            {
                var control = selectionsControl.TaskControls[tag];
                control.TaskName = taskName;
                return(control);
            }
            else
            {
                return(GetProgressControl(taskName));
            }
        }
コード例 #18
0
    /// <inheritdoc />
    public void Purge(ITaskHandler handler)
    {
        #region Sanity checks
        if (handler == null)
        {
            throw new ArgumentNullException(nameof(handler));
        }
        #endregion

        var paths = Directory.GetDirectories(Path).Where(path =>
        {
            var digest = new ManifestDigest();
            digest.TryParse(System.IO.Path.GetFileName(path));
            return(digest.AvailableDigests.Any());
        }).ToList();
        if (paths.Count == 0)
        {
            return;
        }

        if (MissingAdminRights)
        {
            throw new NotAdminException(Resources.MustBeAdminToRemove);
        }

        handler.RunTask(ForEachTask.Create(
                            name: string.Format(Resources.DeletingDirectory, Path),
                            target: paths,
                            work: path => RemoveInner(path, handler, allowAutoShutdown: true)));

        RemoveDeleteInfoFile();
    }
コード例 #19
0
        /// <summary>
        /// Executes the work-step for a single implementation.
        /// </summary>
        public void Work(ManifestDigest manifestDigest)
        {
            string digestString = manifestDigest.Best;
            if (digestString == null) return;
            string implementationPath = Path.Combine(_storePath, digestString);
            var manifest = Manifest.Load(Path.Combine(implementationPath, Manifest.ManifestFile), ManifestFormat.FromPrefix(digestString));

            string currentDirectory = "";
            new AggregateDispatcher<ManifestNode>
            {
                (ManifestDirectory x) => { currentDirectory = FileUtils.UnifySlashes(x.FullPath.TrimStart('/')); },
                (ManifestFileBase x) =>
                {
                    if (x.Size == 0) return;

                    var key = new DedupKey(x.Size, x.ModifiedTime, manifest.Format, x.Digest);
                    var file = new StoreFile(implementationPath, Path.Combine(currentDirectory, x.FileName));

                    StoreFile existingFile;
                    if (_fileHashes.TryGetValue(key, out existingFile))
                    {
                        if (!FileUtils.AreHardlinked(file, existingFile))
                        {
                            if (JoinWithHardlink(file, existingFile))
                                SavedBytes += x.Size;
                        }
                    }
                    else _fileHashes.Add(key, file);
                }
            }.Dispatch(manifest);
        }
コード例 #20
0
        /// <summary>
        /// Executes a specific <see cref="RetrievalMethod"/>.
        /// </summary>
        /// <param name="retrievalMethod">The retrieval method to execute.</param>
        /// <param name="manifestDigest">The digest the result of the retrieval method should produce.</param>
        /// <exception cref="OperationCanceledException">A download or IO task was canceled from another thread.</exception>
        /// <exception cref="WebException">A file could not be downloaded from the internet.</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="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 Retrieve(RetrievalMethod retrievalMethod, ManifestDigest manifestDigest)
        {
            if (retrievalMethod is ExternalRetrievalMethod externalRetrievalMethod)
            {
                RunNative(externalRetrievalMethod);
                return;
            }

            // Treat single steps as a Recipes for easier handling
            var recipe = retrievalMethod as Recipe ?? new Recipe {
                Steps = { (IRecipeStep)retrievalMethod }
            };

            try
            {
                // Enable Recipe steps to call back to Fetcher
                using (FetchHandle.Register(impl => Fetch(impl, tag: manifestDigest) ?? throw new ImplementationNotFoundException(manifestDigest)))
                    Cook(recipe, manifestDigest);
            }
            #region Error handling
            catch (ImplementationAlreadyInStoreException)
            {}
            catch (DigestMismatchException)
            {
                Log.Error("Damaged download: " + retrievalMethod);
                throw;
            }
            #endregion
        }
コード例 #21
0
            public override ExitCode Execute()
            {
                ManifestDigest manifestDigest;
                string         path = Path.GetFullPath(AdditionalArgs[0]).TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);

                try
                {
                    manifestDigest = new ManifestDigest(Path.GetFileName(path));
                }
                #region Error handling
                catch (ArgumentException ex)
                {
                    // Wrap exception since only certain exception types are allowed
                    throw new IOException(ex.Message);
                }
                #endregion

                var store = (AdditionalArgs.Count == 2) ? new DiskImplementationStore(AdditionalArgs[1]) : ImplementationStore;
                try
                {
                    store.AddDirectory(path, manifestDigest, Handler);
                    return(ExitCode.OK);
                }
                catch (ImplementationAlreadyInStoreException ex)
                {
                    Log.Warn(ex);
                    return(ExitCode.NoChanges);
                }
            }
コード例 #22
0
        protected virtual string VerifyAndAdd(string tempID, ManifestDigest expectedDigest, ITaskHandler handler)
        {
            #region Sanity checks
            if (string.IsNullOrEmpty(tempID))
            {
                throw new ArgumentNullException(nameof(tempID));
            }
            if (handler == null)
            {
                throw new ArgumentNullException(nameof(handler));
            }
            #endregion

            // Determine the digest method to use
            string?expectedDigestValue = expectedDigest.Best;
            if (string.IsNullOrEmpty(expectedDigestValue))
            {
                throw new NotSupportedException(Resources.NoKnownDigestMethod);
            }

            // Determine the source and target directories
            string source = Path.Combine(DirectoryPath, tempID);
            string target = Path.Combine(DirectoryPath, expectedDigestValue);

            if (_isUnixFS)
            {
                FlagUtils.ConvertToFS(source);
            }

            // Calculate the actual digest, compare it with the expected one and create a manifest file
            VerifyDirectory(source, expectedDigest, handler).Save(Path.Combine(source, Manifest.ManifestFile));

            lock (_renameLock) // Prevent race-conditions when adding the same digest twice
            {
                if (Directory.Exists(target))
                {
                    throw new ImplementationAlreadyInStoreException(expectedDigest);
                }

                // Move directory to final store destination
                try
                {
                    Directory.Move(source, target);
                }
                catch (IOException ex)
                    // TODO: Make language independent
                    when(ex.Message.Contains("already exists"))
                    {
                        throw new ImplementationAlreadyInStoreException(expectedDigest);
                    }
            }

            // Prevent any further changes to the directory
            if (_useWriteProtection)
            {
                EnableWriteProtection(target);
            }
            return(target);
        }
コード例 #23
0
        /// <summary>
        /// Deserializes an exception.
        /// </summary>
        private ImplementationNotFoundException(SerializationInfo info, StreamingContext context) : base(info, context)
        {
            #region Sanity checks
            if (info == null) throw new ArgumentNullException(nameof(info));
            #endregion

            ManifestDigest = (ManifestDigest)info.GetValue("ManifestDigest", typeof(ManifestDigest));
        }
コード例 #24
0
    public void TryParseSuccess()
    {
        var digest = new ManifestDigest();

        digest.TryParse("sha1new=test1");
        digest.TryParse("sha256new_test2");
        digest.AvailableDigests.Should().Equal("sha256new_test2", "sha1new=test1");
    }
コード例 #25
0
ファイル: RunTest.cs プロジェクト: 0install/0install-dotnet
    [Fact] // Ensures all options are parsed and handled correctly.
    public void TestNormal()
    {
        var selections = ExpectSolve();

        ExpectFetchUncached(selections,
                            new Implementation {
            ID = "id1", ManifestDigest = new ManifestDigest(Sha256: "abc"), Version = new("1.0")
        },
コード例 #26
0
    /// <inheritdoc/>
    public void Add(ManifestDigest manifestDigest, Action <IBuilder> build)
    {
        #region Sanity checks
        if (build == null)
        {
            throw new ArgumentNullException(nameof(build));
        }
        #endregion

        if (manifestDigest.AvailableDigests.Any(digest => Directory.Exists(System.IO.Path.Combine(Path, digest))))
        {
            throw new ImplementationAlreadyInStoreException(manifestDigest);
        }
        string expectedDigest = manifestDigest.Best ?? throw new NotSupportedException(Resources.NoKnownDigestMethod);
        Log.Debug($"Storing implementation {expectedDigest} in {this}");
        var format = ManifestFormat.FromPrefix(manifestDigest.Best);

        // Place files in temp directory until digest is verified
        string tempDir = GetTempDir();
        using var _ = new Disposable(() => DeleteTempDir(tempDir));

        var builder = new ManifestBuilder(format);
        build(new DirectoryBuilder(tempDir, builder));
        var manifest = ImplementationStoreUtils.Verify(builder.Manifest, expectedDigest);

        if (manifest == null)
        {
            throw new DigestMismatchException(
                      expectedDigest, actualDigest: builder.Manifest.CalculateDigest(),
                      actualManifest: builder.Manifest);
        }
        manifest.Save(System.IO.Path.Combine(tempDir, Manifest.ManifestFile));

        string target = System.IO.Path.Combine(Path, expectedDigest);
        lock (_renameLock) // Prevent race-conditions when adding the same digest twice
        {
            if (Directory.Exists(target))
            {
                throw new ImplementationAlreadyInStoreException(manifestDigest);
            }

            // Move directory to final destination
            try
            {
                Directory.Move(tempDir, target);
            }
            catch (IOException ex) when(ex.Message.Contains("already exists") || Directory.Exists(target))
            {
                throw new ImplementationAlreadyInStoreException(manifestDigest);
            }
        }

        // Prevent any further changes to the directory
        if (UseWriteProtection)
        {
            EnableWriteProtection(target);
        }
    }
コード例 #27
0
        /// <summary>
        /// Sets the <see cref="ManifestDigest"/> in the <see cref="ContainerRef"/>.
        /// </summary>
        /// <param name="digest">The digest to set.</param>
        /// <param name="executor">Used to apply properties in an undoable fashion.</param>
        private void SetDigest(ManifestDigest digest, ICommandExecutor executor)
        {
            executor.Execute(new SetValueCommand <ManifestDigest>(() => ContainerRef.ManifestDigest, value => ContainerRef.ManifestDigest = value, digest));

            if (string.IsNullOrEmpty(ContainerRef.ID) || ContainerRef.ID.Contains(@"="))
            {
                executor.Execute(new SetValueCommand <string>(() => ContainerRef.ID, value => ContainerRef.ID = value, @"sha1new=" + digest.Sha1New));
            }
        }
コード例 #28
0
            public void Fail()
            {
                var digest = new ManifestDigest(sha256New: "abc");

                StoreMock.Setup(x => x.Verify(digest, Handler)).Throws <DigestMismatchException>();

                RunAndAssert(new DigestMismatchException().Message, ExitCode.DigestMismatch,
                             "sha256new_" + digest.Sha256New);
            }
コード例 #29
0
            public void Test()
            {
                var digest = new ManifestDigest(sha256New: "abc");

                StoreMock.Setup(x => x.Remove(digest, Handler)).Returns(true);

                RunAndAssert(null, ExitCode.OK,
                             "sha256new_abc");
            }
コード例 #30
0
            public void Pass()
            {
                var digest = new ManifestDigest(sha256New: "abc");

                StoreMock.Setup(x => x.Verify(digest, Handler));

                RunAndAssert(null, ExitCode.OK,
                             "sha256new_" + digest.Sha256New);
            }
コード例 #31
0
        public void TestVerifyPass()
        {
            var digest = new ManifestDigest(sha256New: "abc");

            StoreMock.Setup(x => x.Verify(digest, Resolve <ICommandHandler>()));

            RunAndAssert(null, ExitCode.OK,
                         "verify", "sha256new_" + digest.Sha256New);
        }
コード例 #32
0
            public void Test()
            {
                var digest = new ManifestDigest(sha256New: "abc");

                StoreMock.Setup(x => x.GetPath(digest)).Returns("path");

                RunAndAssert("path", ExitCode.OK,
                             "sha256new_abc");
            }
コード例 #33
0
        public void TestGetTree()
        {
            var digest1 = new ManifestDigest(sha256New: "a");
            var digest2 = new ManifestDigest(sha256New: "b");

            _storeMock.Setup(x => x.GetPath(digest1)).Returns("fake/path");
            _storeMock.Setup(x => x.GetPath(digest2)).Returns(() => null);

            var tree = _selectionsManager.GetTree(new Selections
            {
                InterfaceUri    = new FeedUri("http://root/"),
                Implementations =
                {
                    new ImplementationSelection
                    {
                        InterfaceUri   = new FeedUri("http://root/"),
                        ID             = "a",
                        ManifestDigest = digest1,
                        Version        = new ImplementationVersion("1.0"),
                        Dependencies   =
                        {
                            new Dependency {
                                InterfaceUri = new FeedUri("http://dependency/")
                            },
                            new Dependency {
                                InterfaceUri = new FeedUri("http://missing/")
                            }
                        }
                    },
                    new ImplementationSelection
                    {
                        InterfaceUri   = new FeedUri("http://dependency/"),
                        ID             = "b",
                        ManifestDigest = digest2,
                        Version        = new ImplementationVersion("2.0"),
                        Dependencies   =   { new Dependency{
                                                 InterfaceUri = new FeedUri("http://root/")
                                             } }                                                     // Exercise cycle detection
                    }
                }
            });

            var node1 = new SelectionsTreeNode(new FeedUri("http://root/"), new ImplementationVersion("1.0"), "fake/path", parent: null);

            node1.ToString().Should().Be("- URI: http://root/\n  Version: 1.0\n  Path: fake/path");

            var node2 = new SelectionsTreeNode(new FeedUri("http://dependency/"), new ImplementationVersion("2.0"), path: null, parent: node1);

            node2.ToString().Should().Be($"  - URI: http://dependency/\n    Version: 2.0\n    {Resources.NotCached}");

            var node3 = new SelectionsTreeNode(new FeedUri("http://missing/"), version: null, path: null, parent: node1);

            node3.ToString().Should().Be($"  - URI: http://missing/\n    {Resources.NoSelectedVersion}");

            tree.Should().Equal(node1, node2, node3);
        }
コード例 #34
0
        public void ShouldAllowToAddFolder()
        {
            using (var packageDir = new TemporaryDirectory("0install-unit-tests"))
            {
                var digest = new ManifestDigest(ManifestTest.CreateDotFile(packageDir, ManifestFormat.Sha256, _handler));
                _store.AddDirectory(packageDir, digest, _handler);

                Assert.IsTrue(_store.Contains(digest), "After adding, Store must contain the added package");
                CollectionAssert.AreEqual(new[] {digest}, _store.ListAll(), "After adding, Store must show the added package in the complete list");
            }
        }
コード例 #35
0
        public void TestParseID()
        {
            Assert.AreEqual("test", new ManifestDigest("sha1=test").Sha1);
            Assert.AreEqual("test", new ManifestDigest("sha1new=test").Sha1New);
            Assert.AreEqual("test", new ManifestDigest("sha256=test").Sha256);
            Assert.AreEqual("test", new ManifestDigest("sha256new_test").Sha256New);

            // Once a digest value has been set, ID values shall not be able to overwrite it
            var digest = new ManifestDigest("sha1=test");
            digest.ParseID("sha1=test2");
            Assert.AreEqual("test", digest.Sha1);
        }
コード例 #36
0
        public void TestParseID()
        {
            new ManifestDigest("sha1=test").Sha1.Should().Be("test");
            new ManifestDigest("sha1new=test").Sha1New.Should().Be("test");
            new ManifestDigest("sha256=test").Sha256.Should().Be("test");
            new ManifestDigest("sha256new_test").Sha256New.Should().Be("test");

            // Once a digest value has been set, ID values shall not be able to overwrite it
            var digest = new ManifestDigest("sha1=test");
            digest.ParseID("sha1=test2");
            digest.Sha1.Should().Be("test");
        }
コード例 #37
0
        /// <summary>
        /// Creates a new owned implementation node.
        /// </summary>
        /// <param name="digest">The digest identifying the implementation.</param>
        /// <param name="implementation">Information about the implementation from a <see cref="Feed"/> file.</param>
        /// <param name="parent">The node of the feed owning the implementation.</param>
        /// <param name="store">The <see cref="IStore"/> the implementation is located in.</param>
        /// <exception cref="FormatException">The manifest file is not valid.</exception>
        /// <exception cref="IOException">The manifest file could not be read.</exception>
        /// <exception cref="UnauthorizedAccessException">Read access to the file is not permitted.</exception>
        public OwnedImplementationNode(ManifestDigest digest, [NotNull] Implementation implementation, [NotNull] FeedNode parent, [NotNull] IStore store)
            : base(digest, store)
        {
            #region Sanity checks
            if (implementation == null) throw new ArgumentNullException("implementation");
            if (parent == null) throw new ArgumentNullException("parent");
            if (store == null) throw new ArgumentNullException("store");
            #endregion

            _parent = parent;
            _implementation = implementation;
        }
コード例 #38
0
        /// <summary>
        /// Creates a new implementation node.
        /// </summary>
        /// <param name="digest">The digest identifying the implementation.</param>
        /// <param name="store">The <see cref="IStore"/> the implementation is located in.</param>
        /// <exception cref="FormatException">The manifest file is not valid.</exception>
        /// <exception cref="IOException">The manifest file could not be read.</exception>
        /// <exception cref="UnauthorizedAccessException">Read access to the file is not permitted.</exception>
        protected ImplementationNode(ManifestDigest digest, [NotNull] IStore store)
            : base(store)
        {
            #region Sanity checks
            if (store == null) throw new ArgumentNullException("store");
            #endregion

            _digest = digest;

            // Determine the total size of an implementation via its manifest file
            string path = store.GetPath(digest);
            if (path == null) return;
            string manifestPath = System.IO.Path.Combine(path, Manifest.ManifestFile);
            Size = Manifest.Load(manifestPath, ManifestFormat.FromPrefix(digest.AvailableDigests.FirstOrDefault())).TotalSize;
        }
コード例 #39
0
ファイル: IpcStore.cs プロジェクト: modulexcite/0install-win
 /// <inheritdoc/>
 public string AddArchives(IEnumerable<ArchiveFileInfo> archiveInfos, ManifestDigest manifestDigest, ITaskHandler handler)
 {
     try
     {
         string result = GetServiceProxy().AddArchives(archiveInfos, manifestDigest, handler);
         Log.Info("Sent implementation to Store Service: " + manifestDigest.AvailableDigests.First());
         return result;
     }
         #region Error handling
     catch (RemotingException ex)
     {
         // Wrap exception since only certain exception types are allowed
         throw new IOException(ex.Message, ex);
     }
     #endregion
 }
コード例 #40
0
        public static string GetPathSafe([NotNull] this IStore store, ManifestDigest manifestDigest)
        {
            #region Sanity checks
            if (store == null) throw new ArgumentNullException("store");
            #endregion

            try
            {
                return store.GetPath(manifestDigest);
            }
                #region Error handling
            catch (UnauthorizedAccessException)
            {
                return null;
            }
            #endregion
        }
コード例 #41
0
        public void TestPartialEqual()
        {
            var digest1 = new ManifestDigest(sha1: "test1");
            var digest2 = new ManifestDigest(sha1: "test1", sha1New: "test2");
            digest1.PartialEquals(digest2).Should().BeTrue();

            digest1 = new ManifestDigest(sha1: "test1");
            digest2 = new ManifestDigest(sha1: "test2");
            digest1.PartialEquals(digest2).Should().BeFalse();

            digest1 = new ManifestDigest(sha1: "test1");
            digest2 = new ManifestDigest(sha1New: "test2");
            digest1.PartialEquals(digest2).Should().BeFalse();

            digest1 = new ManifestDigest(sha1New: "test1");
            digest2 = new ManifestDigest(sha256: "test2");
            digest1.PartialEquals(digest2).Should().BeFalse();
        }
コード例 #42
0
        public void TestPartialEqual()
        {
            var digest1 = new ManifestDigest(sha1: "test1");
            var digest2 = new ManifestDigest(sha1: "test1", sha1New: "test2");
            Assert.IsTrue(digest1.PartialEquals(digest2));

            digest1 = new ManifestDigest(sha1: "test1");
            digest2 = new ManifestDigest(sha1: "test2");
            Assert.IsFalse(digest1.PartialEquals(digest2));

            digest1 = new ManifestDigest(sha1: "test1");
            digest2 = new ManifestDigest(sha1New: "test2");
            Assert.IsFalse(digest1.PartialEquals(digest2));

            digest1 = new ManifestDigest(sha1New: "test1");
            digest2 = new ManifestDigest(sha256: "test2");
            Assert.IsFalse(digest1.PartialEquals(digest2));
        }
コード例 #43
0
        public static Implementation GetImplementation([NotNull] this IEnumerable<Feed> feeds, ManifestDigest digest, out Feed feed)
        {
            #region Sanity checks
            if (feeds == null) throw new ArgumentNullException(nameof(feeds));
            #endregion

            foreach (var curFeed in feeds)
            {
                var impl = curFeed.Elements.OfType<Implementation>().FirstOrDefault(implementation => implementation.ManifestDigest.PartialEquals(digest));
                if (impl != null)
                {
                    feed = curFeed;
                    return impl;
                }
            }

            feed = null;
            return null;
        }
コード例 #44
0
        public void TestGetImplementation()
        {
            var digest1 = new ManifestDigest(sha256: "123");
            var implementation1 = new Implementation {ManifestDigest = digest1};
            var feed1 = new Feed {Elements = {implementation1}};
            var digest2 = new ManifestDigest(sha256: "abc");
            var implementation2 = new Implementation {ManifestDigest = digest2};
            var feed2 = new Feed {Elements = {implementation2}};
            var feeds = new[] {feed1, feed2};

            Feed feed;
            Assert.AreEqual(implementation1, feeds.GetImplementation(digest1, out feed));
            Assert.AreEqual(feed1, feed);

            Assert.AreEqual(implementation2, feeds.GetImplementation(digest2, out feed));
            Assert.AreEqual(feed2, feed);

            Assert.IsNull(feeds.GetImplementation(new ManifestDigest(sha256: "invalid"), out feed), "No implementation should have been found");
            Assert.IsNull(feed, "No feed should have been found");
        }
コード例 #45
0
        public void TestGetImplementation()
        {
            var digest1 = new ManifestDigest(sha256: "123");
            var implementation1 = new Implementation {ManifestDigest = digest1};
            var feed1 = new Feed {Elements = {implementation1}};
            var digest2 = new ManifestDigest(sha256: "abc");
            var implementation2 = new Implementation {ManifestDigest = digest2};
            var feed2 = new Feed {Elements = {implementation2}};
            var feeds = new[] {feed1, feed2};

            Feed feed;
            feeds.GetImplementation(digest1, out feed).Should().Be(implementation1);
            feed.Should().Be(feed1);

            feeds.GetImplementation(digest2, out feed).Should().Be(implementation2);
            feed.Should().Be(feed2);

            feeds.GetImplementation(new ManifestDigest(sha256: "invalid"), out feed).Should().BeNull(because: "No implementation should have been found");
            feed.Should().BeNull(because: "No feed should have been found");
        }
コード例 #46
0
ファイル: IpcStore.cs プロジェクト: 0install/0install-win
 /// <summary>
 /// Does nothing. Should be handled by an <see cref="DirectoryStore"/> directly instead of using the service.
 /// </summary>
 public bool Remove(ManifestDigest manifestDigest, ITaskHandler handler)
 {
     return false;
 }
コード例 #47
0
ファイル: IpcStore.cs プロジェクト: 0install/0install-win
 /// <inheritdoc/>
 public string AddDirectory(string path, ManifestDigest manifestDigest, ITaskHandler handler)
 {
     try
     {
         string result = GetServiceProxy().AddDirectory(path, manifestDigest, handler);
         Log.Info("Sent implementation to Store Service: " + manifestDigest.Best);
         return result;
     }
         #region Error handling
     catch (RemotingException ex)
     {
         // Wrap exception since only certain exception types are allowed
         throw new IOException(ex.Message, ex);
     }
     catch (SerializationException ex)
     {
         // Wrap exception since only certain exception types are allowed
         throw new IOException(ex.Message, ex);
     }
     #endregion
 }
コード例 #48
0
ファイル: IpcStore.cs プロジェクト: 0install/0install-win
 /// <summary>
 /// Always returns <c>null</c>. Use a non-IPC <see cref="IStore"/> for this method instead.
 /// </summary>
 /// <remarks>Using the store service for this is unnecessary since it only requires read access to the file system.</remarks>
 public string GetPath(ManifestDigest manifestDigest)
 {
     return null;
 }
コード例 #49
0
        /// <summary>
        /// Executes a <see cref="Recipe"/>.
        /// </summary>
        /// <param name="recipe">The recipe to execute.</param>
        /// <param name="manifestDigest">The digest the result of the recipe should produce.</param>
        /// <exception cref="OperationCanceledException">A download or IO task was canceled from another thread.</exception>
        /// <exception cref="WebException">A file could not be downloaded from the internet.</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="Store.Model.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="Store.Model.Implementation"/>'s <see cref="Archive"/>s don't match the associated <see cref="ManifestDigest"/>.</exception>
        private void Cook([NotNull] Recipe recipe, ManifestDigest manifestDigest)
        {
            Handler.CancellationToken.ThrowIfCancellationRequested();

            // Fail fast on unsupported archive type
            foreach (var archive in recipe.Steps.OfType<Archive>()) Extractor.VerifySupport(archive.MimeType);

            var downloadedFiles = new List<TemporaryFile>();
            try
            {
                foreach (var downloadStep in recipe.Steps.OfType<DownloadRetrievalMethod>())
                    downloadedFiles.Add(Download(downloadStep, tag: manifestDigest));

                // More efficient special-case handling for Archive-only cases
                if (recipe.Steps.All(step => step is Archive))
                    ApplyArchives(recipe.Steps.Cast<Archive>().ToList(), downloadedFiles, manifestDigest);
                else
                    ApplyRecipe(recipe, downloadedFiles, manifestDigest);
            }
            finally
            {
                foreach (var downloadedFile in downloadedFiles) downloadedFile.Dispose();
            }
        }
コード例 #50
0
        /// <summary>
        /// Executes a specific <see cref="RetrievalMethod"/>.
        /// </summary>
        /// <param name="retrievalMethod">The retrieval method to execute.</param>
        /// <param name="manifestDigest">The digest the result of the retrieval method should produce.</param>
        /// <exception cref="OperationCanceledException">A download or IO task was canceled from another thread.</exception>
        /// <exception cref="WebException">A file could not be downloaded from the internet.</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="UnauthorizedAccessException">Write access to <see cref="IStore"/> is not permitted.</exception>
        /// <exception cref="DigestMismatchException">An <see cref="Store.Model.Implementation"/>'s <see cref="Archive"/>s don't match the associated <see cref="ManifestDigest"/>.</exception>
        private void Retrieve([NotNull] RetrievalMethod retrievalMethod, ManifestDigest manifestDigest)
        {
            var externalRetrievalMethod = retrievalMethod as ExternalRetrievalMethod;
            if (externalRetrievalMethod != null)
            {
                RunNative(externalRetrievalMethod);
                return;
            }

            // Treat single steps as a Recipes for easier handling
            var recipe = retrievalMethod as Recipe ?? new Recipe {Steps = {(IRecipeStep)retrievalMethod}};
            try
            {
                Cook(recipe, manifestDigest);
            }
                #region Error handling
            catch (ImplementationAlreadyInStoreException)
            {}
            catch (DigestMismatchException ex)
            {
                // Wrap exception to add context information
                throw new DigestMismatchException("Damaged download: " + retrievalMethod, ex);
            }
            #endregion
        }
コード例 #51
0
        public void StressTest()
        {
            using (var packageDir = new TemporaryDirectory("0install-unit-tests"))
            {
                new PackageBuilder().AddFolder("subdir")
                    .AddFile("file", "AAA", new DateTime(2000, 1, 1))
                    .WritePackageInto(packageDir);

                var digest = new ManifestDigest(ManifestTest.CreateDotFile(packageDir, ManifestFormat.Sha256, _handler));

                Exception exception = null;
                var threads = new Thread[100];
                for (int i = 0; i < threads.Length; i++)
                {
                    threads[i] = new Thread(() =>
                    {
                        try
                        {
                            // ReSharper disable once AccessToDisposedClosure
                            _store.AddDirectory(packageDir, digest, _handler);
                            _store.Remove(digest, _handler);
                        }
                        catch (ImplementationAlreadyInStoreException)
                        {}
                        catch (ImplementationNotFoundException)
                        {}
                        catch (Exception ex)
                        {
                            exception = ex;
                        }
                    });
                    threads[i].Start();
                }

                foreach (var thread in threads)
                    thread.Join();
                if (exception != null)
                    Assert.Fail(exception.ToString());

                Assert.IsFalse(_store.Contains(digest));
            }
        }
コード例 #52
0
 /// <summary>
 /// Creates a new implementation not found exception.
 /// </summary>
 /// <param name="manifestDigest">The <see cref="ManifestDigest"/> of the <see cref="Store.Model.Implementation"/> to be found.</param>
 public ImplementationNotFoundException(ManifestDigest manifestDigest)
     : base(string.Format(Resources.ImplementationNotFound, manifestDigest))
 {
     ManifestDigest = manifestDigest;
 }
コード例 #53
0
        /// <summary>
        /// Creates a new GUI element for tracking a <see cref="ITask"/> for a specific implementation and returns a handle to it. May run multiple in parallel.
        /// </summary>
        /// <param name="taskName">The name of the task to be tracked.</param>
        /// <param name="tag">A digest used to associate the task with a specific implementation.</param>
        /// <remarks>This method must not be called from a background thread.</remarks>
        public IProgress<TaskSnapshot> SetupProgress(string taskName, ManifestDigest tag)
        {
            #region Sanity checks
            if (string.IsNullOrEmpty(taskName)) throw new ArgumentNullException("taskName");
            if (InvokeRequired) throw new InvalidOperationException("Method called from a non UI thread.");
            #endregion

            // Hide other stuff
            trackingControl.Hide();

            if (_selectionsShown)
            {
                var control = selectionsControl.TrackingControls[tag];
                control.TaskName = taskName;
                return new Progress<TaskSnapshot>(control.Report);
            }
            else return SetupProgress(taskName);
        }
コード例 #54
0
		public override void installPackageWithVerification (System.Uri packageURI, IPackageInstallObserver observer, int flags, string installerPackageName, System.Uri verificationURI, ManifestDigest manifestDigest)
		{
			throw new NotImplementedException ();
		}
コード例 #55
0
        public void ShouldRecreateMissingStoreDir()
        {
            Directory.Delete(_tempDir, recursive: true);

            using (var packageDir = new TemporaryDirectory("0install-unit-tests"))
            {
                var digest = new ManifestDigest(ManifestTest.CreateDotFile(packageDir, ManifestFormat.Sha256, _handler));
                _store.AddDirectory(packageDir, digest, _handler);

                Assert.IsTrue(_store.Contains(digest), "After adding, Store must contain the added package");
                CollectionAssert.AreEqual(new[] {digest}, _store.ListAll(), "After adding, Store must show the added package in the complete list");

                Assert.IsTrue(Directory.Exists(_tempDir), "Store directory should have been recreated");
            }
        }
コード例 #56
0
ファイル: IpcStore.cs プロジェクト: 0install/0install-win
 /// <summary>
 /// Does nothing. Should be handled by an <see cref="DirectoryStore"/> directly instead of using the service.
 /// </summary>
 public void Verify(ManifestDigest manifestDigest, ITaskHandler handler)
 {}
コード例 #57
0
ファイル: IpcStore.cs プロジェクト: 0install/0install-win
 /// <summary>
 /// Always returns <c>false</c>. Use a non-IPC <see cref="IStore"/> for this method instead.
 /// </summary>
 /// <remarks>Using the store service for this is unnecessary since it only requires read access to the file system.</remarks>
 public bool Contains(ManifestDigest manifestDigest)
 {
     return false;
 }
コード例 #58
0
        private TaskControl CreateTrackingControl(ManifestDigest manifestDigest)
        {
            var trackingControl = new TaskControl {Dock = DockStyle.Fill};
            trackingControl.CreateGraphics(); // Ensure control initialization even in tray icon mode

            int i = _selections.Implementations.FindIndex(x => x.ManifestDigest.PartialEquals(manifestDigest));
            tableLayout.Controls.Add(trackingControl, 2, i);

            return trackingControl;
        }
コード例 #59
0
 /// <summary>
 /// Creates a new implementation already in store exception.
 /// </summary>
 /// <param name="manifestDigest">The digest of the <see cref="Store.Model.Implementation"/> that was supposed to be added.</param>
 public ImplementationAlreadyInStoreException(ManifestDigest manifestDigest)
     : base(string.Format(Resources.ImplementationAlreadyInStore, manifestDigest))
 {
     ManifestDigest = manifestDigest;
 }
コード例 #60
0
        public void TestAuditPass()
        {
            using (var packageDir = new TemporaryDirectory("0install-unit-tests"))
            {
                new PackageBuilder().AddFolder("subdir")
                    .AddFile("file", "AAA", new DateTime(2000, 1, 1))
                    .WritePackageInto(packageDir);
                var digest = new ManifestDigest(ManifestTest.CreateDotFile(packageDir, ManifestFormat.Sha1New, _handler));
                _store.AddDirectory(packageDir, digest, _handler);

                _store.Verify(digest, _handler);
                Assert.IsNull(_handler.LastQuestion);
            }
        }