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