Skip to content
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

Generate include script for each group #1787

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
159 changes: 134 additions & 25 deletions src/Paket.Core/ScriptGeneration.fs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,12 @@ module PackageAndAssemblyResolution =

module ScriptGeneration =
open PackageAndAssemblyResolution

type ScriptPiece =
| ReferenceAssemblyFile of FileInfo
| ReferenceFrameworkAssembly of string
| LoadScript of FileInfo
| PrintStatement of string

type ScriptGenInput = {
PackageName : PackageName
Expand All @@ -75,12 +81,12 @@ module ScriptGeneration =
IncludeScriptsRootFolder : DirectoryInfo
DependentScripts : FileInfo list
FrameworkReferences : string list
OrderedRelativeDllReferences : string list
OrderedDllReferences : FileInfo list
}

type ScriptGenResult =
| DoNotGenerate
| Generate of lines : string list
| Generate of lines : ScriptPiece list

let private makeRelativePath (scriptFile: FileInfo) (libFile: FileInfo) =
(Uri scriptFile.FullName).MakeRelativeUri(Uri libFile.FullName).ToString()
Expand All @@ -91,8 +97,7 @@ module ScriptGeneration =

let depLines =
input.DependentScripts
|> List.map (fun fi -> fi.Name)
|> List.map (sprintf """#load @"%s" """)
|> List.map LoadScript

let frameworkRefLines =
input.FrameworkReferences
Expand All @@ -104,42 +109,93 @@ module ScriptGeneration =
false
| _ -> true
)
|> List.map (sprintf """#r "%s" """)
|> List.map ReferenceFrameworkAssembly

let dllLines =
match packageName.ToLowerInvariant() with
| "fsharp.core" -> []
| _ ->
input.OrderedRelativeDllReferences
|> List.map (sprintf """#r "%s" """)
input.OrderedDllReferences
|> List.map ReferenceAssemblyFile

let lines = List.concat [depLines; frameworkRefLines; dllLines]
match lines with
| [] -> DoNotGenerate
| xs -> List.append xs [ sprintf "printfn \"%%s\" \"Loaded %s\"" packageName ] |> Generate
| xs -> List.append xs [ PrintStatement (sprintf "%s Loaded" packageName) ] |> Generate

/// default implementation of C# include script generator
let generateCSharpScript (input: ScriptGenInput) =
let packageName = input.PackageName.GetCompareString()

let depLines =
input.DependentScripts
|> List.map (fun fi -> fi.Name)
|> List.map (sprintf """#load "%s" """)
|> List.map LoadScript

let frameworkRefLines =
input.FrameworkReferences
|> List.map (sprintf """#r "%s" """)
|> List.map ReferenceFrameworkAssembly

let dllLines =
input.OrderedRelativeDllReferences
|> List.map (sprintf """#r "%s" """)
input.OrderedDllReferences
|> List.map ReferenceAssemblyFile

let lines = List.concat [depLines; frameworkRefLines; dllLines]

match lines with
| [] -> DoNotGenerate
| xs -> List.append xs [ sprintf "System.Console.WriteLine(\"Loaded {0}\", \"%s\");" packageName ] |> Generate
| xs -> List.append xs [ PrintStatement (sprintf "%s Loaded" packageName) ] |> Generate

let writeFSharpScript scriptFile input =
let pieces = [
for piece in input do
yield
match piece with
| ReferenceAssemblyFile file ->
makeRelativePath scriptFile file
|> sprintf """#r "%s" """
| LoadScript script ->
makeRelativePath scriptFile script
|> sprintf """#load @"%s" """
| ReferenceFrameworkAssembly name ->
sprintf """#r "%s" """ name
| PrintStatement text ->
let escape =
// /!\ /!\ /!\ TODO escape text /!\ /!\ /!\
id
sprintf @"printfn ""%s"" " (escape text)
]

let text =
pieces
|> String.concat ("\n")

File.WriteAllText(scriptFile.FullName, text)

let writeCSharpScript scriptFile input =
let pieces = [
for piece in input do
yield
match piece with
| ReferenceAssemblyFile file ->
makeRelativePath scriptFile file
|> sprintf """#r "%s" """
| LoadScript script ->
makeRelativePath scriptFile script
|> sprintf """#load "%s" """
| ReferenceFrameworkAssembly name ->
sprintf """#r "%s" """ name
| PrintStatement text ->
let escape =
// /!\ /!\ /!\ TODO escape text /!\ /!\ /!\
id
sprintf @"System.Console.WriteLine(""%s""); " (escape text)
]

let text =
pieces
|> String.concat ("\n")

File.WriteAllText(scriptFile.FullName, text)

let getIncludeScriptRootFolder (includeScriptsRootFolder: DirectoryInfo) (framework: FrameworkIdentifier) =
DirectoryInfo(Path.Combine(includeScriptsRootFolder.FullName, string framework))
Expand All @@ -160,12 +216,57 @@ module ScriptGeneration =
None
else
Some (groupName.ToString())

let generateGroupScript
(deps : Dependencies)
(getScriptFile : GroupName -> FileInfo)
(writeScript : FileInfo -> ScriptPiece seq -> unit)
(framework : FrameworkIdentifier)
=
let all =
seq {
for group, nuget, _ in deps.GetInstalledPackages() do
let model = deps.GetInstalledPackageModel(Some group, nuget)
let libs = model.GetLibReferences(framework) |> Seq.map FileInfo
let syslibs = model.GetFrameworkAssembliesLazy.Value
yield group, (libs, syslibs |> Set.toSeq)
}
|> Seq.groupBy fst
|> Seq.map (fun (group, items) -> group, items |> Seq.map snd)

for group, libs in all do
let assemblies, frameworkLibs =
Seq.foldBack (fun (l,r) (pl, pr) -> Seq.concat [pl ; l], Seq.concat [pr ; r]) libs (Seq.empty, Seq.empty)
|> fun (l,r) -> Seq.distinct l, Seq.distinct r

let assemblies =
let assemblyFilePerAssemblyDef =
assemblies
|> Seq.map (fun f -> f.FullName |> AssemblyDefinition.ReadAssembly, f)
|> dict

assemblyFilePerAssemblyDef.Keys
|> Seq.toList
|> PackageAndAssemblyResolution.getDllOrder
|> Seq.map (assemblyFilePerAssemblyDef.TryGetValue >> snd)

let scriptFile = getScriptFile (GroupName group)

[
for a in frameworkLibs do
yield ScriptPiece.ReferenceFrameworkAssembly a
for a in assemblies do
yield ScriptPiece.ReferenceAssemblyFile a
yield ScriptPiece.PrintStatement (sprintf "Loaded group %s" group)
]
|> writeScript scriptFile

/// Generate a include script from given order of packages,
/// if a package is ordered before its dependencies this function
/// will throw.
let generateScripts
(scriptGenerator : ScriptGenInput -> ScriptGenResult)
(writeScript : FileInfo -> ScriptPiece seq -> unit)
(getScriptFile : GroupName -> PackageName -> FileInfo)
(includeScriptsRootFolder : DirectoryInfo)
(framework : FrameworkIdentifier)
Expand All @@ -182,23 +283,23 @@ module ScriptGeneration =
let groupName = getGroupNameAsOption groupName
let dependencies = package.Dependencies |> Seq.map fst' |> Seq.choose knownIncludeScripts.TryFind |> List.ofSeq
let installModel = dependenciesFile.GetInstalledPackageModel(groupName, package.Name.ToString())
let dllFiles = getDllsWithinPackage framework installModel |> List.map (makeRelativePath scriptFile)
let dllFiles = getDllsWithinPackage framework installModel

let scriptInfo = {
PackageName = installModel.PackageName
Framework = framework
PackagesOrGroupFolder = packagesOrGroupFolder
IncludeScriptsRootFolder = includeScriptsRootFolder
FrameworkReferences = getFrameworkReferencesWithinPackage installModel
OrderedRelativeDllReferences = dllFiles
OrderedDllReferences = dllFiles
DependentScripts = dependencies
}

match scriptGenerator scriptInfo with
| DoNotGenerate -> knownIncludeScripts
| Generate lines ->
| Generate pieces ->
scriptFile.Directory.Create()
File.WriteAllLines (scriptFile.FullName, lines)
writeScript scriptFile pieces
knownIncludeScripts |> Map.add package.Name scriptFile

) Map.empty
Expand All @@ -207,7 +308,7 @@ module ScriptGeneration =

/// Generate a include scripts for all packages defined in paket.dependencies,
/// if a package is ordered before its dependencies this function will throw.
let generateScriptsForRootFolderGeneric extension scriptGenerator (framework: FrameworkIdentifier) (rootFolder: DirectoryInfo) =
let generateScriptsForRootFolderGeneric extension scriptGenerator scriptWriter (framework: FrameworkIdentifier) (rootFolder: DirectoryInfo) =
let dependenciesFile, lockFile =
let deps = Paket.Dependencies.Locate(rootFolder.FullName)
let lock =
Expand All @@ -222,7 +323,8 @@ module ScriptGeneration =
let packagesFolder = DirectoryInfo(Path.Combine(rootFolder.FullName, Constants.PackagesFolderName))

let includeScriptsRootFolder =
DirectoryInfo(Path.Combine((FileInfo dependenciesFile.DependenciesFile).Directory.FullName, Constants.PaketFilesFolderName, "include-scripts"))
Path.Combine((FileInfo dependenciesFile.DependenciesFile).Directory.FullName, Constants.PaketFilesFolderName, "include-scripts")
|> DirectoryInfo

let getScriptFile groupName packageName =
getScriptFile includeScriptsRootFolder framework groupName packageName extension
Expand All @@ -235,10 +337,17 @@ module ScriptGeneration =
| None -> packagesFolder
| Some groupName -> DirectoryInfo(Path.Combine(packagesFolder.FullName, groupName))

generateScripts scriptGenerator getScriptFile includeScriptsRootFolder framework dependenciesFile packagesOrGroupFolder groupName packages
generateScripts scriptGenerator scriptWriter getScriptFile includeScriptsRootFolder framework dependenciesFile packagesOrGroupFolder groupName packages
)
|> ignore

let getGroupFile group =
let folder = getScriptFolder includeScriptsRootFolder framework group
Path.Combine(folder.FullName, sprintf "include.%s.group.%s" (group.GetCompareString()) extension).ToLowerInvariant()
|> FileInfo

generateGroupScript dependenciesFile getGroupFile scriptWriter framework

type ScriptType =
| CSharp
| FSharp
Expand All @@ -254,9 +363,9 @@ module ScriptGeneration =
| _ -> None

let generateScriptsForRootFolder scriptType =
let scriptGenerator =
let scriptGenerator, scriptWriter =
match scriptType with
| CSharp -> generateCSharpScript
| FSharp -> generateFSharpScript
| CSharp -> generateCSharpScript, writeCSharpScript
| FSharp -> generateFSharpScript, writeFSharpScript

generateScriptsForRootFolderGeneric scriptType.Extension scriptGenerator
generateScriptsForRootFolderGeneric scriptType.Extension scriptGenerator scriptWriter
2 changes: 1 addition & 1 deletion tests/Paket.Tests/ScriptGeneration/LoadingScriptTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ let scriptGenInputWithNoDendency = {
IncludeScriptsRootFolder = DirectoryInfo "b"
DependentScripts = List.empty
FrameworkReferences = List.empty
OrderedRelativeDllReferences = List.empty
OrderedDllReferences = List.empty
}

[<Test>]
Expand Down