public static Tuple <Version, string> GetSuitableVersion(Context ctx, RemotePackageInfo remotePack, string dependant, VersionRange range) { var rangeMap = new Dictionary <VersionRange, HashSet <string> >(); // Value is for blaming packages rangeMap.Add(range, new HashSet <string>()); rangeMap[range].Add(dependant); // Collect version requirements of other installed packages foreach (LocalPackageInfo localPack in ctx.LocalRegistry.ListPackages(ctx)) { if (localPack.Dependencies.ContainsKey(remotePack.ID)) { if (!rangeMap.ContainsKey(localPack.Dependencies[remotePack.ID])) { rangeMap.Add(localPack.Dependencies[remotePack.ID], new HashSet <string>()); } rangeMap[localPack.Dependencies[remotePack.ID]].Add(localPack.PlainName); } } Tuple <VersionRange, string[]>[] rangeMapArray = rangeMap .OrderBy(pair => pair.Value.Count) .Select(pair => new Tuple <VersionRange, string[]>(pair.Key, pair.Value.ToArray())) .ToArray(); // Narrower the allowed range, from least common range to most common var allowedRange = new VersionRange(null, null); var rangesToBlame = new List <Tuple <VersionRange, string[]> >(); for (int i = 0; i < rangeMapArray.Length; i++) { Tuple <VersionRange, string[]> rangeItem = rangeMapArray[i]; var narrowResult = NarrowerRange(allowedRange, rangeItem.Item1); if (narrowResult.Item2) { allowedRange = narrowResult.Item1; rangesToBlame.Add(rangeItem); // Minimum greater than Maximum, or there is not a downloadable package sitting between the bounds if (!narrowResult.Item3 || !GetVersionInRange(remotePack.AvailableVersions, allowedRange).Item2) { throw new DependencyException(ctx, remotePack.PlainName, dependant, new RangeNotSatisfiableException(ctx, allowedRange, rangesToBlame)); } } } return(GetVersionInRange(remotePack.AvailableVersions, allowedRange).Item1); }
async Task fetchPack(Identifier id) { var ctx = new Context(localReg, remoteReg, i18n); RemotePackageInfo pack = await remoteReg.QueryPackage(ctx, id); if (pack == null || pack.AvailableVersions.Count < 1) { SelectedIdentifier = default(Identifier); btnOK.Enabled = false; showProgress("TODO: Not Found"); } else { SelectedIdentifier = pack.ID; btnOK.Enabled = true; showResult(); } inflateUI(pack); }
public async Task <IEnumerable <Tuple <Identifier, Version, string> > > DoFetch(Identifier id, VersionRange range, LogHandler logCallback, ProgressHandler progressCallback) { // TODO: Throw exception on circular reference var resolveQueue = new Queue <Tuple <Identifier, VersionRange, string> >(); var revInstallSequence = new List <Tuple <Identifier, Version, string> >(); resolveQueue.Enqueue(new Tuple <Identifier, VersionRange, string>(id, range, "")); while (resolveQueue.Count > 0) { var elem = resolveQueue.Dequeue(); RemotePackageInfo remotePack = null; if (!elem.Item1.HasGuid || !elem.Item1.HasName) { // Get the full identifier first, so that installed package can be queried better logCallback(LogLevel.Info, Translation.Translate("bpmcore_context_downloadmetadata", elem.Item1)); remotePack = await CachedQueryRemotePackage(elem.Item1); if (remotePack == null) { if (string.IsNullOrEmpty(elem.Item3)) { throw new PackageNotFoundException(this, elem.Item1); } else { throw new DependencyException(this, elem.Item1.ToString(), elem.Item3, new PackageNotFoundException(this, elem.Item1)); } } else { var newIdentifier = elem.Item1; if (!newIdentifier.HasGuid && remotePack.ID.HasGuid) { newIdentifier.Guid = remotePack.ID.Guid; newIdentifier.HasGuid = true; } if (!newIdentifier.HasName && remotePack.ID.HasName) { newIdentifier.Name = remotePack.ID.Name; newIdentifier.HasName = true; } elem = new Tuple <Identifier, VersionRange, string>(newIdentifier, elem.Item2, elem.Item3); } } var installedPackInfo = LocalRegistry.QueryInstalledPackage(this, elem.Item1); // Skip if the dependency is already installed and the version satisfies the requirement if (installedPackInfo != null && elem.Item2.ContainsVersion(installedPackInfo.Version)) { logCallback(LogLevel.Debug, Translation.Translate("bpmcore_context_alreadyinstalled", elem.Item1.ToString(), installedPackInfo.Version)); continue; } // Get the remote metadata if (remotePack == null) { logCallback(LogLevel.Info, Translation.Translate("bpmcore_context_downloadmetadata", elem.Item1)); remotePack = await CachedQueryRemotePackage(elem.Item1); if (remotePack == null) { if (string.IsNullOrEmpty(elem.Item3)) { throw new PackageNotFoundException(this, elem.Item1); } else { throw new DependencyException(this, elem.Item1.ToString(), elem.Item3, new PackageNotFoundException(this, elem.Item1)); } } } // Check other dependncies for a highest suitable version var installable = DependencyHelper.GetSuitableVersion(this, remotePack, elem.Item3, elem.Item2); logCallback(LogLevel.Info, Translation.Translate("bpmcore_context_willinstall", elem.Item1, installable.Item1)); if (installable.Item1 < remotePack.AvailableVersions.Keys.Last()) { logCallback(LogLevel.Warning, Translation.Translate("bpmcore_context_cannotlatest", remotePack.AvailableVersions.Keys.Last(), remotePack.ID)); } // Download the file from internet logCallback(LogLevel.Info, Translation.Translate("bpmcore_context_downloading", installable.Item2)); var tempFile = await DownloadManager.AcquirePackage(this, elem.Item1, installable.Item1, installable.Item2, progressCallback); // Push further dependencies into the queue var packInfo = LocalRegistry.QueryExternalPackage(this, tempFile); logCallback(LogLevel.Debug, Translation.Translate("bpmcore_context_requires", packInfo.ID, string.Join(",", packInfo.Dependencies.Select(t => t.Key.ToString() + t.Value)))); foreach (var dependency in packInfo.Dependencies) { resolveQueue.Enqueue(new Tuple <Identifier, VersionRange, string>(dependency.Key, dependency.Value, packInfo.PlainName)); } if (revInstallSequence.Any(t => t.Item3 == tempFile)) { revInstallSequence.Remove(revInstallSequence.Single(t => t.Item3 == tempFile)); } revInstallSequence.Add(new Tuple <Identifier, Version, string>(remotePack.ID, installable.Item1, tempFile)); } revInstallSequence.Reverse(); return(revInstallSequence); }
private void inflateUI(RemotePackageInfo pack) { var rangeTuple = DependencyHelper.GetSuitableRange(ctx, pack); var suitableRange = rangeTuple.Item1; var packagesToBlame = rangeTuple.Item2; Font biggerFont = new Font(this.Font.FontFamily, 14, FontStyle.Regular, GraphicsUnit.Pixel); infoPanel.Controls.Clear(); versionPanel.Controls.Clear(); if (pack == null) { return; } int rownum = 0; string[] blacklist = new[] { "Files", "AvailableVersions", "ForcePopup" }; infoPanel.SuspendLayout(); foreach (var prop in pack.GetType().GetProperties()) { var value = prop.GetValue(pack); if (blacklist.Contains(prop.Name)) { continue; } if (value == null) { continue; } infoPanel.Controls.Add(new Label() { Text = prop.Name, Font = biggerFont, ForeColor = accentColor, Margin = new Padding(3) }, 0, rownum); infoPanel.Controls.Add(new Label() { Text = value.ToString(), Font = biggerFont, Margin = new Padding(3) }, 1, rownum); rownum++; } infoPanel.ResumeLayout(); int vernum = 0; bool foundLatestAvailableVersion = false; foreach (var ver in pack.AvailableVersions.Reverse()) { var text = ver.Key.ToString(); if (vernum == 0) { text += " (Latest)"; } bool versionValid = suitableRange.ContainsVersion(ver.Key); if (versionValid && !foundLatestAvailableVersion && vernum > 0) { text += " (Latest Installable)"; } versionPanel.Controls.Add(new RadioButton() { Size = new Size(300, 30), Enabled = versionValid, Checked = versionValid && !foundLatestAvailableVersion, Font = biggerFont, Tag = ver.Key, Text = text }); foundLatestAvailableVersion |= versionValid; vernum++; } btnOK.Enabled = foundLatestAvailableVersion; bool hasWarning = !foundLatestAvailableVersion || !suitableRange.ContainsVersion(pack.AvailableVersions.Last().Key); if (hasWarning) { if (!mainTabControl.TabPages.Contains(tabPageWarning)) { mainTabControl.TabPages.Insert(0, tabPageWarning); } mainTabControl.SelectedIndex = 0; var sb = new System.Text.StringBuilder(); if (foundLatestAvailableVersion) { sb.AppendLine(I._("bpmcore_context_cannotlatest", pack.AvailableVersions.Keys.Last(), pack.ID)); } else { if (!suitableRange.NotEmpty) { sb.AppendLine(I._("bpmcore_exception_badrange1")); } else { sb.AppendLine(I._("bpmcore_exception_badrange2")); } } sb.AppendLine(I._("bpmcore_exception_blame")); foreach (var item in packagesToBlame) { sb.AppendLine(I._("bpmcore_exception_constraint", item.Item1.ToString(), string.IsNullOrEmpty(item.Item2[0]) ? I._("bpmcore_exception_userconstraint") : item.Item2[0], item.Item2.Length > 1 ? "...(" + (item.Item2.Length - 1).ToString() + "+)" : "")); } textWarn.Font = biggerFont; textWarn.Text = sb.ToString(); } else { if (mainTabControl.TabPages.Contains(tabPageWarning)) { mainTabControl.TabPages.Remove(tabPageWarning); } } }