From 2fe7014f84ec5f12c81e8f94211d5e3d3b7083e6 Mon Sep 17 00:00:00 2001 From: Isaac Abraham Date: Thu, 11 Sep 2014 23:32:56 +0100 Subject: [PATCH 1/2] initial work. --- src/Paket/BasicTypes.fs | 18 ++++++++++++ src/Paket/DependenciesFile.fs | 40 +++++++++++++++++++-------- src/Paket/GitHub.fs | 13 +++++++++ src/Paket/LockFile.fs | 13 +++++---- src/Paket/Paket.fsproj | 8 ++++-- src/Paket/Process.fs | 36 ++++++++++++++++++------ src/Paket/Program.fs | 1 - src/Paket/ProjectFile.fs | 2 +- src/Paket/Resolver.fs | 2 +- tests/ManualCSTest/paket.dependencies | 5 +++- 10 files changed, 105 insertions(+), 33 deletions(-) create mode 100644 src/Paket/GitHub.fs diff --git a/src/Paket/BasicTypes.fs b/src/Paket/BasicTypes.fs index 134fbf323e..1c4c36f174 100644 --- a/src/Paket/BasicTypes.fs +++ b/src/Paket/BasicTypes.fs @@ -84,6 +84,22 @@ type PackageSource = | true, uri -> if uri.Scheme = System.Uri.UriSchemeFile then LocalNuget(source) else Nuget(source) | _ -> failwith "unable to parse package source: %s" source +// Represents details on a dependent source file. +type SourceFileDetails = + { Owner : string + Project : string + Path : string + Commit : string option } + member this.FilePath = + this.Path + .TrimStart('/') + .Replace("/", "\\") + +// The different types of source files. +type SourceFile = | GitHub of File : SourceFileDetails + +// TODO: Perhaps Source File and Package should be merged into a DU? + /// Represents a package. type Package = { Name : string @@ -92,6 +108,8 @@ type Package = ResolverStrategy : ResolverStrategy Sources : PackageSource list } + + /// Represents a package dependency. type PackageDependency = { Defining : Package diff --git a/src/Paket/DependenciesFile.fs b/src/Paket/DependenciesFile.fs index ea6cabdd78..2921341015 100644 --- a/src/Paket/DependenciesFile.fs +++ b/src/Paket/DependenciesFile.fs @@ -33,7 +33,7 @@ module DependenciesFileParser = with | _ -> failwithf "could not parse version range \"%s\"" text - let private (|Remote|Package|Blank|) (line:string) = + let private (|Remote|Package|Blank|GitHubFile|) (line:string) = match line.Trim() with | _ when String.IsNullOrWhiteSpace line -> Blank | trimmed when trimmed.StartsWith "source" -> @@ -41,16 +41,26 @@ module DependenciesFileParser = let snd = trimmed.IndexOf("\"",fst+1) Remote (trimmed.Substring(fst,snd-fst).Replace("\"","")) | trimmed when trimmed.StartsWith "nuget" -> Package(trimmed.Replace("nuget","").Trim()) + | trimmed when trimmed.StartsWith "github" -> + let parts = trimmed.Replace("\"", "").Split ' ' + let getParts (projectSpec:string) = + match projectSpec.Split ':' with + | [| owner; project |] -> owner, project, None + | [| owner; project; commit |] -> owner, project, Some commit + | _ -> failwith "invalid github specification" + match parts with + | [| _; projectSpec; fileSpec |] -> GitHubFile(getParts projectSpec, fileSpec) + | _ -> failwith "invalid github specification" | _ -> Blank let parseDependenciesFile (lines:string seq) = - ((0,[], []), lines) - ||> Seq.fold(fun (lineNo, sources: PackageSource list, packages) line -> + ((0,[], [], []), lines) + ||> Seq.fold(fun (lineNo, sources: PackageSource list, packages, remoteFiles) line -> let lineNo = lineNo + 1 try match line with - | Remote newSource -> lineNo, (PackageSource.Parse(newSource.TrimEnd([|'/'|])) :: sources), packages - | Blank -> lineNo, sources, packages + | Remote newSource -> lineNo, (PackageSource.Parse(newSource.TrimEnd([|'/'|])) :: sources), packages, remoteFiles + | Blank -> lineNo, sources, packages, remoteFiles | Package details -> let parts = details.Split('"') if parts.Length < 4 || String.IsNullOrWhiteSpace parts.[1] || String.IsNullOrWhiteSpace parts.[3] then @@ -60,19 +70,27 @@ module DependenciesFileParser = Name = parts.[1] DirectDependencies = [] ResolverStrategy = if version.StartsWith "!" then ResolverStrategy.Min else ResolverStrategy.Max - VersionRange = parseVersionRange(version.Trim '!') } :: packages + VersionRange = parseVersionRange(version.Trim '!') } :: packages, remoteFiles + | GitHubFile((owner,project, commit), path) -> + lineNo, sources, packages, + GitHub { Owner = owner + Project = project + Commit = commit + Path = path } :: remoteFiles + with | exn -> failwithf "Error in paket.dependencies line %d%s %s" lineNo Environment.NewLine exn.Message) - |> fun (_,_,x) -> x - |> List.rev + |> fun (_,_,packages,remoteFiles) -> + packages |> List.rev, + remoteFiles |> List.rev /// Allows to parse and analyze Dependencies files. -type DependenciesFile(packages : Package seq) = - let packages = packages |> Seq.toList +type DependenciesFile(packages : Package list, remoteFiles : SourceFile list) = let dependencyMap = Map.ofSeq (packages |> Seq.map (fun p -> p.Name, p.VersionRange)) member __.DirectDependencies = dependencyMap member __.Packages = packages - member __.Resolve(force, discovery : IDiscovery) = Resolver.Resolve(force, discovery, packages) + member __.RemoteFiles = remoteFiles + member __.Resolve(force, discovery : IDiscovery) = PackageResolver.Resolve(force, discovery, packages) static member FromCode(code:string) : DependenciesFile = DependenciesFile(DependenciesFileParser.parseDependenciesFile <| code.Replace("\r\n","\n").Replace("\r","\n").Split('\n')) static member ReadFromFile fileName : DependenciesFile = diff --git a/src/Paket/GitHub.fs b/src/Paket/GitHub.fs new file mode 100644 index 0000000000..8989fadeab --- /dev/null +++ b/src/Paket/GitHub.fs @@ -0,0 +1,13 @@ +module Paket.GitHub + +open System.Net +open System +open Paket + +/// Gets a single file from github. +let downloadFile (remoteFile:SourceFileDetails) = + let commit = defaultArg remoteFile.Commit "master" + let url = sprintf "https://github.com/%s/%s/raw/%s/%s" remoteFile.Owner remoteFile.Project commit remoteFile.Path + use wc = new WebClient() + Uri url |> wc.AsyncDownloadString + diff --git a/src/Paket/LockFile.fs b/src/Paket/LockFile.fs index e83f5ab105..0fdd0f7c71 100644 --- a/src/Paket/LockFile.fs +++ b/src/Paket/LockFile.fs @@ -112,17 +112,18 @@ let Parse(lines : string seq) = |> List.rev /// Analyzes the dependencies from the Dependencies file. -let Create(force,dependenciesFile) = +let Create(force, dependenciesFile) = let cfg = DependenciesFile.ReadFromFile dependenciesFile tracefn "Analyzing %s" dependenciesFile - cfg.Resolve(force,Nuget.NugetDiscovery) + cfg.Resolve(force, Nuget.NugetDiscovery) /// Updates the Lock file with the analyzed dependencies from the Dependencies file. -let Update(force, packageFile, lockFile) = - let resolution = Create(force,packageFile) - let errors = extractErrors resolution +let Update(force, dependenciesFile:DependenciesFile, lockFile) = + tracefn "Analyzing %s" dependenciesFile + let packageResolution = dependenciesFile.Resolve(force, Nuget.NugetDiscovery) + let errors = extractErrors packageResolution if errors = "" then - File.WriteAllText(lockFile, format resolution) + File.WriteAllText(lockFile, format (packageResolution)) tracefn "Locked version resolutions written to %s" lockFile else failwith <| "Could not resolve dependencies." + Environment.NewLine + errors diff --git a/src/Paket/Paket.fsproj b/src/Paket/Paket.fsproj index 542ad50f4b..b8ece55221 100644 --- a/src/Paket/Paket.fsproj +++ b/src/Paket/Paket.fsproj @@ -1,4 +1,4 @@ - + @@ -25,10 +25,11 @@ DEBUG;TRACE 3 ..\..\bin\Paket.xml - update + update --dependencies-file "C:\Users\Isaac\Source\Repos\Paket\tests\ManualCSTest\paket.dependencies" Project paket.exe - D:\code\paket + + pdbonly @@ -71,6 +72,7 @@ + diff --git a/src/Paket/Process.fs b/src/Paket/Process.fs index 1e45dae69b..1bd023f504 100644 --- a/src/Paket/Process.fs +++ b/src/Paket/Process.fs @@ -2,6 +2,7 @@ module Paket.Process open System.IO +open System.Collections.Generic /// Downloads and extracts all package. let ExtractPackages(force, packages : Package seq) = @@ -60,22 +61,39 @@ let private findAllProjects(folder) = DirectoryInfo(folder).EnumerateFiles("*.*p /// Installs the given packageFile. let Install(regenerate, force, dependenciesFile) = let lockfile = findLockfile dependenciesFile - + + let cfg = DependenciesFile.ReadFromFile dependenciesFile if regenerate || (not lockfile.Exists) then - LockFile.Update(force, dependenciesFile, lockfile.FullName) + LockFile.Update(force, cfg, lockfile.FullName) - let extracted = + let extractedPackages = ExtractPackages(force, File.ReadAllLines lockfile.FullName |> LockFile.Parse) |> Async.Parallel + |> Async.RunSynchronously + + let extractedFiles = + let rootPath = dependenciesFile |> Path.GetDirectoryName + cfg.RemoteFiles + |> List.map( + function + | GitHub source -> + async { + let! file = GitHub.downloadFile source + let destination = Path.Combine(rootPath, "paket-files", source.Owner, source.Project, source.FilePath) + Directory.CreateDirectory(destination |> Path.GetDirectoryName) |> ignore + File.WriteAllText(destination, file) + return destination }) + |> Async.Parallel |> Async.RunSynchronously + for proj in findAllProjects(".") do let directPackages = extractReferencesFromListFile proj.FullName let project = ProjectFile.Load proj.FullName - let usedPackages = new System.Collections.Generic.HashSet<_>() + let usedPackages = new HashSet<_>() let allPackages = - extracted + extractedPackages |> Array.map (fun (p,_) -> p.Name,p) |> Map.ofArray @@ -90,14 +108,14 @@ let Install(regenerate, force, dependenciesFile) = directPackages |> Array.iter addPackage - project.UpdateReferences(extracted,usedPackages) + project.UpdateReferences(extractedPackages,usedPackages) /// Finds all outdated packages. -let FindOutdated(packageFile) = - let lockFile = findLockfile packageFile +let FindOutdated(dependenciesFile) = + let lockFile = findLockfile dependenciesFile - let newPackages = LockFile.Create(true,packageFile) + let newPackages = LockFile.Create(true, dependenciesFile) let installed = if lockFile.Exists then LockFile.Parse(File.ReadAllLines lockFile.FullName) else [] [for p in installed do diff --git a/src/Paket/Program.fs b/src/Paket/Program.fs index 86aace76f6..c1d26c5ea6 100644 --- a/src/Paket/Program.fs +++ b/src/Paket/Program.fs @@ -3,7 +3,6 @@ module Paket.Program open System open Nessos.UnionArgParser -open System.IO type Command = | Install diff --git a/src/Paket/ProjectFile.fs b/src/Paket/ProjectFile.fs index 677aad3623..b17567ee8b 100644 --- a/src/Paket/ProjectFile.fs +++ b/src/Paket/ProjectFile.fs @@ -5,7 +5,7 @@ open System.IO open System.Xml open System.Collections.Generic -/// Contains methods to read and manipulate project file ndoes. +/// Contains methods to read and manipulate project file nodes. type private InstallInfo = { DllName : string Path : string diff --git a/src/Paket/Resolver.fs b/src/Paket/Resolver.fs index 963a6e79fc..5332e3f88b 100644 --- a/src/Paket/Resolver.fs +++ b/src/Paket/Resolver.fs @@ -1,5 +1,5 @@ /// Contains logic which helps to resolve the dependency graph. -module Paket.Resolver +module Paket.PackageResolver open Paket open System diff --git a/tests/ManualCSTest/paket.dependencies b/tests/ManualCSTest/paket.dependencies index fbf69dff9d..e4574b05e0 100644 --- a/tests/ManualCSTest/paket.dependencies +++ b/tests/ManualCSTest/paket.dependencies @@ -1,3 +1,6 @@ source "http://nuget.org/api/v2" -nuget "Newtonsoft.Json" "~> 6.0" \ No newline at end of file +nuget "Newtonsoft.Json" "~> 6.0" +github "fsharp:FAKE" "src/app/FAKE/Cli.fs" +github "fsharp:FAKE:Globbing" "/src/app/Fake.Deploy.Lib/FakeDeployAgentHelper.fs" +github "fsharp:FAKE:b019e6db78b88386447a1efd1bd70826f5008344" "src/app/FAKE/CommandlineParams.fs" \ No newline at end of file From 82dc1a9b259eb7fa41ac34a38683ab7dea34dfd5 Mon Sep 17 00:00:00 2001 From: Isaac Abraham Date: Sat, 13 Sep 2014 19:21:07 +0100 Subject: [PATCH 2/2] LockFile integration. --- src/Paket/BasicTypes.fs | 13 ++-- src/Paket/DependenciesFile.fs | 25 +++---- src/Paket/GitHub.fs | 5 +- src/Paket/LockFile.fs | 121 +++++++++++++++++++++++----------- src/Paket/Paket.fsproj | 2 +- src/Paket/Process.fs | 50 +++++++------- src/Paket/Program.fs | 4 +- 7 files changed, 133 insertions(+), 87 deletions(-) diff --git a/src/Paket/BasicTypes.fs b/src/Paket/BasicTypes.fs index 1c4c36f174..7d4162ac5a 100644 --- a/src/Paket/BasicTypes.fs +++ b/src/Paket/BasicTypes.fs @@ -85,7 +85,8 @@ type PackageSource = | _ -> failwith "unable to parse package source: %s" source // Represents details on a dependent source file. -type SourceFileDetails = +//TODO: As new sources e.g. fssnip etc. are added, this should probably become a DU or perhaps have an enum marker. +type SourceFile = { Owner : string Project : string Path : string @@ -94,12 +95,10 @@ type SourceFileDetails = this.Path .TrimStart('/') .Replace("/", "\\") + member this.CommitWithDefault = defaultArg this.Commit "master" + override this.ToString() = sprintf "(%s:%s:%s) %s" this.Owner this.Project this.CommitWithDefault this.Path -// The different types of source files. -type SourceFile = | GitHub of File : SourceFileDetails - -// TODO: Perhaps Source File and Package should be merged into a DU? - +//TODO: Perhaps Source File and Package should be merged into a DU? /// Represents a package. type Package = { Name : string @@ -108,8 +107,6 @@ type Package = ResolverStrategy : ResolverStrategy Sources : PackageSource list } - - /// Represents a package dependency. type PackageDependency = { Defining : Package diff --git a/src/Paket/DependenciesFile.fs b/src/Paket/DependenciesFile.fs index 2921341015..97650ebed6 100644 --- a/src/Paket/DependenciesFile.fs +++ b/src/Paket/DependenciesFile.fs @@ -33,7 +33,7 @@ module DependenciesFileParser = with | _ -> failwithf "could not parse version range \"%s\"" text - let private (|Remote|Package|Blank|GitHubFile|) (line:string) = + let private (|Remote|Package|Blank|SourceFile|) (line:string) = match line.Trim() with | _ when String.IsNullOrWhiteSpace line -> Blank | trimmed when trimmed.StartsWith "source" -> @@ -49,18 +49,18 @@ module DependenciesFileParser = | [| owner; project; commit |] -> owner, project, Some commit | _ -> failwith "invalid github specification" match parts with - | [| _; projectSpec; fileSpec |] -> GitHubFile(getParts projectSpec, fileSpec) + | [| _; projectSpec; fileSpec |] -> SourceFile(getParts projectSpec, fileSpec) | _ -> failwith "invalid github specification" | _ -> Blank let parseDependenciesFile (lines:string seq) = ((0,[], [], []), lines) - ||> Seq.fold(fun (lineNo, sources: PackageSource list, packages, remoteFiles) line -> + ||> Seq.fold(fun (lineNo, sources: PackageSource list, packages, sourceFiles) line -> let lineNo = lineNo + 1 try match line with - | Remote newSource -> lineNo, (PackageSource.Parse(newSource.TrimEnd([|'/'|])) :: sources), packages, remoteFiles - | Blank -> lineNo, sources, packages, remoteFiles + | Remote newSource -> lineNo, (PackageSource.Parse(newSource.TrimEnd([|'/'|])) :: sources), packages, sourceFiles + | Blank -> lineNo, sources, packages, sourceFiles | Package details -> let parts = details.Split('"') if parts.Length < 4 || String.IsNullOrWhiteSpace parts.[1] || String.IsNullOrWhiteSpace parts.[3] then @@ -70,13 +70,14 @@ module DependenciesFileParser = Name = parts.[1] DirectDependencies = [] ResolverStrategy = if version.StartsWith "!" then ResolverStrategy.Min else ResolverStrategy.Max - VersionRange = parseVersionRange(version.Trim '!') } :: packages, remoteFiles - | GitHubFile((owner,project, commit), path) -> - lineNo, sources, packages, - GitHub { Owner = owner - Project = project - Commit = commit - Path = path } :: remoteFiles + VersionRange = parseVersionRange(version.Trim '!') } :: packages, sourceFiles + | SourceFile((owner,project, commit), path) -> + let newSourceFile = { Owner = owner + Project = project + Commit = commit + Path = path } + tracefn " %O" newSourceFile + lineNo, sources, packages, newSourceFile :: sourceFiles with | exn -> failwithf "Error in paket.dependencies line %d%s %s" lineNo Environment.NewLine exn.Message) diff --git a/src/Paket/GitHub.fs b/src/Paket/GitHub.fs index 8989fadeab..a2b31578d7 100644 --- a/src/Paket/GitHub.fs +++ b/src/Paket/GitHub.fs @@ -5,9 +5,8 @@ open System open Paket /// Gets a single file from github. -let downloadFile (remoteFile:SourceFileDetails) = - let commit = defaultArg remoteFile.Commit "master" - let url = sprintf "https://github.com/%s/%s/raw/%s/%s" remoteFile.Owner remoteFile.Project commit remoteFile.Path +let downloadFile remoteFile = + let url = sprintf "https://github.com/%s/%s/raw/%s/%s" remoteFile.Owner remoteFile.Project remoteFile.CommitWithDefault remoteFile.Path use wc = new WebClient() Uri url |> wc.AsyncDownloadString diff --git a/src/Paket/LockFile.fs b/src/Paket/LockFile.fs index 0fdd0f7c71..4c953db158 100644 --- a/src/Paket/LockFile.fs +++ b/src/Paket/LockFile.fs @@ -47,7 +47,7 @@ let extractErrors (resolved : PackageResolution) = /// [omit] -let format (resolved : PackageResolution) = +let serializePackages (resolved : PackageResolution) = let sources = resolved.ResolvedVersionMap |> Seq.map (fun x -> @@ -76,54 +76,97 @@ let format (resolved : PackageResolution) = String.Join(Environment.NewLine, all) -let private (|Remote|Package|Dependency|Spec|Header|Blank|) (line:string) = - match line.Trim() with - | "NUGET" -> Header - | _ when String.IsNullOrWhiteSpace line -> Blank - | trimmed when trimmed.StartsWith "remote:" -> Remote (trimmed.Substring(trimmed.IndexOf(": ") + 2)) - | trimmed when trimmed.StartsWith "specs:" -> Spec - | trimmed when line.StartsWith " " -> Dependency (trimmed.Split ' ' |> Seq.head) - | trimmed -> Package trimmed +let serializeSourceFiles (files:SourceFile list) = + seq { + yield "GITHUB" + for (owner,project), files in files |> Seq.groupBy(fun f -> f.Owner,f.Project) do + yield sprintf " remote: %s/%s" owner project + yield " specs:" + for file in files do + let path = file.Path.TrimStart '/' + match file.Commit with + | Some commit -> yield sprintf " %s (%s)" path commit + | None -> yield sprintf " %s" path + } + |> fun all -> String.Join(Environment.NewLine, all) + +type private ParseState = + { RepositoryType : string option + Remote : string option + Packages : Package list + SourceFiles : SourceFile list } + +let private (|Remote|NugetPackage|NugetDependency|SourceFile|Spec|RepositoryType|Blank|) (state, line:string) = + match (state.RepositoryType, line.Trim()) with + | _, "NUGET" -> RepositoryType "NUGET" + | _, "GITHUB" -> RepositoryType "GITHUB" + | _, _ when String.IsNullOrWhiteSpace line -> Blank + | _, trimmed when trimmed.StartsWith "remote:" -> Remote (trimmed.Substring(trimmed.IndexOf(": ") + 2)) + | _, trimmed when trimmed.StartsWith "specs:" -> Spec + | _, trimmed when line.StartsWith " " -> NugetDependency (trimmed.Split ' ' |> Seq.head) + | Some "NUGET", trimmed -> NugetPackage trimmed + | Some "GITHUB", trimmed -> SourceFile trimmed + | Some _, _ -> failwith "unknown Repository Type." + | _ -> failwith "unknown lock file format." /// Parses a Lock file from lines let Parse(lines : string seq) = - (("http://nuget.org/api/v2", []), lines) - ||> Seq.fold(fun (currentSource, packages) line -> - match line with - | Remote newSource -> newSource, packages - | Header | Spec | Blank -> (currentSource, packages) - | Package details -> - let parts = details.Split(' ') - let version = parts.[1].Replace("(", "").Replace(")", "") - currentSource, { Sources = [PackageSource.Parse currentSource] - Name = parts.[0] - DirectDependencies = [] - ResolverStrategy = Max - VersionRange = VersionRange.Exactly version } :: packages - | Dependency details -> - match packages with + let remove textToRemove (source:string) = source.Replace(textToRemove, "") + let removeBrackets = remove "(" >> remove ")" + ({ RepositoryType = None; Remote = None; Packages = []; SourceFiles = [] }, lines) + ||> Seq.fold(fun state line -> + match (state, line) with + | Remote remoteSource -> { state with Remote = Some remoteSource } + | Spec | Blank -> state + | RepositoryType repoType -> { state with RepositoryType = Some repoType } + | NugetPackage details -> + match state.Remote with + | Some remote -> + let parts = details.Split ' ' + let version = parts.[1] |> removeBrackets + { state with Packages = { Sources = [PackageSource.Parse remote] + Name = parts.[0] + DirectDependencies = [] + ResolverStrategy = Max + VersionRange = VersionRange.Exactly version } :: state.Packages } + | None -> failwith "no source has been specified." + | NugetDependency details -> + match state.Packages with | currentPackage :: otherPackages -> - currentSource, - { currentPackage with - DirectDependencies = [details] - |> List.append currentPackage.DirectDependencies } :: otherPackages - | _ -> failwith "cannot set a dependency - no package has been specified.") - |> snd - |> List.rev + { state with + Packages = { currentPackage with + DirectDependencies = [details] |> List.append currentPackage.DirectDependencies + } :: otherPackages } + | [] -> failwith "cannot set a dependency - no package has been specified." + | SourceFile details -> + match state.Remote |> Option.map(fun s -> s.Split '/') with + | Some [| owner; project |] -> + let path, commit = match details.Split ' ' with + | [| filePath; commit |] -> filePath, Some (commit |> removeBrackets) + | [| filePath |] -> filePath, None + | _ -> failwith "invalid file source details." + { state with + SourceFiles = { Commit = commit + Owner = owner + Project = project + Path = path } :: state.SourceFiles } + | _ -> failwith "invalid remote details." + ) + |> fun state -> List.rev state.Packages, List.rev state.SourceFiles /// Analyzes the dependencies from the Dependencies file. -let Create(force, dependenciesFile) = - let cfg = DependenciesFile.ReadFromFile dependenciesFile - tracefn "Analyzing %s" dependenciesFile - cfg.Resolve(force, Nuget.NugetDiscovery) +let Create(force, dependenciesFilename) = + tracefn "Parsing %s" dependenciesFilename + let dependenciesFile = DependenciesFile.ReadFromFile dependenciesFilename + dependenciesFile.Resolve(force, Nuget.NugetDiscovery), dependenciesFile.RemoteFiles /// Updates the Lock file with the analyzed dependencies from the Dependencies file. -let Update(force, dependenciesFile:DependenciesFile, lockFile) = - tracefn "Analyzing %s" dependenciesFile - let packageResolution = dependenciesFile.Resolve(force, Nuget.NugetDiscovery) +let Update(force, dependenciesFilename, lockFile) = + let packageResolution, remoteFiles = Create(force, dependenciesFilename) let errors = extractErrors packageResolution if errors = "" then - File.WriteAllText(lockFile, format (packageResolution)) + let output = String.Join(Environment.NewLine, serializePackages (packageResolution), serializeSourceFiles remoteFiles) + File.WriteAllText(lockFile, output) tracefn "Locked version resolutions written to %s" lockFile else failwith <| "Could not resolve dependencies." + Environment.NewLine + errors diff --git a/src/Paket/Paket.fsproj b/src/Paket/Paket.fsproj index b8ece55221..b408676561 100644 --- a/src/Paket/Paket.fsproj +++ b/src/Paket/Paket.fsproj @@ -25,7 +25,7 @@ DEBUG;TRACE 3 ..\..\bin\Paket.xml - update --dependencies-file "C:\Users\Isaac\Source\Repos\Paket\tests\ManualCSTest\paket.dependencies" + install --dependencies-file "C:\Users\Isaac\Source\Repos\Paket\tests\ManualCSTest\paket.dependencies" Project paket.exe diff --git a/src/Paket/Process.fs b/src/Paket/Process.fs index 1bd023f504..c7dc4ae868 100644 --- a/src/Paket/Process.fs +++ b/src/Paket/Process.fs @@ -59,29 +59,33 @@ let extractReferencesFromListFile projectFile = let private findAllProjects(folder) = DirectoryInfo(folder).EnumerateFiles("*.*proj", SearchOption.AllDirectories) /// Installs the given packageFile. -let Install(regenerate, force, dependenciesFile) = - let lockfile = findLockfile dependenciesFile - - let cfg = DependenciesFile.ReadFromFile dependenciesFile - if regenerate || (not lockfile.Exists) then - LockFile.Update(force, cfg, lockfile.FullName) +let Install(regenerate, force, dependenciesFilename) = + let packages, sourceFiles = + let lockfile = findLockfile dependenciesFilename + + if regenerate || (not lockfile.Exists) then + LockFile.Update(force, dependenciesFilename, lockfile.FullName) + + File.ReadAllLines lockfile.FullName |> LockFile.Parse let extractedPackages = - ExtractPackages(force, File.ReadAllLines lockfile.FullName |> LockFile.Parse) + ExtractPackages(force, packages) |> Async.Parallel |> Async.RunSynchronously - - let extractedFiles = - let rootPath = dependenciesFile |> Path.GetDirectoryName - cfg.RemoteFiles - |> List.map( - function - | GitHub source -> + + let extractedSourceFiles = + let rootPath = dependenciesFilename |> Path.GetDirectoryName + sourceFiles + |> List.map(fun source -> async { - let! file = GitHub.downloadFile source - let destination = Path.Combine(rootPath, "paket-files", source.Owner, source.Project, source.FilePath) - Directory.CreateDirectory(destination |> Path.GetDirectoryName) |> ignore - File.WriteAllText(destination, file) + let destination = Path.Combine(rootPath, "paket-files", source.Owner, source.Project, source.CommitWithDefault, source.FilePath) + + if File.Exists destination then tracefn "%s already exists locally" (source.ToString()) + else + tracefn "Downloading %s..." (source.ToString()) + let! file = GitHub.downloadFile source + Directory.CreateDirectory(destination |> Path.GetDirectoryName) |> ignore + File.WriteAllText(destination, file) return destination }) |> Async.Parallel |> Async.RunSynchronously @@ -114,11 +118,13 @@ let Install(regenerate, force, dependenciesFile) = /// Finds all outdated packages. let FindOutdated(dependenciesFile) = let lockFile = findLockfile dependenciesFile - - let newPackages = LockFile.Create(true, dependenciesFile) - let installed = if lockFile.Exists then LockFile.Parse(File.ReadAllLines lockFile.FullName) else [] - [for p in installed do + //TODO: Anything we need to do for source files here? + let newPackages, _ = LockFile.Create(true, dependenciesFile) + let installedPackages, _ = + if lockFile.Exists then LockFile.Parse(File.ReadAllLines lockFile.FullName) else [], [] + + [for p in installedPackages do match newPackages.ResolvedVersionMap.[p.Name] with | Resolved newVersion -> if p.VersionRange <> newVersion.Referenced.VersionRange then diff --git a/src/Paket/Program.fs b/src/Paket/Program.fs index c1d26c5ea6..0a1656abe1 100644 --- a/src/Paket/Program.fs +++ b/src/Paket/Program.fs @@ -8,7 +8,7 @@ type Command = | Install | Update | Outdated - | Unkown + | Unknown type CLIArguments = | [][][] Install @@ -38,7 +38,7 @@ let results,verbose = if results.Contains <@ CLIArguments.Install @> then Command.Install elif results.Contains <@ CLIArguments.Update @> then Command.Update elif results.Contains <@ CLIArguments.Outdated @> then Command.Outdated - else Command.Unkown + else Command.Unknown Some(command,results),results.Contains <@ CLIArguments.Verbose @> with | _ ->