/
InstallProcess.fs
575 lines (502 loc) · 29.1 KB
/
InstallProcess.fs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
/// Contains methods for the install process.
module Paket.InstallProcess
open Paket
open Chessie.ErrorHandling
open Paket.Domain
open Paket.Logging
open Paket.BindingRedirects
open Paket.ModuleResolver
open Paket.PackageResolver
open System.IO
open Paket.PackageSources
open Paket.PackagesConfigFile
open Paket.Requirements
open System.Collections.Generic
open Paket.ProjectFile
open System.Diagnostics
open System
let updatePackagesConfigFile (model: Map<GroupName*PackageName,SemVerInfo*InstallSettings>) packagesConfigFileName =
let packagesInConfigFile = PackagesConfigFile.Read packagesConfigFileName
let packagesInModel =
model
|> Seq.filter (fun kv -> defaultArg (snd kv.Value).IncludeVersionInPath false)
|> Seq.map (fun kv ->
{ NugetPackage.Id = (snd kv.Key).ToString()
VersionRange = VersionRange.Specific (fst kv.Value)
CliTool = false
TargetFramework = None })
|> Seq.toList
if packagesInModel <> [] then
packagesInConfigFile
|> Seq.filter (fun p -> packagesInModel |> Seq.exists (fun p' -> p'.Id = p.Id) |> not)
|> Seq.append packagesInModel
|> PackagesConfigFile.Save packagesConfigFileName
let findPackageFolder root (groupName,packageName) (version,settings) =
let includeVersionInPath = defaultArg settings.IncludeVersionInPath false
let storageOption = defaultArg settings.StorageConfig PackagesFolderGroupConfig.Default
match storageOption.Resolve root groupName packageName version includeVersionInPath with
| ResolvedPackagesFolder.ResolvedFolder targetFolder ->
let direct = DirectoryInfo targetFolder
if direct.Exists then
direct
else
let lowerName = packageName.ToString() + if includeVersionInPath then "." + version.ToString() else ""
let di =
if groupName = Constants.MainDependencyGroup then
DirectoryInfo(Path.Combine(root, Constants.DefaultPackagesFolderName))
else
let groupName = groupName.CompareString
let di = DirectoryInfo(Path.Combine(root, Constants.DefaultPackagesFolderName, groupName))
if di.Exists then di else
match di.GetDirectories() |> Seq.tryFind (fun subDir -> String.endsWithIgnoreCase groupName subDir.FullName) with
| Some x -> x
| None ->
traceWarnfn "The following directories exists:"
for d in di.GetDirectories() do
traceWarnfn " %s" d.FullName
failwithf "Group directory for group %s was not found." groupName
match di.GetDirectories() |> Seq.tryFind (fun subDir -> String.endsWithIgnoreCase lowerName subDir.FullName) with
| Some x -> x
| None ->
traceWarnfn "The following directories exists:"
for d in di.GetDirectories() do
traceWarnfn " %s" d.FullName
failwithf "Package directory for package %O was not found." packageName
| ResolvedPackagesFolder.NoPackagesFolder ->
let d = DirectoryInfo(NuGetCache.GetTargetUserFolder packageName version)
if not d.Exists then failwithf "Package directory for package %O was not found." packageName
d
let contentFileBlackList : list<(FileInfo -> bool)> = [
fun f -> f.Name = "_._"
fun f -> f.Name.EndsWith ".transform"
fun f -> f.Name.EndsWith ".pp"
fun f -> f.Name.EndsWith ".tt"
fun f -> f.Name.EndsWith ".ttinclude"
fun f -> f.Name.EndsWith ".install.xdt"
fun f -> f.Name.EndsWith ".uninstall.xdt"
]
let processContentFiles root project (usedPackages:Map<_,_>) gitRemoteItems options =
let contentFiles = System.Collections.Generic.HashSet<_>()
let nuGetFileItems =
let packageDirectoriesWithContent =
usedPackages
|> Seq.map (fun kv ->
let contentCopySettings = defaultArg (snd kv.Value).OmitContent ContentCopySettings.Overwrite
let contentCopyToOutputSettings = (snd kv.Value).CopyContentToOutputDirectory
kv.Key,kv.Value,contentCopySettings,contentCopyToOutputSettings)
|> Seq.filter (fun (_,_,contentCopySettings,_) -> contentCopySettings <> ContentCopySettings.Omit)
|> Seq.map (fun ((group, packName),v,s,s') -> s,s',findPackageFolder root (group, packName) v)
|> Seq.choose (fun (contentCopySettings,contentCopyToOutputSettings,packageDir) ->
packageDir.GetDirectories "Content"
|> Array.append (packageDir.GetDirectories "content")
|> Array.tryFind (fun _ -> true)
|> Option.map (fun x -> x,contentCopySettings,contentCopyToOutputSettings))
|> Seq.toList
let copyContentFiles (project : ProjectFile, packagesWithContent) =
let onBlackList (fi : FileInfo) = contentFileBlackList |> List.exists (fun rule -> rule(fi))
let rec copyDirContents (fromDir : DirectoryInfo, contentCopySettings, toDir : Lazy<DirectoryInfo>) =
fromDir.GetDirectories() |> Array.toList
|> List.collect (fun subDir -> copyDirContents(subDir, contentCopySettings, lazy toDir.Force().CreateSubdirectory(subDir.Name)))
|> List.append
(fromDir.GetFiles()
|> Array.toList
|> List.filter (fun file ->
if onBlackList file then false else
if file.Name = "paket.references" then traceWarnfn "You can't use paket.references as a content file in the root of a project. Please take a look at %s" file.FullName; false else true)
|> List.map (fun file ->
let overwrite = contentCopySettings = ContentCopySettings.Overwrite
let target = FileInfo(Path.Combine(toDir.Force().FullName, file.Name))
contentFiles.Add(target.FullName) |> ignore
if overwrite || not target.Exists then
file.CopyTo(target.FullName, true)
else target))
packagesWithContent
|> List.collect (fun (packageDir,contentCopySettings,contentCopyToOutputSettings) ->
copyDirContents (packageDir, contentCopySettings, lazy (DirectoryInfo(Path.GetDirectoryName(project.FileName))))
|> List.map (fun x -> x,contentCopySettings,contentCopyToOutputSettings))
copyContentFiles(project, packageDirectoriesWithContent)
|> List.map (fun (file,contentCopySettings,contentCopyToOutputSettings) ->
let createSubNodes = contentCopySettings <> ContentCopySettings.OmitIfExisting
{ BuildAction = project.DetermineBuildAction file.Name
Include = createRelativePath project.FileName file.FullName
WithPaketSubNode = createSubNodes
CopyToOutputDirectory = contentCopyToOutputSettings
Link = None })
let removeCopiedFiles (project: ProjectFile) =
let rec removeEmptyDirHierarchy (dir : DirectoryInfo) =
if dir.Exists && dir.EnumerateFileSystemInfos() |> Seq.isEmpty then
dir.Delete()
removeEmptyDirHierarchy dir.Parent
let removeFilesAndTrimDirs (files: FileInfo list) =
for f in files do
if f.Exists then
f.Delete()
let dirsPathsDeepestFirst =
files
|> List.map (fun f -> f.Directory.FullName)
|> List.distinct
|> List.rev
for dirPath in dirsPathsDeepestFirst do
removeEmptyDirHierarchy (DirectoryInfo dirPath)
project.GetPaketFileItems()
|> List.filter (fun fi ->
not (fi.FullName.Contains Constants.PaketFilesFolderName) &&
not (contentFiles.Contains fi.FullName) &&
fi.Name <> "paket.references")
|> removeFilesAndTrimDirs
removeCopiedFiles project
project.UpdateFileItems(gitRemoteItems @ nuGetFileItems)
/// Restores the given packages from the lock file.
let CreateModel(alternativeProjectRoot, root, force, dependenciesFile:DependenciesFile, lockFile : LockFile, packages:Set<GroupName*PackageName>, updatedGroups:Map<_,_>) =
for kv in lockFile.Groups do
let files = if updatedGroups |> Map.containsKey kv.Key then [] else kv.Value.RemoteFiles
if List.isEmpty files |> not then
RemoteDownload.DownloadSourceFiles(root, kv.Key, force, files)
lockFile.Groups
|> Seq.map (fun kv' ->
let sources = dependenciesFile.Groups.[kv'.Key].Sources
let caches = dependenciesFile.Groups.[kv'.Key].Caches
kv'.Value.Resolution
|> Map.filter (fun name _ -> packages.Contains(kv'.Key,name))
|> Seq.map (fun kv -> RestoreProcess.CreateInstallModel(alternativeProjectRoot, root,kv'.Key,sources,caches,force,kv'.Value.GetPackage kv.Key))
|> Seq.toArray
|> Async.Parallel
|> Async.RunSynchronously)
|> Seq.concat
|> Seq.toArray
let inline private getOrAdd (key: 'key) (getValue: 'key -> 'value) (d: Dictionary<'key, 'value>) : 'value =
let value: 'value ref = ref Unchecked.defaultof<_>
if d.TryGetValue(key, value) then !value
else
let value = getValue key
d.[key] <- value
value
// HashSet to prevent repeating the same "Broken project dependency" warning
let brokenDeps = HashSet<_>()
/// Applies binding redirects for all strong-named references to all app. and web.config files.
let private applyBindingRedirects isFirstGroup createNewBindingFiles cleanBindingRedirects
root groupName findDependencies allKnownLibNames
(projectCache: Dictionary<string, ProjectFile option>)
(extractedPackages:seq<InstallModel * _>) =
let dependencyGraph = Dictionary<_,Set<_>>()
let referenceFiles = Dictionary<_,ReferencesFile option>()
let referenceFile (projectFile : ProjectFile) =
let referenceFile (projectFile : ProjectFile) =
projectFile.FindReferencesFile()
|> Option.map ReferencesFile.FromFile
referenceFiles |> getOrAdd projectFile referenceFile
let rec dependencies (projectFile : ProjectFile) =
let reportBrokenDep (src:string) (target:string) =
if brokenDeps.Add (src,target) then
traceWarnfn "Broken project dependency: '%s' -> '%s'" src target
match referenceFile projectFile with
| Some referenceFile ->
projectFile.GetInterProjectDependencies()
|> Seq.map (fun r ->
let found = getOrAdd r.Path ProjectFile.TryLoad projectCache
match found with
| Some prj -> Some prj
| None ->
reportBrokenDep projectFile.FileName r.Path
None)
|> Seq.choose id
|> Seq.map (fun p -> dependencyGraph |> getOrAdd p dependencies)
|> Set.unionMany
|> Set.union (
referenceFile.Groups
|> Seq.filter (fun g -> g.Key = groupName)
|> Seq.collect (fun g -> g.Value.NugetPackages |> List.map (fun p -> (groupName,p.Name)))
|> Seq.collect(fun (g,p) -> findDependencies(g,p,projectFile.FileName))
|> Seq.map (fun x -> x, projectFile.GetTargetProfile())
|> Set.ofSeq)
| None -> Set.empty
let bindingRedirects (projectFile : ProjectFile) =
let referenceFile = referenceFile projectFile
let dependencies = dependencyGraph |> getOrAdd projectFile dependencies
let redirectsFromReference packageName =
referenceFile
|> Option.bind (fun r ->
r.Groups
|> Seq.filter (fun g -> g.Key = groupName)
|> Seq.collect (fun g -> g.Value.NugetPackages)
|> Seq.tryFind (fun p -> p.Name = packageName)
|> Option.bind (fun p -> p.Settings.CreateBindingRedirects))
let targetProfile = projectFile.GetTargetProfile()
let assemblies =
extractedPackages
|> Seq.map (fun (model,redirects) -> (model, redirectsFromReference model.PackageName |> Option.fold (fun _ x -> Some x) redirects))
|> Seq.collect (fun (model,redirects) ->
dependencies
|> Set.filter (fst >> ((=) model.PackageName))
|> Seq.collect (fun (_,profile) ->
model.GetLegacyReferences profile
|> Seq.map (fun x -> x, redirects, profile)))
|> Seq.groupBy (fun (p,_,profile) -> profile,FileInfo(p.Path).Name)
|> Seq.choose(fun (_,librariesForPackage) ->
librariesForPackage
|> Seq.choose(fun (library,redirects,profile) ->
try
let assembly = Mono.Cecil.AssemblyDefinition.ReadAssembly(library.Path)
Some (assembly, BindingRedirects.getPublicKeyToken assembly, assembly.MainModule.AssemblyReferences, redirects, profile)
with _ -> None)
|> Seq.sortBy(fun (assembly,_,_,_,_) -> assembly.Name.Version)
|> Seq.toList
|> List.rev
|> function | head :: _ -> Some head | _ -> None)
|> Seq.cache
let referencesDifferentProfiles (assemblyName : Mono.Cecil.AssemblyNameDefinition) profile =
profile = targetProfile
&& assemblies
|> Seq.filter (fun (_,_,_,_,p) -> p <> profile)
|> Seq.map (fun (a,_,_,_,_) -> a.Name)
|> Seq.filter (fun a -> a.Name = assemblyName.Name)
|> Seq.exists (fun a -> a.Version <> assemblyName.Version)
assemblies
|> Seq.choose (fun (assembly,token,refs,redirects,profile) ->
token |> Option.map (fun token -> (assembly,token,refs,redirects,profile)))
|> Seq.filter (fun (_,_,_,redirects,_) ->
match redirects with
| Some BindingRedirectsSettings.On
| Some BindingRedirectsSettings.Force -> true
| Some BindingRedirectsSettings.Off -> false
| _ -> false)
|> Seq.filter (fun (assembly,_,_,redirects,profile) ->
let assemblyName = assembly.Name
redirects = Some BindingRedirectsSettings.Force
|| referencesDifferentProfiles assemblyName profile
|| assemblies
|> Seq.collect (fun (_,_,refs,_,_) -> refs)
|> Seq.filter (fun a -> assemblyName.Name = a.Name)
|> Seq.exists (fun a -> assemblyName.Version > a.Version))
|> Seq.map(fun (assembly, token,_,_,_) ->
{ BindingRedirect.AssemblyName = assembly.Name.Name
Version = assembly.Name.Version.ToString()
PublicKeyToken = token
Culture = None })
|> Seq.sort
applyBindingRedirectsToFolder isFirstGroup createNewBindingFiles cleanBindingRedirects root allKnownLibNames bindingRedirects
let invalidateRestoreCachesForDotnetSdk (projectFileInfo:FileInfo) =
let paketPropsFile = ProjectFile.getPaketPropsFileInfo projectFileInfo
if paketPropsFile.Exists then
let old = File.ReadAllText paketPropsFile.FullName
let newContent = old.Replace("<!-- <RestoreSuccess>False</RestoreSuccess> -->","<RestoreSuccess>False</RestoreSuccess>")
File.WriteAllText(paketPropsFile.FullName, newContent)
let assetsFile = ProjectFile.getAssetsFileInfo projectFileInfo
if assetsFile.Exists then
try assetsFile.Delete() with | _ -> ()
let installForDotnetSDK root (project:ProjectFile) =
let paketTargetsPath = RestoreProcess.extractRestoreTargets root
let relativePath = createRelativePath project.FileName paketTargetsPath
project.RemoveImportForPaketTargets()
project.AddImportForPaketTargets(relativePath)
let projectFileInfo = FileInfo(project.FileName)
invalidateRestoreCachesForDotnetSdk (projectFileInfo)
/// Installs all packages from the lock file.
let InstallIntoProjects(options : InstallerOptions, forceTouch, dependenciesFile, lockFile : LockFile, projectsAndReferences : (ProjectFile * ReferencesFile) list, updatedGroups) =
tracefn " - Creating model and downloading packages."
let packagesToInstall =
if options.OnlyReferenced then
projectsAndReferences
|> List.map (fun (_, referencesFile)->
referencesFile
|> lockFile.GetPackageHull
|> Seq.map (fun p -> p.Key))
|> Seq.concat
else
lockFile.GetGroupedResolution()
|> Seq.map (fun kv -> kv.Key)
let root = Path.GetDirectoryName lockFile.FileName
let model = CreateModel(options.AlternativeProjectRoot, root, options.Force, dependenciesFile, lockFile, Set.ofSeq packagesToInstall, updatedGroups) |> Map.ofArray
let lookup = lockFile.GetDependencyLookupTable()
let projectCache = Dictionary<string, ProjectFile option>();
let prefix = dependenciesFile.Directory.Length + 1
let norm (s:string) = (s.Substring prefix).Replace('\\', '/')
let groupSettings = lockFile.Groups |> Map.map (fun k v -> v.Options.Settings)
for project, referenceFile in projectsAndReferences do
tracefn " - %s -> %s" (norm referenceFile.FileName) (norm project.FileName)
let toolsVersion = project.GetToolsVersion()
if verbose then
verbosefn "Installing to %s with ToolsVersion %O" project.FileName toolsVersion
let directDependencies, errorMessages =
referenceFile.Groups
|> Seq.map (fun kv ->
lockFile.GetRemoteReferencedPackages(referenceFile,kv.Value) @ kv.Value.NugetPackages
|> Seq.map (fun ps ->
let group =
match lockFile.Groups |> Map.tryFind kv.Key with
| Some g -> Choice1Of2 g
| None -> Choice2Of2 (sprintf " - %s uses the group %O, but this group was not found in paket.lock." referenceFile.FileName kv.Key)
let package =
match model |> Map.tryFind (kv.Key, ps.Name) with
| Some (p,_) -> Choice1Of2 p
| None -> Choice2Of2 (sprintf " - %s uses NuGet package %O, but it was not found in the paket.lock file in group %O.%s" referenceFile.FileName ps.Name kv.Key (lockFile.CheckIfPackageExistsInAnyGroup ps.Name))
match group, package with
| Choice1Of2 _, Choice1Of2 package ->
((kv.Key,package.Name), (package.Version, ps.Settings + package.Settings))
|> Choice1Of2
| Choice2Of2 error1, Choice2Of2 error2 -> Choice2Of2 (error1 + "\n" + error2)
| Choice2Of2 error, _ | _, Choice2Of2 error -> Choice2Of2 error
))
|> Seq.concat
|> Seq.partitionAndChoose
(function Choice1Of2 _ -> true | Choice2Of2 _ -> false)
(function Choice1Of2 resolvedPackage -> Some resolvedPackage | _ -> None)
(function Choice2Of2 errorMessage -> Some errorMessage | _ -> None)
|> fun (resolvedPackages, dependencyErrors) ->
Map.ofSeq resolvedPackages, dependencyErrors
let usedPackages, errorMessages =
let mutable d = directDependencies
/// we want to treat the settings from the references file through the computation so that it can be used as the base that
/// the other settings modify. In this way we ensure that references files can override the dependencies file, which in turn overrides the lockfile.
let usedPackageDependencies, groupErrors =
directDependencies
|> Seq.collect (fun u -> lookup.[u.Key] |> Seq.map (fun i -> fst u.Key, u.Value, i))
|> Seq.partitionAndChoose
(fun (groupName,(_,parentSettings), dep) ->
lockFile.Groups |> Map.containsKey groupName)
(fun (groupName,(_,parentSettings), dep) ->
let group = lockFile.Groups.[groupName]
match group.TryFind dep with
| None -> None
| Some p ->
Some ((groupName,p.Name), (p.Version,parentSettings + p.Settings)) )
(fun (groupName,(_,parentSettings), dep) ->
Some (sprintf " - %s uses the group %O, but this group was not found in paket.lock." referenceFile.FileName groupName)
)
for key,settings in usedPackageDependencies do
if d.ContainsKey key |> not then
d <- Map.add key settings d
d, Seq.append errorMessages groupErrors
let usedPackages, errorMessages =
let dict = System.Collections.Generic.Dictionary<PackageName,SemVerInfo*bool>()
let errors = ResizeArray ()
usedPackages
|> Map.filter (fun (_groupName,packageName) (v,model) ->
let hasCondition = model.ReferenceCondition.IsSome
match dict.TryGetValue packageName with
| true,(v',true) when hasCondition ->
true
| true,(v',hasCondition') ->
if v' = v then
traceWarnfn "Package %O is referenced through multiple groups in %s (inspect lockfile for details). To resolve this warning use a single group for this project to get a unified dependency resolution or use conditions on the groups if you know what you are doing." packageName project.FileName
false
else
errors.Add (sprintf "Package %O is referenced in different versions in %s (%O vs %O), (inspect the lockfile for details) to resolve this either add all dependencies to a single group (to get a unified resolution) or use a condition on both groups and control compilation yourself." packageName project.FileName v' v)
false
| _ ->
dict.Add(packageName,(v,hasCondition))
true)
|> fun usedPackages -> usedPackages, Seq.append errorMessages errors
let gitRemotePathPairs, errorMessages =
((Seq.empty,Seq.empty),referenceFile.Groups)
||> Seq.fold (fun (pathAcc,errorAcc) kv ->
let refpaths, errors =
kv.Value.RemoteFiles
|> Seq.partitionAndChoose
// reject files with missing group names or who can't be found in the group specified
(fun remoteFile ->
match lockFile.Groups |> Map.tryFind kv.Key with
| None -> false
| Some group ->
group.RemoteFiles
|> Seq.exists (fun f -> Path.GetFileName(f.Name) = remoteFile.Name))
// get the full path of the remote item
(fun remoteFile ->
let group = lockFile.Groups.[kv.Key]
group.RemoteFiles
|> Seq.find (fun f -> Path.GetFileName(f.Name) = remoteFile.Name)
|> fun file -> Some (remoteFile, (file.FilePath(root,kv.Key))))
(fun remoteFile ->
Some (sprintf "%s references file %s in group %O, but it was not found in the paket.lock file." referenceFile.FileName remoteFile.Name kv.Key)
)
(Seq.append pathAcc refpaths),(Seq.append errorAcc errors)
)|> fun (refpaths,errors) -> Seq.toArray refpaths, Seq.concat [| errorMessages ; errors |] |> Seq.toArray
if toolsVersion >= 15.0 then
// HACK: just validate that the list of packages contains one named FSharp.Core, if it is a *.fsproj
if project.Name.EndsWith(".fsproj", StringComparison.OrdinalIgnoreCase) then
let hasFSharpCore =
usedPackages |> Seq.exists (fun kv ->
let (_, x) = kv.Key
x.CompareString = "fsharp.core")
if not hasFSharpCore then
traceWarnfn "F# project %s does not reference FSharp.Core." project.FileName
// if any errors have been found during the installation process thus far, fail and print all errors collected
if not (Seq.isEmpty errorMessages) then
failwithf "Installation Errors :\n%s" (String.concat "\n" errorMessages)
else // start the installation process
if toolsVersion >= 15.0 then
installForDotnetSDK root project
else
project.UpdateReferences(root, model, directDependencies, usedPackages)
Path.Combine(FileInfo(project.FileName).Directory.FullName, Constants.PackagesConfigFile)
|> updatePackagesConfigFile usedPackages
let gitRemoteItems =
gitRemotePathPairs
|> Seq.map (fun (file,remoteFilePath) ->
let link = if file.Link = "." then Path.GetFileName file.Name else Path.Combine(file.Link, Path.GetFileName file.Name)
if verbose then
tracefn "FileName: %s " file.Name
let linked = defaultArg file.Settings.Link true
let buildAction = project.DetermineBuildActionForRemoteItems file.Name
if buildAction <> BuildAction.Reference && linked then
{ BuildAction = buildAction
Include = createRelativePath project.FileName remoteFilePath
WithPaketSubNode = true
CopyToOutputDirectory = None
Link = Some link
}
else
{ BuildAction = buildAction
WithPaketSubNode = true
CopyToOutputDirectory = None
Include =
if buildAction = BuildAction.Reference then
createRelativePath project.FileName remoteFilePath
else
let toDir = Path.GetDirectoryName(project.FileName)
let targetFile = FileInfo(Path.Combine(toDir,link))
if targetFile.Directory.Exists |> not then
targetFile.Directory.Create()
File.Copy(remoteFilePath,targetFile.FullName,true)
createRelativePath project.FileName targetFile.FullName
Link = None
}
) |> Seq.toList
processContentFiles root project usedPackages gitRemoteItems options
project.Save forceTouch
projectCache.[project.FileName] <- Some project
let first = ref true
let allKnownLibNames =
model
|> Seq.map (fun kv -> (snd kv.Value).GetAllLegacyReferenceAndFrameworkReferenceNames())
|> Set.unionMany
let commandRedirects =
if options.Redirects = BindingRedirectsSettings.Off then None
else Some options.Redirects
for g in lockFile.Groups do
let group = g.Value
let groupRedirects =
g.Value.Options.Redirects ++ commandRedirects
model
|> Seq.filter (fun kv -> (fst kv.Key) = g.Key)
|> Seq.map (fun kv ->
let packageRedirects =
group.Resolution
|> Map.tryFind (snd kv.Key)
|> Option.bind (fun p -> p.Settings.CreateBindingRedirects ++ groupRedirects)
(snd kv.Value,packageRedirects))
|> applyBindingRedirects
!first
options.CreateNewBindingFiles
options.CleanBindingRedirects
(FileInfo project.FileName).Directory.FullName
g.Key
lockFile.GetAllDependenciesOf
allKnownLibNames
projectCache
first := false
/// Installs all packages from the lock file.
let Install(options : InstallerOptions, forceTouch, dependenciesFile, lockFile : LockFile, updatedGroups) =
let root = FileInfo(lockFile.FileName).Directory.FullName
let projects = RestoreProcess.findAllReferencesFiles root |> returnOrFail
InstallIntoProjects(options, forceTouch, dependenciesFile, lockFile, projects, updatedGroups)