private XElement FindMatchingPackageNode(PackageReference entry, XElement packagesNode)
        {
            XElement matchingIdNode;
            bool     hasMatchingNode = PackagesConfig.HasAttributeValue(packagesNode, PackagesConfig.IdAttributeName,
                                                                        entry.PackageIdentity.Id, out matchingIdNode);

            if (matchingIdNode != null)
            {
                string version;
                PackagesConfig.TryGetAttribute(matchingIdNode, PackagesConfig.VersionAttributeName, out version);

                if (!string.IsNullOrEmpty(version))
                {
                    NuGetVersion nuGetVersion;
                    bool         isNuGetVersion = NuGetVersion.TryParse(version, out nuGetVersion);

                    if (isNuGetVersion && nuGetVersion != null && nuGetVersion.Equals(entry.PackageIdentity.Version))
                    {
                        return(matchingIdNode);
                    }
                }
            }

            return(null);
        }
        /// <summary>
        /// Adds a package entry to the file
        /// </summary>
        /// <param name="entry">Package reference entry</param>
        public void AddPackageEntry(PackageReference entry)
        {
            if (entry == null)
            {
                throw new ArgumentNullException(nameof(entry));
            }

            if (_disposed)
            {
                throw new PackagesConfigWriterException(string.Format(CultureInfo.CurrentCulture,
                                                                      Strings.UnableToAddEntry));
            }

            var packagesNode = EnsurePackagesNode();

            XElement package;

            if (PackagesConfig.HasAttributeValue(packagesNode, PackagesConfig.IdAttributeName, entry.PackageIdentity.Id, out package))
            {
                throw new PackagesConfigWriterException(String.Format(CultureInfo.CurrentCulture,
                                                                      Strings.PackageEntryAlreadyExist, entry.PackageIdentity.Id));
            }
            else
            {
                // Append the entry to existing package nodes
                var node = CreateXElementForPackageEntry(entry);
                packagesNode.Add(node);

                // Sort the entries by package Id
                SortPackageNodes(packagesNode);
            }
        }
        private XElement ReplacePackageAttributes(XElement existingNode, PackageReference newEntry)
        {
            var newEntryNode = CreateXElementForPackageEntry(newEntry);

            var newAttributeNames      = newEntryNode.Attributes().Select(a => a.Name);
            var existingAttributeNames = existingNode.Attributes().Select(a => a.Name);
            var addableAttributeNames  = newAttributeNames.Except(existingAttributeNames);

            foreach (XName name in existingAttributeNames)
            {
                // Clear newValue
                string newValue = null;

                // Try to get newValue correlated to the attribute on the existing node.
                PackagesConfig.TryGetAttribute(newEntryNode, name.LocalName, out newValue);

                // When the attribute is not specified a value in the new node
                if (string.IsNullOrEmpty(newValue))
                {
                    if (name.Equals(XName.Get(PackagesConfig.RequireInstallAttributeName)))
                    {
                        // Remove the requirementReinstallation attribute.
                        existingNode.SetAttributeValue(name, value: null);
                    }
                    else
                    {
                        // no-op. Keep the allowedVersion attribute and all other attributes as-is.
                    }
                }
                else
                {
                    // Replace existing attributes with new values
                    existingNode.SetAttributeValue(name, newValue);
                }
            }

            // Add new attributes that was not in the old package reference entry, if any
            foreach (XName name in addableAttributeNames)
            {
                var attribute = new XAttribute(name, newEntryNode.Attribute(name).Value);
                existingNode.Add(attribute);
            }

            return(existingNode);
        }
Exemple #4
0
        /// <summary>
        /// Get a boolean attribute value, or false if it does not exist
        /// </summary>
        public static bool BoolAttribute(XElement node, string name, bool defaultValue = false)
        {
            string value = null;

            if (PackagesConfig.TryGetAttribute(node, name, out value))
            {
                if (StringComparer.OrdinalIgnoreCase.Equals(value, "true"))
                {
                    return(true);
                }
                else
                {
                    return(false);
                }
            }

            return(defaultValue);
        }
        /// <summary>
        /// Update a package entry using the original entry as a base if it exists.
        /// </summary>
        public void UpdateOrAddPackageEntry(XDocument originalConfig, PackageReference newEntry)
        {
            if (originalConfig == null)
            {
                throw new ArgumentNullException(nameof(originalConfig));
            }

            if (newEntry == null)
            {
                throw new ArgumentNullException(nameof(newEntry));
            }

            if (_disposed)
            {
                throw new PackagesConfigWriterException(string.Format(CultureInfo.CurrentCulture,
                                                                      Strings.UnableToAddEntry));
            }

            var originalPackagesNode = originalConfig.Element(XName.Get(PackagesConfig.PackagesNodeName));

            XElement matchingIdNode;

            if (PackagesConfig.HasAttributeValue(
                    originalPackagesNode,
                    PackagesConfig.IdAttributeName,
                    newEntry.PackageIdentity.Id,
                    out matchingIdNode))
            {
                // Find the old entry and update it based on the new entry
                var packagesNode   = _xDocument.Element(XName.Get(PackagesConfig.PackagesNodeName));
                var newPackageNode = ReplacePackageAttributes(matchingIdNode, newEntry);
                packagesNode.Add(newPackageNode);
                SortPackageNodes(packagesNode);
            }
            else
            {
                // There was no existing entry, add a new one
                AddPackageEntry(newEntry);
            }
        }
        /// <summary>
        /// Reads all package node entries in the config.
        /// </summary>
        /// <param name="allowDuplicatePackageIds">If True validation will be performed to ensure that
        /// only one entry exists for each unique package id.</param>
        public IEnumerable <PackageReference> GetPackages(bool allowDuplicatePackageIds)
        {
            var packages = new List <PackageReference>();

            foreach (var package in _doc.Root.Elements(XName.Get(PackagesConfig.PackageNodeName)))
            {
                string id = null;
                if (!PackagesConfig.TryGetAttribute(package, "id", out id) ||
                    String.IsNullOrEmpty(id))
                {
                    throw new PackagesConfigReaderException(string.Format(
                                                                CultureInfo.CurrentCulture,
                                                                Strings.ErrorNullOrEmptyPackageId));
                }

                string version = null;
                if (!PackagesConfig.TryGetAttribute(package, PackagesConfig.VersionAttributeName, out version) ||
                    String.IsNullOrEmpty(version))
                {
                    throw new PackagesConfigReaderException(string.Format(
                                                                CultureInfo.CurrentCulture,
                                                                Strings.ErrorInvalidPackageVersion,
                                                                id,
                                                                version));
                }

                NuGetVersion semver = null;
                if (!NuGetVersion.TryParse(version, out semver))
                {
                    throw new PackagesConfigReaderException(string.Format(
                                                                CultureInfo.CurrentCulture,
                                                                Strings.ErrorInvalidPackageVersion,
                                                                id,
                                                                version));
                }

                string       attributeValue  = null;
                VersionRange allowedVersions = null;
                if (PackagesConfig.TryGetAttribute(package, PackagesConfig.allowedVersionsAttributeName, out attributeValue))
                {
                    if (!VersionRange.TryParse(attributeValue, out allowedVersions))
                    {
                        throw new PackagesConfigReaderException(string.Format(
                                                                    CultureInfo.CurrentCulture,
                                                                    Strings.ErrorInvalidAllowedVersions,
                                                                    id,
                                                                    attributeValue));
                    }
                }

                var targetFramework = NuGetFramework.UnsupportedFramework;
                if (PackagesConfig.TryGetAttribute(package, PackagesConfig.TargetFrameworkAttributeName, out attributeValue))
                {
                    targetFramework = NuGetFramework.Parse(attributeValue, _frameworkMappings);
                }

                var developmentDependency = PackagesConfig.BoolAttribute(package, PackagesConfig.developmentDependencyAttributeName);
                var requireReinstallation = PackagesConfig.BoolAttribute(package, PackagesConfig.RequireInstallAttributeName);
                var userInstalled         = PackagesConfig.BoolAttribute(package, PackagesConfig.UserInstalledAttributeName, true);

                var entry = new PackageReference(new PackageIdentity(id, semver), targetFramework, userInstalled, developmentDependency, requireReinstallation, allowedVersions);

                packages.Add(entry);
            }

            // check if there are duplicate entries
            var             duplicates   = new HashSet <string>(StringComparer.OrdinalIgnoreCase);
            PackageIdentity lastIdentity = null;
            var             comparer     = PackageIdentity.Comparer;

            // Sort the list of packages and check for duplicates
            foreach (var package in packages.OrderBy(p => p.PackageIdentity, comparer))
            {
                if (lastIdentity != null)
                {
                    if (allowDuplicatePackageIds)
                    {
                        // Full compare
                        if (comparer.Equals(package.PackageIdentity, lastIdentity))
                        {
                            duplicates.Add(lastIdentity.ToString());
                        }
                    }
                    else if (string.Equals(
                                 package.PackageIdentity.Id,
                                 lastIdentity.Id,
                                 StringComparison.OrdinalIgnoreCase))
                    {
                        // Id only compare
                        duplicates.Add(lastIdentity.Id);
                    }
                }

                lastIdentity = package.PackageIdentity;
            }

            if (duplicates.Count > 0)
            {
                throw new PackagesConfigReaderException(string.Format(
                                                            CultureInfo.CurrentCulture,
                                                            Strings.ErrorDuplicatePackages,
                                                            string.Join(", ", duplicates)));
            }

            return(packages);
        }