using System; using System.Collections.Generic; using System.Reflection; namespace NaGet.Packages.Install { /// /// 依存関係を解決したりするための便利メソッド群 /// public sealed class DependeciesResolver { private DependeciesResolver() { } /// /// 依存解決済みInstallation配列を生成する /// /// 元のインストールリスト /// インストール確認などをおこなうパッケージリストのマネージャ /// 解決済みInstallation配列 /// 依存によって必要とされたInstallation配列。ない場合は空配列 public static void ResolveInstallations(Installation[] insts, PackageListsManager pkgListsMan, out Installation[] resolved, out Installation[] dependencies) { List depInsts; // 依存関係のインストールリスト depInsts = CreateRequiresInstallations(insts, pkgListsMan, null); dependencies = depInsts.ToArray(); // 依存解決をしたインストールリスト depInsts.AddRange(insts); resolved = depInsts.ToArray(); } /// /// Requires依存による依存パッケージの検索をし、それを解決するためのインストールリストを返す /// /// 対象インストールリスト /// 現在インストールされているか否かの判断に使われるパッケージリスト /// 優先して使用をするパッケージのリスト。nullでもよい /// Requires依存による依存 public static List CreateRequiresInstallations(Installation[] insts, PackageListsManager pkgListsMan, ICollection preferencial) { List reqInsts = new List(); foreach (Entry entry in DeleteDuplicatedEntries(CreateRequiresEntries(insts))) { List instPkgs = NaGet.Utils.MergeList( pkgListsMan.installedPkgList.GetPackagesForEntry(entry), pkgListsMan.systemInstalledPkgList.GetPackagesForEntry(entry) ); if (instPkgs.Count <= 0) { if (Array.Exists(insts, delegate(Installation inst) { return entry.Match(inst.InstalledPackage); })) { continue; } else { VersionComparetor vc = new VersionComparetor(); Package pkgToBeInstall = null; if (preferencial != null) { foreach (Package pkg in preferencial) { if (entry.Match(pkg)) { pkgToBeInstall = pkg; break; } } } if (pkgToBeInstall == null) { foreach (Package pkg in pkgListsMan.availablePkgList.GetPackagesForEntry(entry)) { if ((pkgToBeInstall == null) || (vc.Compare(pkgToBeInstall.Version, pkg.Version) < 0)) { pkgToBeInstall = pkg; } } } if (pkgToBeInstall != null) { reqInsts.Add(new Installation(pkgToBeInstall)); } } } } return reqInsts; } /// /// 与えられたエントリのイテレータに対し、重複しているものを取り除いて返す /// /// 現段階の実装では、重複の判断は名前のみである /// エントリのイテレータ /// 重複しているものを取り除いたエントリのイテレータ private static IEnumerable DeleteDuplicatedEntries(IEnumerable entries) { LinkedList pkgNames = new LinkedList(); foreach (Entry entry in entries) { if (! pkgNames.Contains(entry.Name)) { // 新出ならば返す yield return entry; pkgNames.AddFirst(entry.Name); } } } /// /// Requires依存エントリのイテレータを返す /// /// 現段階の実装では再帰的な依存は検索しない /// 対象のインストールリスト /// 依存エントリのイテレータ。重複に関して解決は行わない private static IEnumerable CreateRequiresEntries(Installation[] insts) { foreach (Installation inst in insts) { Entry[] deps = inst.InstalledPackage.Requires; if (deps == null) continue; foreach (Entry dep in deps) { yield return dep; } } } } }