/// <summary> /// Sets a package reference and returns the number of changes. /// </summary> /// <param name="m">The monitor.</param> /// <param name="frameworks"> /// Frameworks that applies to the reference. Must not be empty. /// Can be this project's <see cref="TargetFrameworks"/> to update the package reference regardless of the framework. /// </param> /// <param name="packageId">The package identifier.</param> /// <param name="version">The new version to set.</param> /// <param name="addIfNotExists">True to add the reference. By default, it is only updated.</param> /// <param name="preserveExisting">True to keep any existing version.</param> /// <param name="throwProjectDependendencies">False to not challenge ProjectReferences.</param> /// <returns>The number of changes.</returns> public int SetPackageReferenceVersion( IActivityMonitor m, CKTrait frameworks, string packageId, SVersion version, bool addIfNotExists = false, bool preserveExisting = false, bool throwProjectDependendencies = true) { if (!_dependencies.IsInitialized) { throw new InvalidOperationException("Invalid Project."); } if (frameworks.IsEmpty) { throw new ArgumentException("Must not be empty.", nameof(frameworks)); } var actualFrameworks = TargetFrameworks.Intersect(frameworks); if (actualFrameworks.IsEmpty) { throw new ArgumentException($"No {frameworks} in {TargetFrameworks}.", nameof(frameworks)); } if (throwProjectDependendencies && _dependencies.Projects.Any(p => p.TargetProject.ProjectName == packageId)) { throw new ArgumentException($"Package {packageId} is already a ProjectReference.", nameof(packageId)); } var sV = version.ToNormalizedString(); int changeCount = 0; CKTrait pFrameworks = null; foreach (var p in _dependencies.Packages.Where(p => p.PackageId == packageId && !(pFrameworks = p.Frameworks.Intersect(actualFrameworks)).IsEmpty)) { if (p.VersionLocked) { m.Warn($"The version({p.Version}) of the package {packageId} was manually locked. You need to change it manually."); continue; } actualFrameworks = actualFrameworks.Except(pFrameworks); var currentVersion = p.Version; if (currentVersion != version) { if (!preserveExisting) { var e = p.PropertyVersionElement; if (e != null) { e.Value = sV; } else { e = p.OriginElement; e.Attribute("Version").SetValue(sV); } ++changeCount; m.Trace($"Update in {ToString()}: {packageId} from {currentVersion} to {sV}."); } else { m.Trace($"Preserving existing version {currentVersion} for {packageId} in {ToString()} (skipped version is {sV})."); } } } // Handle creation if needed. if (!actualFrameworks.IsEmpty && addIfNotExists) { var firstPropertyGroup = ProjectFile.Document.Root.Element("PropertyGroup"); var pRef = new XElement("ItemGroup", new XElement("PackageReference", new XAttribute("Include", packageId), new XAttribute("Version", sV))); if (TargetFrameworks == actualFrameworks) { ++changeCount; firstPropertyGroup.AddAfterSelf(pRef); m.Trace($"Added unconditional package reference {packageId} -> {sV} for {ToString()}."); } else { foreach (var f in actualFrameworks.AtomicTraits) { ++changeCount; var withCond = new XElement(pRef); withCond.SetAttributeValue("Condition", $"'(TargetFrameWork)' == '{f}' "); firstPropertyGroup.AddAfterSelf(withCond); m.Trace($"Added conditional {f} package reference {packageId} -> {sV} for {ToString()}."); } } } if (changeCount > 0) { OnChange(m); } return(changeCount); }