private void BuildTree() { // default all packages to being roots roots = new List <NugetPackage>(installedPackages); // remove a package as a root if another package is dependent on it foreach (NugetPackage package in installedPackages) { NugetFrameworkGroup frameworkGroup = NugetHelper.GetBestDependencyFrameworkGroupForCurrentSettings(package); foreach (NugetPackageIdentifier dependency in frameworkGroup.Dependencies) { roots.RemoveAll(p => p.Id == dependency.Id); } } }
private void DrawPackage(NugetPackage package) { if (package.Dependencies != null && package.Dependencies.Count > 0) { expanded[package] = EditorGUILayout.Foldout(expanded[package], string.Format("{0} {1}", package.Id, package.Version)); if (expanded[package]) { EditorGUI.indentLevel++; NugetFrameworkGroup frameworkGroup = NugetHelper.GetBestDependencyFrameworkGroupForCurrentSettings(package); foreach (NugetPackageIdentifier dependency in frameworkGroup.Dependencies) { DrawDepencency(dependency); } EditorGUI.indentLevel--; } } else { EditorGUILayout.LabelField(string.Format("{0} {1}", package.Id, package.Version)); } }
/// <summary> /// Parses the given <see cref="XDocument"/> and returns the list of <see cref="NugetPackage"/>s contained within. /// </summary> /// <param name="document">The <see cref="XDocument"/> that is the OData XML response from the NuGet server.</param> /// <returns>The list of <see cref="NugetPackage"/>s read from the given XML.</returns> public static List <NugetPackage> Parse(XDocument document) { List <NugetPackage> packages = new List <NugetPackage>(); var packageEntries = document.Root.Elements(XName.Get("entry", AtomNamespace)); foreach (var entry in packageEntries) { NugetPackage package = new NugetPackage(); package.Id = entry.GetAtomElement("title").Value; package.DownloadUrl = entry.GetAtomElement("content").Attribute("src").Value; var entryProperties = entry.Element(XName.Get("properties", MetaDataNamespace)); package.Title = entryProperties.GetProperty("Title"); package.Version = entryProperties.GetProperty("Version"); package.Description = entryProperties.GetProperty("Description"); package.ReleaseNotes = entryProperties.GetProperty("ReleaseNotes"); package.LicenseUrl = entryProperties.GetProperty("LicenseUrl"); package.ProjectUrl = entryProperties.GetProperty("ProjectUrl"); string iconUrl = entryProperties.GetProperty("IconUrl"); if (!string.IsNullOrEmpty(iconUrl)) { NugetImageLoader.TryDownloadImage(iconUrl, tex => { package.Icon = tex; }); } // if there is no title, just use the ID as the title if (string.IsNullOrEmpty(package.Title)) { package.Title = package.Id; } // Get dependencies package.Dependencies = new List <NugetPackageIdentifier>(); string rawDependencies = entryProperties.GetProperty("Dependencies"); if (!string.IsNullOrEmpty(rawDependencies)) { var dependencyGroups = new Dictionary <string, NugetFrameworkGroup>(); string[] dependencies = rawDependencies.Split('|'); foreach (var dependencyString in dependencies) { string[] details = dependencyString.Split(':'); var dependency = new NugetPackageIdentifier(details[0], details[1]); // some packages (ex: FSharp.Data - 2.1.0) have inproper "semi-empty" dependencies such as: // "Zlib.Portable:1.10.0:portable-net40+sl50+wp80+win80|::net40" // so we need to only add valid dependencies and skip invalid ones if (string.IsNullOrEmpty(dependency.Id) && string.IsNullOrEmpty(dependency.Version)) { continue; } string framework = string.Empty; if (details.Length > 2) { framework = details[2]; } NugetFrameworkGroup group; if (dependencyGroups.TryGetValue(framework, out group)) { group.Dependencies.Add(dependency); } else { group = new NugetFrameworkGroup(); group.Dependencies = new List <NugetPackageIdentifier>(); group.Dependencies.Add(dependency); dependencyGroups.Add(framework, group); } } // find the correct group for this project int intDotNetVersion = (int)NugetHelper.DotNetVersion; //bool using46 = DotNetVersion == ApiCompatibilityLevel.NET_4_6; // NET_4_6 option was added in Unity 5.6 bool using46 = intDotNetVersion == 3; // NET_4_6 = 3 in Unity 5.6 and Unity 2017.1 - use the hard-coded int value to ensure it works in earlier versions of Unity NugetFrameworkGroup selectedGroup = null; foreach (var kvPair in dependencyGroups.OrderByDescending(x => x.Key)) { string framework = kvPair.Key; NugetFrameworkGroup group = kvPair.Value; // Select the highest .NET library available that is supported // See here: https://docs.nuget.org/ndocs/schema/target-frameworks if (using46 && framework == "net462") { selectedGroup = group; break; } else if (using46 && framework == "net461") { selectedGroup = group; break; } else if (using46 && framework == "net46") { selectedGroup = group; break; } else if (using46 && framework == "net452") { selectedGroup = group; break; } else if (using46 && framework == "net451") { selectedGroup = group; break; } else if (using46 && framework == "net45") { selectedGroup = group; break; } else if (using46 && framework == "net403") { selectedGroup = group; break; } else if (using46 && (framework == "net40" || framework == "net4")) { selectedGroup = group; break; } else if (framework == "net35") { selectedGroup = group; break; } else if (framework == "net20") { selectedGroup = group; break; } else if (framework == "net11") { selectedGroup = group; break; } else if (framework == string.Empty) { selectedGroup = group; break; } } if (selectedGroup != null) { package.Dependencies = selectedGroup.Dependencies; } } packages.Add(package); } return(packages); }
/// <summary> /// Loads a .nuspec file inside the given <see cref="XDocument"/>. /// </summary> /// <param name="nuspecDocument">The .nuspec file as an <see cref="XDocument"/>.</param> /// <returns>The newly loaded <see cref="NuspecFile"/>.</returns> public static NuspecFile Load(XDocument nuspecDocument) { NuspecFile nuspec = new NuspecFile(); string nuspecNamespace = nuspecDocument.Root.GetDefaultNamespace().ToString(); XElement package = nuspecDocument.Element(XName.Get("package", nuspecNamespace)); XElement metadata = package.Element(XName.Get("metadata", nuspecNamespace)); nuspec.Id = (string)metadata.Element(XName.Get("id", nuspecNamespace)) ?? string.Empty; nuspec.Version = (string)metadata.Element(XName.Get("version", nuspecNamespace)) ?? string.Empty; nuspec.Title = (string)metadata.Element(XName.Get("title", nuspecNamespace)) ?? string.Empty; nuspec.Authors = (string)metadata.Element(XName.Get("authors", nuspecNamespace)) ?? string.Empty; nuspec.Owners = (string)metadata.Element(XName.Get("owners", nuspecNamespace)) ?? string.Empty; nuspec.LicenseUrl = (string)metadata.Element(XName.Get("licenseUrl", nuspecNamespace)) ?? string.Empty; nuspec.ProjectUrl = (string)metadata.Element(XName.Get("projectUrl", nuspecNamespace)) ?? string.Empty; nuspec.IconUrl = (string)metadata.Element(XName.Get("iconUrl", nuspecNamespace)) ?? string.Empty; nuspec.RequireLicenseAcceptance = bool.Parse((string)metadata.Element(XName.Get("requireLicenseAcceptance", nuspecNamespace)) ?? "False"); nuspec.Description = (string)metadata.Element(XName.Get("description", nuspecNamespace)) ?? string.Empty; nuspec.Summary = (string)metadata.Element(XName.Get("summary", nuspecNamespace)) ?? string.Empty; nuspec.ReleaseNotes = (string)metadata.Element(XName.Get("releaseNotes", nuspecNamespace)) ?? string.Empty; nuspec.Copyright = (string)metadata.Element(XName.Get("copyright", nuspecNamespace)); nuspec.Tags = (string)metadata.Element(XName.Get("tags", nuspecNamespace)) ?? string.Empty; var repositoryElement = metadata.Element(XName.Get("repository", nuspecNamespace)); if (repositoryElement != null) { nuspec.RepositoryType = (string)repositoryElement.Attribute(XName.Get("type")) ?? string.Empty; nuspec.RepositoryUrl = (string)repositoryElement.Attribute(XName.Get("url")) ?? string.Empty; nuspec.RepositoryBranch = (string)repositoryElement.Attribute(XName.Get("branch")) ?? string.Empty; nuspec.RepositoryCommit = (string)repositoryElement.Attribute(XName.Get("commit")) ?? string.Empty; } var dependenciesElement = metadata.Element(XName.Get("dependencies", nuspecNamespace)); if (dependenciesElement != null) { // Dependencies specified for specific target frameworks foreach (var frameworkGroup in dependenciesElement.Elements(XName.Get("group", nuspecNamespace))) { NugetFrameworkGroup group = new NugetFrameworkGroup(); group.TargetFramework = ConvertFromNupkgTargetFrameworkName((string)frameworkGroup.Attribute("targetFramework") ?? string.Empty); foreach (var dependencyElement in frameworkGroup.Elements(XName.Get("dependency", nuspecNamespace))) { NugetPackageIdentifier dependency = new NugetPackageIdentifier(); dependency.Id = (string)dependencyElement.Attribute("id") ?? string.Empty; dependency.Version = (string)dependencyElement.Attribute("version") ?? string.Empty; group.Dependencies.Add(dependency); } nuspec.Dependencies.Add(group); } // Flat dependency list if (nuspec.Dependencies.Count == 0) { NugetFrameworkGroup group = new NugetFrameworkGroup(); foreach (var dependencyElement in dependenciesElement.Elements(XName.Get("dependency", nuspecNamespace))) { NugetPackageIdentifier dependency = new NugetPackageIdentifier(); dependency.Id = (string)dependencyElement.Attribute("id") ?? string.Empty; dependency.Version = (string)dependencyElement.Attribute("version") ?? string.Empty; group.Dependencies.Add(dependency); } nuspec.Dependencies.Add(group); } } var filesElement = package.Element(XName.Get("files", nuspecNamespace)); if (filesElement != null) { //UnityEngine.Debug.Log("Loading files!"); foreach (var fileElement in filesElement.Elements(XName.Get("file", nuspecNamespace))) { NuspecContentFile file = new NuspecContentFile(); file.Source = (string)fileElement.Attribute("src") ?? string.Empty; file.Target = (string)fileElement.Attribute("target") ?? string.Empty; nuspec.Files.Add(file); } } return(nuspec); }
/// <summary> /// Draws the given <see cref="NugetPackage"/>. /// </summary> /// <param name="package">The <see cref="NugetPackage"/> to draw.</param> private void DrawPackage(NugetPackage package, GUIStyle packageStyle, GUIStyle contrastStyle) { IEnumerable <NugetPackage> installedPackages = NugetHelper.InstalledPackages; var installed = installedPackages.FirstOrDefault(p => p.Id == package.Id); EditorGUILayout.BeginHorizontal(); { // The Unity GUI system (in the Editor) is terrible. This probably requires some explanation. // Every time you use a Horizontal block, Unity appears to divide the space evenly. // (i.e. 2 components have half of the window width, 3 components have a third of the window width, etc) // GUILayoutUtility.GetRect is SUPPOSED to return a rect with the given height and width, but in the GUI layout. It doesn't. // We have to use GUILayoutUtility to get SOME rect properties, but then manually calculate others. EditorGUILayout.BeginHorizontal(); { const int iconSize = 32; int padding = EditorStyles.label.padding.vertical; Rect rect = GUILayoutUtility.GetRect(iconSize, iconSize); // only use GetRect's Y position. It doesn't correctly set the width, height or X position. rect.x = padding; rect.y += padding; rect.width = iconSize; rect.height = iconSize; if (package.Icon != null) { GUI.DrawTexture(rect, package.Icon, ScaleMode.StretchToFill); } else { GUI.DrawTexture(rect, defaultIcon, ScaleMode.StretchToFill); } rect.x = iconSize + 2 * padding; rect.width = position.width / 2 - (iconSize + padding); rect.y -= padding; // This will leave the text aligned with the top of the image EditorStyles.label.fontStyle = FontStyle.Bold; EditorStyles.label.fontSize = 16; Vector2 idSize = EditorStyles.label.CalcSize(new GUIContent(package.Id)); rect.y += (iconSize / 2 - idSize.y / 2) + padding; GUI.Label(rect, package.Id, EditorStyles.label); rect.x += idSize.x; EditorStyles.label.fontSize = 10; EditorStyles.label.fontStyle = FontStyle.Normal; Vector2 versionSize = EditorStyles.label.CalcSize(new GUIContent(package.Version)); rect.y += (idSize.y - versionSize.y - padding / 2); if (!string.IsNullOrEmpty(package.Authors)) { string authorLabel = string.Format("by {0}", package.Authors); Vector2 size = EditorStyles.label.CalcSize(new GUIContent(authorLabel)); GUI.Label(rect, authorLabel, EditorStyles.label); rect.x += size.x; } if (package.DownloadCount > 0) { string downloadLabel = string.Format("{0} downloads", package.DownloadCount.ToString("#,#")); Vector2 size = EditorStyles.label.CalcSize(new GUIContent(downloadLabel)); GUI.Label(rect, downloadLabel, EditorStyles.label); rect.x += size.x; } } GUILayout.FlexibleSpace(); if (installed != null && installed.Version != package.Version) { GUILayout.Label(string.Format("Current Version {0}", installed.Version)); } GUILayout.Label(string.Format("Version {0}", package.Version)); if (installedPackages.Contains(package)) { // This specific version is installed if (GUILayout.Button("Uninstall")) { // TODO: Perhaps use a "mark as dirty" system instead of updating all of the data all the time? NugetHelper.Uninstall(package); NugetHelper.UpdateInstalledPackages(); UpdateUpdatePackages(); } } else { if (installed != null) { if (installed < package) { // An older version is installed if (GUILayout.Button("Update")) { NugetHelper.Update(installed, package); NugetHelper.UpdateInstalledPackages(); UpdateUpdatePackages(); } } else if (installed > package) { // A newer version is installed if (GUILayout.Button("Downgrade")) { NugetHelper.Update(installed, package); NugetHelper.UpdateInstalledPackages(); UpdateUpdatePackages(); } } } else { if (GUILayout.Button("Install")) { NugetHelper.InstallIdentifier(package); AssetDatabase.Refresh(); NugetHelper.UpdateInstalledPackages(); UpdateUpdatePackages(); } } } EditorGUILayout.EndHorizontal(); } EditorGUILayout.EndHorizontal(); EditorGUILayout.Space(); EditorGUILayout.BeginHorizontal(); { EditorGUILayout.BeginVertical(); { // Show the package details EditorStyles.label.wordWrap = true; EditorStyles.label.fontStyle = FontStyle.Normal; string summary = package.Summary; if (string.IsNullOrEmpty(summary)) { summary = package.Description; } if (!package.Title.Equals(package.Id, StringComparison.InvariantCultureIgnoreCase)) { summary = string.Format("{0} - {1}", package.Title, summary); } if (summary.Length >= 240) { summary = string.Format("{0}...", summary.Substring(0, 237)); } EditorGUILayout.LabelField(summary); bool detailsFoldout; string detailsFoldoutId = string.Format("{0}.{1}", package.Id, "Details"); if (!foldouts.TryGetValue(detailsFoldoutId, out detailsFoldout)) { foldouts[detailsFoldoutId] = detailsFoldout; } detailsFoldout = EditorGUILayout.Foldout(detailsFoldout, "Details"); foldouts[detailsFoldoutId] = detailsFoldout; if (detailsFoldout) { EditorGUI.indentLevel++; if (!string.IsNullOrEmpty(package.Description)) { EditorGUILayout.LabelField("Description", EditorStyles.boldLabel); EditorGUILayout.LabelField(package.Description); } if (!string.IsNullOrEmpty(package.ReleaseNotes)) { EditorGUILayout.LabelField("Release Notes", EditorStyles.boldLabel); EditorGUILayout.LabelField(package.ReleaseNotes); } // Show project URL link if (!string.IsNullOrEmpty(package.ProjectUrl)) { EditorGUILayout.LabelField("Project Url", EditorStyles.boldLabel); GUILayoutLink(package.ProjectUrl); GUILayout.Space(4f); } // Show the dependencies if (package.Dependencies.Count > 0) { EditorStyles.label.wordWrap = true; EditorStyles.label.fontStyle = FontStyle.Italic; StringBuilder builder = new StringBuilder(); NugetFrameworkGroup frameworkGroup = NugetHelper.GetBestDependencyFrameworkGroupForCurrentSettings(package); foreach (var dependency in frameworkGroup.Dependencies) { builder.Append(string.Format(" {0} {1};", dependency.Id, dependency.Version)); } EditorGUILayout.Space(); EditorGUILayout.LabelField(string.Format("Depends on:{0}", builder.ToString())); EditorStyles.label.fontStyle = FontStyle.Normal; } // Create the style for putting a box around the 'Clone' button var cloneButtonBoxStyle = new GUIStyle("box"); cloneButtonBoxStyle.stretchWidth = false; cloneButtonBoxStyle.margin.top = 0; cloneButtonBoxStyle.margin.bottom = 0; cloneButtonBoxStyle.padding.bottom = 4; var normalButtonBoxStyle = new GUIStyle(cloneButtonBoxStyle); normalButtonBoxStyle.normal.background = packageStyle.normal.background; bool showCloneWindow = openCloneWindows.Contains(package); cloneButtonBoxStyle.normal.background = showCloneWindow ? contrastStyle.normal.background : packageStyle.normal.background; // Create a simillar style for the 'Clone' window var cloneWindowStyle = new GUIStyle(cloneButtonBoxStyle); cloneWindowStyle.padding = new RectOffset(6, 6, 2, 6); // Show button bar EditorGUILayout.BeginHorizontal(); { if (package.RepositoryType == RepositoryType.Git || package.RepositoryType == RepositoryType.TfsGit) { if (!string.IsNullOrEmpty(package.RepositoryUrl)) { EditorGUILayout.BeginHorizontal(cloneButtonBoxStyle); { var cloneButtonStyle = new GUIStyle(GUI.skin.button); cloneButtonStyle.normal = showCloneWindow ? cloneButtonStyle.active : cloneButtonStyle.normal; if (GUILayout.Button("Clone", cloneButtonStyle, GUILayout.ExpandWidth(false))) { showCloneWindow = !showCloneWindow; } if (showCloneWindow) { openCloneWindows.Add(package); } else { openCloneWindows.Remove(package); } } EditorGUILayout.EndHorizontal(); } } if (!string.IsNullOrEmpty(package.LicenseUrl) && package.LicenseUrl != "http://your_license_url_here") { // Creaete a box around the license button to keep it alligned with Clone button EditorGUILayout.BeginHorizontal(normalButtonBoxStyle); // Show the license button if (GUILayout.Button("View License", GUILayout.ExpandWidth(false))) { Application.OpenURL(package.LicenseUrl); } EditorGUILayout.EndHorizontal(); } } EditorGUILayout.EndHorizontal(); if (showCloneWindow) { EditorGUILayout.BeginVertical(cloneWindowStyle); { // Clone latest label EditorGUILayout.BeginHorizontal(); GUILayout.Space(20f); EditorGUILayout.LabelField("clone latest"); EditorGUILayout.EndHorizontal(); // Clone latest row EditorGUILayout.BeginHorizontal(); { if (GUILayout.Button("Copy", GUILayout.ExpandWidth(false))) { GUI.FocusControl(package.Id + package.Version + "repoUrl"); GUIUtility.systemCopyBuffer = package.RepositoryUrl; } GUI.SetNextControlName(package.Id + package.Version + "repoUrl"); EditorGUILayout.TextField(package.RepositoryUrl); } EditorGUILayout.EndHorizontal(); // Clone @ commit label GUILayout.Space(4f); EditorGUILayout.BeginHorizontal(); GUILayout.Space(20f); EditorGUILayout.LabelField("clone @ commit"); EditorGUILayout.EndHorizontal(); // Clone @ commit row EditorGUILayout.BeginHorizontal(); { // Create the three commands a user will need to run to get the repo @ the commit. Intentionally leave off the last newline for better UI appearance string commands = string.Format("git clone {0} {1} --no-checkout{2}cd {1}{2}git checkout {3}", package.RepositoryUrl, package.Id, Environment.NewLine, package.RepositoryCommit); if (GUILayout.Button("Copy", GUILayout.ExpandWidth(false))) { GUI.FocusControl(package.Id + package.Version + "commands"); // Add a newline so the last command will execute when pasted to the CL GUIUtility.systemCopyBuffer = (commands + Environment.NewLine); } EditorGUILayout.BeginVertical(); GUI.SetNextControlName(package.Id + package.Version + "commands"); EditorGUILayout.TextArea(commands); EditorGUILayout.EndVertical(); } EditorGUILayout.EndHorizontal(); } EditorGUILayout.EndVertical(); } EditorGUI.indentLevel--; } EditorGUILayout.Separator(); EditorGUILayout.Separator(); } EditorGUILayout.EndVertical(); } EditorGUILayout.EndHorizontal(); }
/// <summary> /// Automatically called by Unity to draw the GUI. /// </summary> protected void OnGUI() { currentTab = GUILayout.Toolbar(currentTab, tabTitles); switch (currentTab) { case 0: scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition); foreach (NugetPackage package in roots) { DrawPackage(package); } EditorGUILayout.EndScrollView(); break; case 1: EditorStyles.label.fontStyle = FontStyle.Bold; EditorStyles.label.fontSize = 14; EditorGUILayout.LabelField("Select Dependency:", GUILayout.Height(20)); EditorStyles.label.fontStyle = FontStyle.Normal; EditorStyles.label.fontSize = 10; EditorGUI.indentLevel++; int newIndex = EditorGUILayout.Popup(selectedPackageIndex, installedPackageIds); EditorGUI.indentLevel--; if (newIndex != selectedPackageIndex) { selectedPackageIndex = newIndex; parentPackages.Clear(); NugetPackage selectedPackage = installedPackages[selectedPackageIndex]; foreach (var package in installedPackages) { NugetFrameworkGroup frameworkGroup = NugetHelper.GetBestDependencyFrameworkGroupForCurrentSettings(package); foreach (var dependency in frameworkGroup.Dependencies) { if (dependency.Id == selectedPackage.Id) { parentPackages.Add(package); } } } } EditorGUILayout.Space(); EditorStyles.label.fontStyle = FontStyle.Bold; EditorStyles.label.fontSize = 14; EditorGUILayout.LabelField("Packages That Depend on Above:", GUILayout.Height(20)); EditorStyles.label.fontStyle = FontStyle.Normal; EditorStyles.label.fontSize = 10; scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition); EditorGUI.indentLevel++; if (parentPackages.Count <= 0) { EditorGUILayout.LabelField("NONE"); } else { foreach (var parent in parentPackages) { //EditorGUILayout.LabelField(string.Format("{0} {1}", parent.Id, parent.Version)); DrawPackage(parent); } } EditorGUI.indentLevel--; EditorGUILayout.EndScrollView(); break; } }
/// <summary> /// Use the Unity GUI to draw the controls. /// </summary> protected void OnGUI() { if (nuspec == null) { Reload(); } if (nuspec == null) { titleContent = new GUIContent("[NO NUSPEC]"); EditorGUILayout.LabelField("There is no .nuspec file selected."); } else { EditorGUIUtility.labelWidth = 100; nuspec.Id = EditorGUILayout.TextField(new GUIContent("ID", "The name of the package."), nuspec.Id); nuspec.Version = EditorGUILayout.TextField(new GUIContent("Version", "The semantic version of the package."), nuspec.Version); nuspec.Authors = EditorGUILayout.TextField(new GUIContent("Authors", "The authors of the package."), nuspec.Authors); nuspec.Owners = EditorGUILayout.TextField(new GUIContent("Owners", "The owners of the package."), nuspec.Owners); nuspec.LicenseUrl = EditorGUILayout.TextField(new GUIContent("License URL", "The URL for the license of the package."), nuspec.LicenseUrl); nuspec.ProjectUrl = EditorGUILayout.TextField(new GUIContent("Project URL", "The URL of the package project."), nuspec.ProjectUrl); nuspec.IconUrl = EditorGUILayout.TextField(new GUIContent("Icon URL", "The URL for the icon of the package."), nuspec.IconUrl); nuspec.RequireLicenseAcceptance = EditorGUILayout.Toggle(new GUIContent("Require License Acceptance", "Does the package license need to be accepted before use?"), nuspec.RequireLicenseAcceptance); nuspec.Description = EditorGUILayout.TextField(new GUIContent("Description", "The description of the package."), nuspec.Description); nuspec.Summary = EditorGUILayout.TextField(new GUIContent("Summary", "The brief description of the package."), nuspec.Summary); nuspec.ReleaseNotes = EditorGUILayout.TextField(new GUIContent("Release Notes", "The release notes for this specific version of the package."), nuspec.ReleaseNotes); nuspec.Copyright = EditorGUILayout.TextField(new GUIContent("Copyright", "The copyright details for the package."), nuspec.Copyright); nuspec.Tags = EditorGUILayout.TextField(new GUIContent("Tags", "The space-delimited list of tags and keywords that describe the package and aid discoverability of packages through search and filtering."), nuspec.Tags); dependenciesExpanded = EditorGUILayout.Foldout(dependenciesExpanded, new GUIContent("Dependencies", "The list of NuGet packages that this packages depends on.")); if (dependenciesExpanded) { EditorGUILayout.BeginHorizontal(); { GUILayout.Space(50); // automatically fill in the dependencies based upon the "root" packages currently installed in the project if (GUILayout.Button(new GUIContent("Automatically Fill Dependencies", "Populates the list of dependencies with the \"root\" NuGet packages currently installed in the project."))) { NugetHelper.UpdateInstalledPackages(); List <NugetPackage> installedPackages = NugetHelper.InstalledPackages.ToList(); // default all packages to being roots List <NugetPackage> roots = new List <NugetPackage>(installedPackages); // remove a package as a root if another package is dependent on it foreach (NugetPackage package in installedPackages) { NugetFrameworkGroup packageFrameworkGroup = NugetHelper.GetBestDependencyFrameworkGroupForCurrentSettings(package); foreach (NugetPackageIdentifier dependency in packageFrameworkGroup.Dependencies) { roots.RemoveAll(p => p.Id == dependency.Id); } } // remove all existing dependencies from the .nuspec nuspec.Dependencies.Clear(); nuspec.Dependencies.Add(new NugetFrameworkGroup()); nuspec.Dependencies[0].Dependencies = roots.Cast <NugetPackageIdentifier>().ToList(); } } EditorGUILayout.EndHorizontal(); // display the dependencies NugetPackageIdentifier toDelete = null; NugetFrameworkGroup nuspecFrameworkGroup = NugetHelper.GetBestDependencyFrameworkGroupForCurrentSettings(nuspec); foreach (var dependency in nuspecFrameworkGroup.Dependencies) { EditorGUILayout.BeginHorizontal(); GUILayout.Space(75); float prevLabelWidth = EditorGUIUtility.labelWidth; EditorGUIUtility.labelWidth = 50; dependency.Id = EditorGUILayout.TextField(new GUIContent("ID", "The ID of the dependency package."), dependency.Id); EditorGUILayout.EndHorizontal(); //int oldSeletedIndex = IndexOf(ref existingComponents, dependency.Id); //int newSelectIndex = EditorGUILayout.Popup("Name", oldSeletedIndex, existingComponents); //if (oldSeletedIndex != newSelectIndex) //{ // dependency.Name = existingComponents[newSelectIndex]; //} EditorGUILayout.BeginHorizontal(); GUILayout.Space(75); dependency.Version = EditorGUILayout.TextField(new GUIContent("Version", "The version number of the dependency package. (specify ranges with =><)"), dependency.Version); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); { GUILayout.Space(75); if (GUILayout.Button("Remove " + dependency.Id)) { toDelete = dependency; } } EditorGUILayout.EndHorizontal(); EditorGUILayout.Separator(); EditorGUIUtility.labelWidth = prevLabelWidth; } if (toDelete != null) { nuspecFrameworkGroup.Dependencies.Remove(toDelete); } EditorGUILayout.BeginHorizontal(); { GUILayout.Space(50); if (GUILayout.Button("Add Dependency")) { nuspecFrameworkGroup.Dependencies.Add(new NugetPackageIdentifier()); } } EditorGUILayout.EndHorizontal(); } EditorGUILayout.Separator(); if (GUILayout.Button(string.Format("Save {0}", Path.GetFileName(filepath)))) { nuspec.Save(filepath); } EditorGUILayout.Separator(); if (GUILayout.Button(string.Format("Pack {0}.nupkg", Path.GetFileNameWithoutExtension(filepath)))) { NugetHelper.Pack(filepath); } EditorGUILayout.Separator(); apiKey = EditorGUILayout.TextField(new GUIContent("API Key", "The API key to use when pushing the package to the server"), apiKey); if (GUILayout.Button(string.Format("Push to Server"))) { NugetHelper.Push(nuspec, filepath, apiKey); } } }
/// <summary> /// Parses the given <see cref="XDocument"/> and returns the list of <see cref="NugetPackage"/>s contained within. /// </summary> /// <param name="document">The <see cref="XDocument"/> that is the OData XML response from the NuGet server.</param> /// <returns>The list of <see cref="NugetPackage"/>s read from the given XML.</returns> public static List <NugetPackage> Parse(XDocument document) { List <NugetPackage> packages = new List <NugetPackage>(); var packageEntries = document.Root.Elements(XName.Get("entry", AtomNamespace)); foreach (var entry in packageEntries) { NugetPackage package = new NugetPackage(); package.Id = entry.GetAtomElement("title").Value; package.DownloadUrl = entry.GetAtomElement("content").Attribute("src").Value; var entryProperties = entry.Element(XName.Get("properties", MetaDataNamespace)); package.Title = entryProperties.GetProperty("Title"); package.Version = entryProperties.GetProperty("Version"); package.Description = entryProperties.GetProperty("Description"); package.Summary = entryProperties.GetProperty("Summary"); package.ReleaseNotes = entryProperties.GetProperty("ReleaseNotes"); package.LicenseUrl = entryProperties.GetProperty("LicenseUrl"); package.ProjectUrl = entryProperties.GetProperty("ProjectUrl"); package.Authors = entryProperties.GetProperty("Authors"); package.DownloadCount = int.Parse(entryProperties.GetProperty("DownloadCount")); string iconUrl = entryProperties.GetProperty("IconUrl"); if (!string.IsNullOrEmpty(iconUrl)) { package.Icon = NugetHelper.DownloadImage(iconUrl); } // if there is no title, just use the ID as the title if (string.IsNullOrEmpty(package.Title)) { package.Title = package.Id; } // Get dependencies string rawDependencies = entryProperties.GetProperty("Dependencies"); if (!string.IsNullOrEmpty(rawDependencies)) { var dependencyGroups = new Dictionary <string, NugetFrameworkGroup>(); string[] dependencies = rawDependencies.Split('|'); foreach (var dependencyString in dependencies) { string[] details = dependencyString.Split(':'); string framework = string.Empty; if (details.Length > 2) { framework = details[2]; } NugetFrameworkGroup group; if (!dependencyGroups.TryGetValue(framework, out group)) { group = new NugetFrameworkGroup(); group.TargetFramework = framework; dependencyGroups.Add(framework, group); } var dependency = new NugetPackageIdentifier(details[0], details[1]); // some packages (ex: FSharp.Data - 2.1.0) have inproper "semi-empty" dependencies such as: // "Zlib.Portable:1.10.0:portable-net40+sl50+wp80+win80|::net40" // so we need to only add valid dependencies and skip invalid ones if (!string.IsNullOrEmpty(dependency.Id) && !string.IsNullOrEmpty(dependency.Version)) { group.Dependencies.Add(dependency); } } foreach (var group in dependencyGroups.Values) { package.Dependencies.Add(group); } } packages.Add(package); } return(packages); }