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()); } } }
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); } }
/// <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); } }
/// <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(); }
/// <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); } }