Repository navigation
Implementation for #913 Paket.pack: add support for nuget dependencies conditional on target framework #2428
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 3 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,6 +8,7 @@ open Paket.Xml | |
| open System.Text | ||
| open System.Text.RegularExpressions | ||
| open System.Xml | ||
| open Paket.Requirements | ||
|
|
||
| module internal NupkgWriter = | ||
|
|
||
|
|
@@ -83,23 +84,45 @@ module internal NupkgWriter = | |
| frameworkAssembliesList |> List.iter (buildFrameworkReferencesNode >> d.Add) | ||
| metadataNode.Add d | ||
|
|
||
| let buildDependencyNode (Id, requirement:VersionRequirement) = | ||
| let buildDependencyNode (id, requirement:VersionRequirement) = | ||
| let dep = XElement(ns + "dependency") | ||
| dep.SetAttributeValue(XName.Get "id", Id) | ||
| dep.SetAttributeValue(XName.Get "id", id) | ||
| let version = requirement.FormatInNuGetSyntax() | ||
| if String.IsNullOrEmpty version then | ||
| dep.SetAttributeValue(XName.Get "version", "0.0") | ||
| else | ||
| dep.SetAttributeValue(XName.Get "version", version) | ||
| dep | ||
|
|
||
| let buildGroupNode (framework:FrameworkIdentifier, add) = | ||
| let g = XElement(ns + "group") | ||
| g.SetAttributeValue(XName.Get "targetFramework", framework.ToString()) | ||
| add g | ||
| g | ||
|
|
||
|
|
||
| let buildDependencyNodes (excludedDependencies, add, dependencyList) = | ||
| let takeFirstOfThree (a,_,_) = a | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's a nice trick, but could you please manually inline this? I don't think we really need these functions here. Thx |
||
| let takeFirstTwoOfThree (a,b,_) = a,b | ||
| dependencyList | ||
| |> List.filter (fun d -> Set.contains (takeFirstOfThree d) excludedDependencies |> not) | ||
| |> List.map takeFirstTwoOfThree | ||
| |> List.iter (buildDependencyNode >> add) | ||
|
|
||
| let buildDependencyNodesByGroup excludedDependencies add dependencyList framework = | ||
| let node = buildGroupNode(framework, add) | ||
| buildDependencyNodes(excludedDependencies, node.Add, dependencyList) | ||
|
|
||
| let buildDependenciesNode excludedDependencies dependencyList = | ||
| if List.isEmpty dependencyList then () else | ||
| let d = XElement(ns + "dependencies") | ||
| dependencyList | ||
| |> List.filter (fun d -> Set.contains (fst d) excludedDependencies |> not) | ||
| |> List.iter (buildDependencyNode >> d.Add) | ||
| metadataNode.Add d | ||
| let groups = List.groupBy thirdOf3 dependencyList | ||
| if groups.Length = 1 && fst groups.Head = None then | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you please use pattern matching here? |
||
| buildDependencyNodes(excludedDependencies, d.Add, dependencyList) | ||
| else | ||
| groups | ||
| |> List.iter (fun a -> buildDependencyNodesByGroup excludedDependencies d.Add (snd a) (fst a).Value) | ||
| metadataNode.Add d | ||
|
|
||
| let buildReferenceNode (fileName) = | ||
| let dep = XElement(ns + "reference") | ||
|
|
@@ -369,7 +392,7 @@ module NuspecExtensions = | |
| references.Groups |> Seq.collect (fun kvp -> | ||
| kvp.Value.NugetPackages |> List.choose (fun pkg -> | ||
| dependencies.TryGetPackage(kvp.Key,pkg.Name) | ||
| |> Option.map (fun verreq -> pkg.Name,verreq.VersionRequirement))) | ||
| |> Option.map (fun verreq -> pkg.Name,verreq.VersionRequirement, None))) | ||
| |> List.ofSeq | ||
| ) |> Option.defaultValue [] | ||
| let projectInfo, optionalInfo = project.GetTemplateMetadata () | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -107,11 +107,14 @@ let (|Valid|Invalid|) md = | |
| Symbols = s } | ||
| | _ -> Invalid | ||
|
|
||
| let addDependency (templateFile : TemplateFile) (dependency : PackageName * VersionRequirement) = | ||
|
|
||
|
|
||
| let addDependency (templateFile : TemplateFile) (dependency : PackageName * VersionRequirement * FrameworkIdentifier option) = | ||
| match templateFile with | ||
| | CompleteTemplate(core, opt) -> | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here. Please get rid of firstOf3 |
||
| let firstOf3 (a, _, _) = a | ||
| let newDeps = | ||
| match opt.Dependencies |> List.tryFind (fun (n,_) -> n = fst dependency) with | ||
| match opt.Dependencies |> List.tryFind (fun (n,_,_) -> n = firstOf3 dependency) with | ||
| | None -> dependency :: opt.Dependencies | ||
| | _ -> opt.Dependencies | ||
| { FileName = templateFile.FileName | ||
|
|
@@ -253,7 +256,7 @@ let findDependencies (dependenciesFile : DependenciesFile) config platform (temp | |
| match core.Version with | ||
| | Some v -> | ||
| let versionConstraint = if lockDependencies || pinProjectReferences then Specific v else Minimum v | ||
| PackageName core.Id, VersionRequirement(versionConstraint, getPreReleaseStatus v) | ||
| PackageName core.Id, VersionRequirement(versionConstraint, getPreReleaseStatus v), None | ||
| | None -> failwithf "There was no version given for %s." templateFile.FileName | ||
| | IncompleteTemplate -> | ||
| failwithf "You cannot create a dependency on a template file (%s) with incomplete metadata." templateFile.FileName) | ||
|
|
@@ -357,7 +360,7 @@ let findDependencies (dependenciesFile : DependenciesFile) config platform (temp | |
| | None -> | ||
| match version with | ||
| | Some v -> | ||
| np.Name,VersionRequirement.Parse (v.ToString()) | ||
| np.Name,VersionRequirement.Parse (v.ToString()) , None | ||
| | None -> | ||
| if minimumFromLockFile then | ||
| let groupName = | ||
|
|
@@ -368,7 +371,7 @@ let findDependencies (dependenciesFile : DependenciesFile) config platform (temp | |
| |> Option.map fst | ||
|
|
||
| match groupName with | ||
| | None -> np.Name,specificVersionRequirement | ||
| | None -> np.Name,specificVersionRequirement, None | ||
| | Some groupName -> | ||
| let group = lockFile.GetGroup groupName | ||
|
|
||
|
|
@@ -377,9 +380,9 @@ let findDependencies (dependenciesFile : DependenciesFile) config platform (temp | |
| | Some resolvedPackage -> VersionRequirement(GreaterThan resolvedPackage.Version, getPreReleaseStatus resolvedPackage.Version) | ||
| | None -> specificVersionRequirement | ||
|
|
||
| np.Name,lockedVersion | ||
| np.Name,lockedVersion, None | ||
| else | ||
| np.Name,specificVersionRequirement | ||
| np.Name,specificVersionRequirement, None | ||
| | Some groupName -> | ||
| let dependencyVersionRequirement = | ||
| if not lockDependencies then | ||
|
|
@@ -437,7 +440,8 @@ let findDependencies (dependenciesFile : DependenciesFile) config platform (temp | |
| match dependencyVersionRequirement with | ||
| | Some installed -> installed | ||
| | None -> failwithf "No package with id '%O' installed in group %O." np.Name groupName | ||
| np.Name, dep) | ||
|
|
||
| np.Name, dep, None) | ||
|
|
||
| deps | ||
| |> List.fold addDependency withDepsAndIncluded | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,6 +6,7 @@ open System.IO | |
| open System.Text.RegularExpressions | ||
| open Chessie.ErrorHandling | ||
| open Paket.Domain | ||
| open Paket.Requirements | ||
|
|
||
| module private TemplateParser = | ||
| type private ParserState = | ||
|
|
@@ -141,7 +142,7 @@ type OptionalPackagingInfo = | |
| RequireLicenseAcceptance : bool | ||
| Tags : string list | ||
| DevelopmentDependency : bool | ||
| Dependencies : (PackageName * VersionRequirement) list | ||
| Dependencies : (PackageName * VersionRequirement * FrameworkIdentifier option) list | ||
| ExcludedDependencies : Set<PackageName> | ||
| ExcludedGroups : Set<GroupName> | ||
| References : string list | ||
|
|
@@ -261,45 +262,80 @@ module internal TemplateFile = | |
| | Some m -> ok m | ||
| | None -> failP file "No description line in paket.template file." | ||
|
|
||
| let private (|Framework|_|) (line:string) = | ||
| match line.Trim() with | ||
| | String.RemovePrefix "framework:" _ as trimmed -> Some (FrameworkDetection.Extract(trimmed.Replace("framework: ",""))) | ||
| | _ -> None | ||
|
|
||
| let private (|Empty|_|) (line:string) = | ||
| match line.Trim() with | ||
| | _ when String.IsNullOrWhiteSpace line -> Some (Empty line) | ||
| | String.RemovePrefix "//" _ -> Some (Empty line) | ||
| | String.RemovePrefix "#" _ -> Some (Empty line) | ||
| | _ -> None | ||
| type TargetFrameworkGroup = | ||
| { | ||
| Framework : FrameworkIdentifier option | ||
| Dependencies : (PackageName * VersionRequirement * FrameworkIdentifier option) List} | ||
| static member ForNone = { Framework = None ; Dependencies = [] } | ||
| static member ForFramework framework = { Framework = framework ; Dependencies = [] } | ||
|
|
||
| let private getDependencieByLine (fileName, lockFile:LockFile,currentVersion:SemVerInfo option, specificVersions:Map<string, SemVerInfo>, line:string, framework:FrameworkIdentifier option)= | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Small typo in function name |
||
| let reg = Regex(@"(?<id>\S+)(?<version>.*)").Match line | ||
| let name = PackageName reg.Groups.["id"].Value | ||
| let versionRequirement = | ||
| let versionString = | ||
| let s = reg.Groups.["version"].Value.Trim() | ||
| if s.Contains "CURRENTVERSION" then | ||
| match specificVersions.TryFind (string name) with | ||
| | Some v -> s.Replace("CURRENTVERSION", string v) | ||
| | None -> | ||
| match currentVersion with | ||
| | Some v -> s.Replace("CURRENTVERSION", string v) | ||
| | None -> failwithf "The template file %s contains the placeholder CURRENTVERSION, but no version was given." fileName | ||
|
|
||
| elif s.Contains "LOCKEDVERSION" then | ||
| match lockFile.Groups.[Constants.MainDependencyGroup].Resolution |> Map.tryFind name with | ||
| | Some p -> s.Replace("LOCKEDVERSION", string p.Version) | ||
| | None -> | ||
| let packages = | ||
| lockFile.GetGroupedResolution() | ||
| |> Seq.filter (fun kv -> snd kv.Key = name) | ||
| |> Seq.toList | ||
|
|
||
| match packages with | ||
| | [] -> failwithf "The template file %s contains the placeholder LOCKEDVERSION, but no version was given for package %O in paket.lock." fileName name | ||
| | [kv] -> s.Replace("LOCKEDVERSION", string kv.Value.Version) | ||
| | _ -> failwithf "The template file %s contains the placeholder LOCKEDVERSION, but more than one group contains package %O in paket.lock." fileName name | ||
|
|
||
| else s | ||
|
|
||
| DependenciesFileParser.parseVersionRequirement versionString | ||
| name, versionRequirement, framework | ||
|
|
||
| let private getDependenciesByTargetFramework fileName lockFile currentVersion specificVersions (lineNo, state: TargetFrameworkGroup list) line= | ||
| match state with | ||
| | current::other -> | ||
| let lineNo = lineNo + 1 | ||
| match line with | ||
| | Framework framework -> | ||
| let group = TargetFrameworkGroup.ForFramework framework::current::other | ||
| lineNo, group | ||
| | Empty _ -> lineNo, current::other | ||
| | _ -> | ||
| let dependency = getDependencieByLine(fileName, lockFile, currentVersion, specificVersions, line, current.Framework) | ||
| lineNo ,{ current with Dependencies = current.Dependencies @ [dependency] }::other | ||
| | [] -> failwithf "Error in paket.dependencies line %d" lineNo | ||
|
|
||
| let private getDependencies (fileName, lockFile:LockFile, info : Map<string, string>,currentVersion:SemVerInfo option, specificVersions:Map<string, SemVerInfo>) = | ||
| match Map.tryFind "dependencies" info with | ||
| | None -> [] | ||
| | Some d -> | ||
| d.Split '\n' | ||
| |> Array.map (fun d -> | ||
| let reg = Regex(@"(?<id>\S+)(?<version>.*)").Match d | ||
| let name = PackageName reg.Groups.["id"].Value | ||
| let versionRequirement = | ||
| let versionString = | ||
| let s = reg.Groups.["version"].Value.Trim() | ||
| if s.Contains "CURRENTVERSION" then | ||
| match specificVersions.TryFind (string name) with | ||
| | Some v -> s.Replace("CURRENTVERSION", string v) | ||
| | None -> | ||
| match currentVersion with | ||
| | Some v -> s.Replace("CURRENTVERSION", string v) | ||
| | None -> failwithf "The template file %s contains the placeholder CURRENTVERSION, but no version was given." fileName | ||
|
|
||
| elif s.Contains "LOCKEDVERSION" then | ||
| match lockFile.Groups.[Constants.MainDependencyGroup].Resolution |> Map.tryFind name with | ||
| | Some p -> s.Replace("LOCKEDVERSION", string p.Version) | ||
| | None -> | ||
| let packages = | ||
| lockFile.GetGroupedResolution() | ||
| |> Seq.filter (fun kv -> snd kv.Key = name) | ||
| |> Seq.toList | ||
|
|
||
| match packages with | ||
| | [] -> failwithf "The template file %s contains the placeholder LOCKEDVERSION, but no version was given for package %O in paket.lock." fileName name | ||
| | [kv] -> s.Replace("LOCKEDVERSION", string kv.Value.Version) | ||
| | _ -> failwithf "The template file %s contains the placeholder LOCKEDVERSION, but more than one group contains package %O in paket.lock." fileName name | ||
|
|
||
| else s | ||
|
|
||
| DependenciesFileParser.parseVersionRequirement versionString | ||
|
|
||
| name, versionRequirement) | ||
| |> Array.toList | ||
| d.Split '\n' | ||
| |> Array.fold (getDependenciesByTargetFramework fileName lockFile currentVersion specificVersions) (0, [TargetFrameworkGroup.ForNone]) | ||
| |> snd | ||
| |> List.rev | ||
| |> List.collect (fun a -> a.Dependencies) | ||
|
|
||
|
|
||
| let private getExcludedDependencies (info : Map<string, string>) = | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -439,7 +439,6 @@ module FrameworkDetection = | |
|
|
||
| open Logging | ||
| /// parse a string to construct a Netframework, NetCore, NetStandard, or other dotnet identifier | ||
| [<Obsolete "Use PlatformMatching.extractPlatforms instead">] | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ? |
||
| let Extract = | ||
| memoize | ||
| (fun (path:string) -> | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you please rename this thing. id is a function from the FSharp.Core and I think we should avoid confusion. Maybe name or idProperty or something like that