Skip to content

Commit f616c8b

Browse files
new option generate_load_scripts: on|off|true|false in paket.dependencies
this option, if on/true, calls the loading script generation Note that this does it in very eager way (if defined for any group, it will generate all), it also doesn't allow to specify framework or language like from command line, keeping it simple for now. The option is off by default, because there is performance penality and it generates lots of small script files, there is also no proper logic for "garbage collection" process. Implementation notes: * A new convenience method is also exposed on PublicAPI: Dependencies.GenerateIncludeScripts() * I had to migrate a good deal of stuff in a module I named Queries, mostly stuff which were raw in Program.fs * added a unit test for parser, testing all cases of the new option * added an integration checking calling install with option on results in script being generated without further invocation * Since both .dependencies and .lock files are used often in conjunction, I made a PaketFiles DU (in Queries module) * Since both group name and package name are used often in conjunction, I made a QualifiedPackageName single case DU, which helped me remove a bit of cruft related to default group
1 parent cbc0f55 commit f616c8b

14 files changed

Lines changed: 301 additions & 140 deletions

File tree

‎integrationtests/Paket.IntegrationTests/LoadingScriptGenerationTests.fs‎

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -57,13 +57,7 @@ let ``simple dependencies generates expected scripts``() =
5757
if not isMono then // TODO: Fix me
5858
Assert.AreEqual(expectedFiles,actualFiles)
5959

60-
[<Test;Category("scriptgen")>]
61-
let ``framework specified``() =
62-
let scenario = "framework-specified"
63-
paket "install" scenario |> ignore
64-
65-
directPaket "generate-include-scripts" scenario |> ignore
66-
60+
let assertNhibernateForFramework35IsThere scenario =
6761
let expectations = [
6862
"include.iesi.collections.csx", ["Net35/Iesi.Collections.dll"]
6963
"include.iesi.collections.fsx", ["Net35/Iesi.Collections.dll"]
@@ -76,6 +70,16 @@ let ``framework specified``() =
7670
if not (Seq.isEmpty failures) then
7771
Assert.Fail (failures |> String.concat Environment.NewLine)
7872

73+
74+
[<Test;Category("scriptgen")>]
75+
let ``framework specified``() =
76+
let scenario = "framework-specified"
77+
paket "install" scenario |> ignore
78+
79+
directPaket "generate-include-scripts" scenario |> ignore
80+
81+
assertNhibernateForFramework35IsThere scenario
82+
7983
[<Test; Category("scriptgen"); Ignore("group script is always generated")>]
8084
let ``don't generate scripts when no references are found``() =
8185
(* The deps file for this scenario just includes FAKE, which has no lib or framework references, so no script should be generated for it. *)
@@ -191,3 +195,9 @@ let ``fsharp.core excluded from f# script`` () =
191195

192196
Assert.False hasFilesWithFsharpCore
193197

198+
[<Test; Category("scriptgen dependencies")>]
199+
let ``generates script on install`` () =
200+
let scenario = "dependencies-file-flag"
201+
paket "install" scenario |> ignore
202+
203+
assertNhibernateForFramework35IsThere scenario
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
source http://nuget.org/api/v2
2+
framework: net35
3+
generate_load_scripts: on
4+
nuget NHibernate ~> 3

‎src/Paket.Core/Files/LockFile.fs‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -510,7 +510,7 @@ module LockFileParser =
510510
type LockFile(fileName:string,groups: Map<GroupName,LockFileGroup>) =
511511
member __.Groups = groups
512512
member __.FileName = fileName
513-
513+
member __.RootPath = FileInfo(fileName).Directory.FullName
514514
member this.GetGroup groupName =
515515
match this.Groups |> Map.tryFind groupName with
516516
| Some g -> g
@@ -749,3 +749,5 @@ type LockFile(fileName:string,groups: Map<GroupName,LockFileGroup>) =
749749
|> failIfNone (ReferenceNotFoundInLockFile(referencesFile.FileName, groupName.ToString(), package.Name)))
750750
|> collect
751751
|> lift (Seq.concat >> Set.ofSeq)
752+
753+

‎src/Paket.Core/Files/ReferencesFile.fs‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,8 @@ type ReferencesFile =
139139
CreateBindingRedirects = createBindingRedirects
140140
Excludes = []
141141
Aliases = Map.empty
142-
OmitContent = if omitContent then Some ContentCopySettings.Omit else None } }
142+
OmitContent = if omitContent then Some ContentCopySettings.Omit else None
143+
GenerateLoadScripts = Some false } }
143144

144145

145146
match this.Groups |> Map.tryFind groupName with

‎src/Paket.Core/Paket.Core.fsproj‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,8 @@
120120
<Compile Include="Nuget.fs" />
121121
<Compile Include="NuGetV3.fs" />
122122
<Compile Include="NuGetV2.fs" />
123+
<Compile Include="Queries.fs" />
124+
<Compile Include="ScriptGeneration.fs" />
123125
<Compile Include="LocalFile.fs" />
124126
<Compile Include="DependencyChangeDetection.fs" />
125127
<Compile Include="GarbageCollection.fs" />
@@ -143,7 +145,6 @@
143145
<Compile Include="FindReferences.fs" />
144146
<Compile Include="Why.fs" />
145147
<Compile Include="PublicAPI.fs" />
146-
<Compile Include="ScriptGeneration.fs" />
147148
<None Include="paket.template" />
148149
<None Include="paket.references" />
149150
</ItemGroup>

‎src/Paket.Core/Parsers/DependenciesFileParser.fs‎

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ module DependenciesFileParser =
196196
| ImportTargets of bool
197197
| CopyLocal of bool
198198
| CopyContentToOutputDir of CopyToOutputDirectorySettings
199+
| GenerateLoadScripts of bool option
199200
| ReferenceCondition of string
200201
| Redirects of bool option
201202
| ResolverStrategyForTransitives of ResolverStrategy option
@@ -327,6 +328,13 @@ module DependenciesFileParser =
327328

328329
Some (ParserOptions(ParserOption.CopyContentToOutputDir(setting)))
329330
| String.StartsWith "condition" trimmed -> Some (ParserOptions(ParserOption.ReferenceCondition(trimmed.Replace(":","").Trim().ToUpper())))
331+
| String.StartsWith "generate_load_scripts" trimmed ->
332+
let setting =
333+
match trimmed.Replace(":","").Trim().ToLowerInvariant() with
334+
| "on" | "true" -> Some true
335+
| "off" | "false" -> Some false
336+
| _ -> None
337+
Some (ParserOptions(ParserOption.GenerateLoadScripts setting))
330338
| _ -> None
331339

332340
let private (|SourceFile|_|) (line:string) =
@@ -406,19 +414,18 @@ module DependenciesFileParser =
406414

407415
let private parseOptions (current : DependenciesGroup) options =
408416
match options with
409-
| ReferencesMode mode -> { current.Options with Strict = mode }
410-
| Redirects mode -> { current.Options with Redirects = mode }
411-
| ResolverStrategyForTransitives strategy -> { current.Options with ResolverStrategyForTransitives = strategy }
417+
| ReferencesMode mode -> { current.Options with Strict = mode }
418+
| Redirects mode -> { current.Options with Redirects = mode }
419+
| ResolverStrategyForTransitives strategy -> { current.Options with ResolverStrategyForTransitives = strategy }
412420
| ResolverStrategyForDirectDependencies strategy -> { current.Options with ResolverStrategyForDirectDependencies = strategy }
413-
| CopyLocal mode -> { current.Options with Settings = { current.Options.Settings with CopyLocal = Some mode } }
414-
| CopyContentToOutputDir mode -> { current.Options with Settings = { current.Options.Settings with CopyContentToOutputDirectory = Some mode } }
415-
| ImportTargets mode -> { current.Options with Settings = { current.Options.Settings with ImportTargets = Some mode } }
416-
| FrameworkRestrictions r -> { current.Options with Settings = { current.Options.Settings with FrameworkRestrictions = r } }
417-
| AutodetectFrameworkRestrictions ->
418-
{ current.Options with Settings = { current.Options.Settings with FrameworkRestrictions = AutoDetectFramework } }
419-
| OmitContent omit -> { current.Options with Settings = { current.Options.Settings with OmitContent = Some omit } }
420-
| ReferenceCondition condition -> { current.Options with Settings = { current.Options.Settings with ReferenceCondition = Some condition } }
421-
421+
| CopyLocal mode -> { current.Options with Settings = { current.Options.Settings with CopyLocal = Some mode } }
422+
| CopyContentToOutputDir mode -> { current.Options with Settings = { current.Options.Settings with CopyContentToOutputDirectory = Some mode } }
423+
| ImportTargets mode -> { current.Options with Settings = { current.Options.Settings with ImportTargets = Some mode } }
424+
| FrameworkRestrictions r -> { current.Options with Settings = { current.Options.Settings with FrameworkRestrictions = r } }
425+
| AutodetectFrameworkRestrictions -> { current.Options with Settings = { current.Options.Settings with FrameworkRestrictions = AutoDetectFramework } }
426+
| OmitContent omit -> { current.Options with Settings = { current.Options.Settings with OmitContent = Some omit } }
427+
| ReferenceCondition condition -> { current.Options with Settings = { current.Options.Settings with ReferenceCondition = Some condition } }
428+
| GenerateLoadScripts mode -> { current.Options with Settings = { current.Options.Settings with GenerateLoadScripts = mode }}
422429
let private parseLine fileName checkDuplicates (lineNo, state) line =
423430
match state with
424431
| current::other ->

‎src/Paket.Core/PublicAPI.fs‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,9 @@ type Dependencies(dependenciesFileName: string) =
192192
semVerUpdateMode = defaultArg semVerUpdateMode SemVerUpdateMode.NoRestriction,
193193
touchAffectedRefs = defaultArg touchAffectedRefs false)
194194

195+
static member GenerateIncludeScripts() =
196+
LoadingScripts.ScriptGeneration.executeCommand (DirectoryInfo (Directory.GetCurrentDirectory())) List.empty List.empty
197+
195198
/// Updates all dependencies.
196199
member this.Update(force: bool): unit = this.Update(force, false, false, false)
197200

‎src/Paket.Core/Queries.fs‎

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
module Paket.Queries // mostly logic which was in PublicAPI.fs but is useful to other places (like script generation)
2+
3+
open Domain
4+
open System.IO
5+
open System
6+
7+
type QualifiedPackageName = QualifiedPackageName of GroupName * PackageName
8+
with
9+
static member FromStrings (groupName: string option, packageName: string) =
10+
let groupName =
11+
match groupName with
12+
| None -> Constants.MainDependencyGroup
13+
| Some name -> GroupName name
14+
let packageName = PackageName packageName
15+
QualifiedPackageName(groupName, packageName)
16+
17+
type PaketFiles =
18+
| JustDependencies of DependenciesFile
19+
| DependenciesAndLock of DependenciesFile * LockFile
20+
with
21+
static member LocateFromDirectory (directory: DirectoryInfo) =
22+
let rec findInPath (dir:DirectoryInfo , withError) =
23+
let path = Path.Combine(dir.FullName,Constants.DependenciesFileName)
24+
if File.Exists(path) then
25+
path
26+
else
27+
let parent = dir.Parent
28+
match parent with
29+
| null ->
30+
if withError then
31+
failwithf "Could not find '%s'. To use Paket with this solution, please run 'paket init' first.%sIf you have already run 'paket.init' then ensure that '%s' is located in the top level directory of your repository.%sLike this:%sMySourceDir%s .paket%s paket.dependencies"
32+
Constants.DependenciesFileName Environment.NewLine Constants.DependenciesFileName Environment.NewLine Environment.NewLine Environment.NewLine Environment.NewLine
33+
else
34+
Constants.DependenciesFileName
35+
| _ -> findInPath(parent, withError)
36+
37+
let dependenciesFile =
38+
findInPath(directory,true)
39+
|> DependenciesFile.ReadFromFile
40+
41+
42+
let file = dependenciesFile.FindLockfile()
43+
if file.Exists then
44+
let lockFile = file.FullName |> LockFile.LoadFrom
45+
PaketFiles.DependenciesAndLock(dependenciesFile, lockFile)
46+
else
47+
PaketFiles.JustDependencies dependenciesFile
48+
49+
let getLockFileFromDependenciesFile dependenciesFileName =
50+
let lockFileName = DependenciesFile.FindLockfile dependenciesFileName
51+
LockFile.LoadFrom lockFileName.FullName
52+
53+
let listPackages (packages: System.Collections.Generic.KeyValuePair<GroupName*PackageName, PackageResolver.ResolvedPackage> seq) =
54+
packages
55+
|> Seq.map (fun kv ->
56+
let groupName,packageName = kv.Key
57+
groupName.ToString(),packageName.ToString(),kv.Value.Version.ToString())
58+
|> Seq.toList
59+
60+
let getAllInstalledPackagesFromLockFile (lockFile: LockFile) =
61+
lockFile.GetGroupedResolution() |> listPackages
62+
63+
let getInstalledPackageModel (lockFile: LockFile) (QualifiedPackageName(groupName, packageName)) =
64+
match lockFile.Groups |> Map.tryFind groupName with
65+
| None -> failwithf "Group %O can't be found in paket.lock." groupName
66+
| Some group ->
67+
match group.Resolution.TryFind(packageName) with
68+
| None -> failwithf "Package %O is not installed in group %O." packageName groupName
69+
| Some resolvedPackage ->
70+
let packageName = resolvedPackage.Name
71+
let groupFolder = if groupName = Constants.MainDependencyGroup then "" else "/" + groupName.ToString()
72+
let folder = DirectoryInfo(sprintf "%s/packages%s/%O" lockFile.RootPath groupFolder packageName)
73+
let nuspec = FileInfo(sprintf "%s/packages%s/%O/%O.nuspec" lockFile.RootPath groupFolder packageName packageName)
74+
let nuspec = Nuspec.Load nuspec.FullName
75+
let files = NuGetV2.GetLibFiles(folder.FullName)
76+
let files = files |> Array.map (fun fi -> fi.FullName)
77+
InstallModel.CreateFromLibs(packageName, resolvedPackage.Version, [], files, [], [], nuspec)
78+
79+
let resolveFrameworkForScriptGeneration (dependencies: DependenciesFile) = lazy (
80+
dependencies.Groups
81+
|> Seq.map (fun f -> f.Value.Options.Settings.FrameworkRestrictions)
82+
|> Seq.map(fun restrictions ->
83+
match restrictions with
84+
| Paket.Requirements.AutoDetectFramework -> failwithf "couldn't detect framework"
85+
| Paket.Requirements.FrameworkRestrictionList list ->
86+
list |> Seq.collect (
87+
function
88+
| Paket.Requirements.FrameworkRestriction.Exactly framework
89+
| Paket.Requirements.FrameworkRestriction.AtLeast framework -> Seq.singleton framework
90+
| Paket.Requirements.FrameworkRestriction.Between (bottom,top) -> [bottom; top] |> Seq.ofList //TODO: do we need to cap the list of generated frameworks based on this? also see todo in Requirements.fs for potential generation of range for 'between'
91+
| Paket.Requirements.FrameworkRestriction.Portable portable -> failwithf "unhandled portable framework %s" portable
92+
)
93+
)
94+
|> Seq.concat
95+
)
96+
97+
let resolveEnvironmentFrameworkForScriptGeneration = lazy (
98+
// HACK: resolve .net version based on environment
99+
// list of match is incomplete / inaccurate
100+
#if NETCOREAPP1_0
101+
// Environment.Version is not supported
102+
//dunno what is used for, using a default
103+
DotNetFramework (FrameworkVersion.V4_5)
104+
#else
105+
let version = Environment.Version
106+
match version.Major, version.Minor, version.Build, version.Revision with
107+
| 4, 0, 30319, 42000 -> DotNetFramework (FrameworkVersion.V4_6)
108+
| 4, 0, 30319, _ -> DotNetFramework (FrameworkVersion.V4_5)
109+
| _ -> DotNetFramework (FrameworkVersion.V4_5) // paket.exe is compiled for framework 4.5
110+
#endif
111+
)

‎src/Paket.Core/Requirements.fs‎

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -550,7 +550,8 @@ type InstallSettings =
550550
CopyLocal : bool option
551551
Excludes : string list
552552
Aliases : Map<string,string>
553-
CopyContentToOutputDirectory : CopyToOutputDirectorySettings option }
553+
CopyContentToOutputDirectory : CopyToOutputDirectorySettings option
554+
GenerateLoadScripts : bool option }
554555

555556
static member Default =
556557
{ CopyLocal = None
@@ -562,7 +563,8 @@ type InstallSettings =
562563
Excludes = []
563564
Aliases = Map.empty
564565
CopyContentToOutputDirectory = None
565-
OmitContent = None }
566+
OmitContent = None
567+
GenerateLoadScripts = None }
566568

567569
member this.ToString(asLines) =
568570
let options =
@@ -596,7 +598,11 @@ type InstallSettings =
596598
match this.FrameworkRestrictions with
597599
| FrameworkRestrictionList [] -> ()
598600
| AutoDetectFramework -> ()
599-
| FrameworkRestrictionList list -> yield "framework: " + (String.Join(", ",list))]
601+
| FrameworkRestrictionList list -> yield "framework: " + (String.Join(", ",list))
602+
match this.GenerateLoadScripts with
603+
| Some true -> yield "generate_load_scripts: true"
604+
| Some false -> yield "generate_load_scripts: false"
605+
| None -> () ]
600606

601607
let separator = if asLines then Environment.NewLine else ", "
602608
String.Join(separator,options)
@@ -668,6 +674,11 @@ type InstallSettings =
668674
match getPair "copy_local" with
669675
| Some "false" -> Some false
670676
| Some "true" -> Some true
677+
| _ -> None
678+
GenerateLoadScripts =
679+
match getPair "generate_load_scripts" with
680+
| Some "on" | Some "true" -> Some true
681+
| Some "off" | Some "false" -> Some true
671682
| _ -> None }
672683

673684
// ignore resolver settings here

0 commit comments

Comments
 (0)