Пример #1
0
        public Merge(Gothic gothic, MergeOptions options)
        {
            this.gothic  = gothic;
            this.options = options;

            if (options == MergeOptions.All)
            {
                mergingPatterns.Add("*");
                logPattern = "Merge.Merging".Translate() + ": {1}";
            }
            else
            {
                logPattern = "Merge.Merging".Translate() + " {0}: {1}";

                if (options.HasFlag(MergeOptions.Scripts))
                {
                    mergingPatterns.Add("*.d");
                    mergingPatterns.Add("*.src");
                    mergingOptions.Add("Scripts".Translate());
                }

                if (options.HasFlag(MergeOptions.Worlds))
                {
                    mergingPatterns.Add("*.zen");
                    mergingOptions.Add("Worlds".Translate());
                }

                if (options.HasFlag(MergeOptions.Sounds))
                {
                    mergingPatterns.Add("*.wav");
                    mergingOptions.Add("Sounds".Translate());
                }
            }
        }
Пример #2
0
        public void MergeAssets()
        {
            if (options == MergeOptions.All || options.HasFlag(MergeOptions.Scripts))
            {
                if (Program.Options.InvokedVerb != "pack" && Program.Options.TestVerb.NoReparse == false)
                {
                    new DirectoryHelper(gothic.GetGameDirectory(Gothic.GameDirectory.Scripts)).Delete();
                }
            }

            foreach (string directoryPath in Program.Config.ModFiles.Assets)
            {
                mergeDirectory(directoryPath);
            }
        }
Пример #3
0
        /// <summary>
        /// Determines the packages needed for merging, including dependencies if necessary.
        /// </summary>
        /// <param name="distarr">packages selected for merging</param>
        /// <param name="mopts">merge options</param>
        /// <param name="downloader">the downloader</param>
        /// <param name="scheduled">output list of packages scheduled for merge</param>
        private void ScheduleMerges(IDistribution[] distarr, MergeOptions mopts, Downloader downloader, 
            out List<MergeEventArgs> scheduled)
        {
            scheduled = new List<MergeEventArgs>();

            DependencyGraph dg = DependencyGraph.Compute(distarr);
            IDistribution[] distdeparr = dg.SortedNodes.ToArray();

            DependencyGraph.Conflict[] conflicts = dg.FindSlotConflicts();
            if (conflicts.Length > 0)
                throw new SlotConflictException(conflicts);

            for (int i = 0; i < distdeparr.Length; i++) {
                IDistribution dist = distdeparr[i];
                Atom current = _pkgmgr
                    .FindPackages(Atom.Parse(dist.Package.FullName, AtomParseOptions.WithoutVersion))
                    .Where(n => n.Slot == dist.Slot)
                    .SingleOrDefault();
                bool realselect = distarr.Contains(dist);

                if (!realselect && current != null && !mopts.HasFlag(MergeOptions.Deep) && dg.CheckSatisfies(current))
                    dist = dist.PortsTree.Lookup(current);

                MergeEventArgs mea = new MergeEventArgs();
                mea.Previous = current;
                mea.Selected = realselect && !mopts.HasFlag(MergeOptions.OneShot);
                mea.Distribution = dist;
                mea.FetchOnly = mopts.HasFlag(MergeOptions.FetchOnly);

                mea.HardMask = dist.PortsTree.IsHardMasked(dist);
                mea.KeywordMask = dist.PortsTree.IsKeywordMasked(dist);

                mea.KeywordsNeeded = dist.Keywords
                    .Where(kw => _cfg.AcceptKeywords.Contains(kw) ||
                                 _cfg.AcceptKeywords.Contains(Distribution.GetKeywordName(kw)))
                    .ToArray();

                if (!mopts.HasFlag(MergeOptions.Pretend) && (mea.HardMask || mea.KeywordMask))
                    throw new MaskedPackageException(dist.Package.FullName);

                if (current == null)
                    mea.Flags |= MergeFlags.New;
                if (!mea.Flags.HasFlag(MergeFlags.New) && current.Version == dist.Version)
                    mea.Flags |= MergeFlags.Replacing;
                if (!mea.Flags.HasFlag(MergeFlags.New) && !mea.Flags.HasFlag(MergeFlags.Replacing))
                    mea.Flags |= MergeFlags.Updating;
                if (!mea.Flags.HasFlag(MergeFlags.New) && current.Version > dist.Version)
                    mea.Flags |= MergeFlags.Downgrading;
                if (dist.Slot > 0)
                    mea.Flags |= MergeFlags.Slot;
                if (dist.Interactive)
                    mea.Flags |= MergeFlags.Interactive;
                /* TODO block */

                if (mea.Flags.HasFlag(MergeFlags.Updating))
                    mea.Selected = _pkgmgr.IsSelected(dist.Atom);

                if (dist.FetchRestriction && Distribution.CheckSourcesExist(dist, _cfg.DistFilesDir))
                    mea.Flags |= MergeFlags.FetchExists;
                else if (dist.FetchRestriction)
                    mea.Flags |= MergeFlags.FetchNeeded;

                if (mea.Flags.HasFlag(MergeFlags.Replacing) &&
                        (!realselect || mopts.HasFlag(MergeOptions.NoReplace)) && !mopts.HasFlag(MergeOptions.EmptyTree))
                    continue;

                if (mea.Flags.HasFlag(MergeFlags.FetchNeeded) && !mopts.HasFlag(MergeOptions.Pretend)) {
                    throw new InstallException("Fetch restriction is enabled for " + dist.ToString()
                        + "\nCopy the package archive into " + _cfg.DistFilesDir);
                }

                if (!(mea.Flags.HasFlag(MergeFlags.FetchExists) || mea.Flags.HasFlag(MergeFlags.FetchNeeded)))
                    mea.FetchHandle = downloader.Enqueue(dist);

                scheduled.Add(mea);
            }
        }
Пример #4
0
        /// <summary>
        /// Merge a single package into the system.
        /// </summary>
        /// <param name="mea">merge event arguments</param>
        /// <param name="mopts">merge options</param>
        /// <param name="downloader">the downloader</param>
        /// <param name="rootdir">root directory</param>
        private void MergeOne(MergeEventArgs mea, MergeOptions mopts, Downloader downloader, DirectoryInfo rootdir)
        {
            IDistribution dist = mea.Distribution;
            uint rc = 0;

            if (mopts.HasFlag(MergeOptions.Pretend)) {
                if (this.OnPretendMerge != null)
                    this.OnPretendMerge.Invoke(this, mea);

                return;
            }

            if (this.OnRealMerge != null)
                this.OnRealMerge.Invoke(this, mea);

            if (mea.HardMask || mea.KeywordMask)
                throw new MaskedPackageException(mea.Distribution.Package.FullName);

            if (dist.PlatformSources.Length > 0) {
                if (mea.FetchHandle != Guid.Empty && !downloader.Peek(mea.FetchHandle)) {
                    _log.Info("Fetching files in the background... please wait");
                    _log.InfoFormat("See {0} for fetch progress", downloader.LogFile);
                    downloader.WaitFor(mea.FetchHandle);
                }

                _log.InfoFormat("Checking package digests");

                foreach (SourceFile src in dist.PlatformSources) {
                    FileInfo distfile = new FileInfo(_cfg.DistFilesDir + @"\" + src.LocalName);

                    if (!Md5Sum.Check(distfile.FullName, src.Digest, Md5Sum.MD5SUMMODE.BINARY)) {
                        _log.ErrorFormat("Digest check failed for {0}", distfile.FullName);
                        throw new InstallException("Computed digest doesn't match expected value.");
                    }
                }
            }

            if (mopts.HasFlag(MergeOptions.FetchOnly))
                return;

            SandboxDirectory sbox = SandboxDirectory.Create();
            _log.DebugFormat("Created sandbox directory: {0}", sbox.Root.FullName);

            IInstallProject installer = dist.GetInstallProject(sbox);
            if (installer == null)
                throw new InstallException("Encountered missing or invalid installer project.");

            bool runmake = installer.HasSrcUnpackTarget ||
                           installer.HasSrcCompileTarget ||
                           installer.HasSrcInstallTarget ||
                           installer.HasSrcTestTarget;
            if (runmake && (rc = this.SpawnSandboxHost(sbox, installer)) != 0) {
                _log.DebugFormat("sandbox host return code: {0}", rc);
                throw new InstallException("Installation failed. See previous errors.");
            }

            if (this.OnInstall != null)
                this.OnInstall.Invoke(this, mea);

            if (_cfg.CollisionDetect && this.DetectCollisions(sbox.ImageDir, dist.Atom))
                throw new InstallException("File collision(s) were detected.");

            if (mea.Previous != null) {
                _log.Debug("Trashing files from previous installation");
                FileTuple[] oldfiles = _pkgmgr.QueryPackageFiles(mea.Previous);

                foreach (FileTuple ft in oldfiles) {
                    if (ft.Item2 != FileType.Directory || !this.IsProtected(ft.Item1))
                        TrashWorker.AddFile(ft.Item1, _pkgmgr);
                }
            }

            FileTuple[] files = null;
            FileTuple[] shortcuts = null;

            if (installer.HasPkgPreInstTarget) {
                _log.Info("Executing pre-install tasks...");
                installer.PkgPreInst();
            }

            IntPtr wow64oldval = IntPtr.Zero;
            if (Environment.Is64BitOperatingSystem && !Environment.Is64BitProcess) {
                if (!Wow64DisableWow64FsRedirection(out wow64oldval))
                    throw new InstallException("Failed to disable Wow64 file system redirection.");
            }

            try {
                this.InstallImage(sbox.ImageDir, rootdir, out files);
            } finally {
                if (Environment.Is64BitOperatingSystem && !Environment.Is64BitProcess)
                    Wow64RevertWow64FsRedirection(wow64oldval);
            }

            this.InstallImage(
                sbox.LinkDir,
                new DirectoryInfo(Environment.GetFolderPath(Environment.SpecialFolder.CommonStartMenu)),
                out shortcuts);

            FileTuple[] allfiles = files.Union(shortcuts).ToArray();
            Dictionary<string, string> metadata = new Dictionary<string, string>();
            metadata.Add("repository", dist.PortsTree.Repository);
            _pkgmgr.RecordPackage(dist, installer, allfiles, metadata.ToArray());

            if (installer.HasPkgPostInstTarget) {
                _log.Info("Executing post-install tasks...");
                installer.PkgPostInst();
            }

            if (mea.Selected) {
                _log.InfoFormat("Recording {0} in world favourites", dist.Package.FullName);
                _pkgmgr.SelectPackage(dist.Atom);
            }

            _log.Debug("Destroying the sandbox...");
            sbox.Delete();
        }
Пример #5
0
        /// <summary>
        /// Merges the given distributions into the system.
        /// </summary>
        /// <param name="distarr">the distributions to merge</param>
        /// <param name="mopts">merge option flags</param>
        public void Merge(IDistribution[] distarr, MergeOptions mopts)
        {
            if (distarr.Length == 0)
                return;

            Downloader downloader = new Downloader(_cfg.DistFilesDir);
            List<MergeEventArgs> scheduled = null;

            this.ScheduleMerges(distarr, mopts, downloader, out scheduled);

            if (!mopts.HasFlag(MergeOptions.Pretend)) {
                if (this.OnParallelFetch != null)
                    this.OnParallelFetch.Invoke(this, new EventArgs());

                downloader.FetchAsync();
            }

            for (int i = 0; i < scheduled.Count; i++) {
                MergeEventArgs mea = scheduled[i];
                mea.CurrentIter = i + 1;
                mea.TotalMerges = scheduled.Count;

                this.MergeOne(mea, mopts, downloader, _pkgmgr.RootDir);
            }

            if (!mopts.HasFlag(MergeOptions.Pretend)) {
                if (this.OnAutoClean != null)
                    this.OnAutoClean.Invoke(this, new EventArgs());

                TrashWorker.Purge(_pkgmgr);
            }
        }