diff --git a/src/Paket.Core/FindReferences.fs b/src/Paket.Core/FindReferences.fs index febcc40353..c5463cf72c 100644 --- a/src/Paket.Core/FindReferences.fs +++ b/src/Paket.Core/FindReferences.fs @@ -6,25 +6,43 @@ open Logging open Paket.Domain open Paket.Rop -let FindReferencesForPackage (dependenciesFileName, package:PackageName) = - let root = Path.GetDirectoryName dependenciesFileName - let projectFiles = ProjectFile.FindAllProjects root - let lockFile = LockFile.LoadFrom((DependenciesFile.FindLockfile dependenciesFileName).FullName) - - [for project,referencesFile in InstallProcess.findAllReferencesFiles root |> returnOrFail do - let installedPackages = - referencesFile - |> lockFile.GetPackageHull - |> Seq.map NormalizedPackageName - |> Set.ofSeq - - if installedPackages.Contains(NormalizedPackageName package) then - yield project.FileName ] - -let ShowReferencesFor (dependenciesFileName, packages : PackageName list) = - packages - |> Seq.map (fun package -> package,FindReferencesForPackage(dependenciesFileName,package)) +let private findReferencesFor package (lockFile: LockFile) projects = rop { + let! referencedIn = + projects + |> Seq.map (fun (project, referencesFile) -> rop { + let! installedPackages = + referencesFile + |> lockFile.GetPackageHullSafe + + let referenced = + installedPackages + |> Set.map NormalizedPackageName + |> Set.contains (NormalizedPackageName package) + + return if referenced then Some project.FileName else None }) + |> Rop.collect + + return referencedIn |> List.choose id +} + +let FindReferencesForPackage package environment = rop { + let! lockFile = environment |> PaketEnv.ensureLockFileExists + + return! findReferencesFor package lockFile environment.Projects +} + +let ShowReferencesFor packages environment = rop { + let! lockFile = environment |> PaketEnv.ensureLockFileExists + let! projectsPerPackage = + packages + |> Seq.map (fun package -> rop { + let! projects = findReferencesFor package lockFile environment.Projects + return package, projects }) + |> Rop.collect + + projectsPerPackage |> Seq.iter (fun (PackageName k, vs) -> tracefn "%s" k - vs |> Seq.iter (tracefn "%s") - tracefn "") \ No newline at end of file + vs |> Seq.iter (tracefn "%s") + tracefn "") +} \ No newline at end of file diff --git a/src/Paket.Core/LockFile.fs b/src/Paket.Core/LockFile.fs index 85a1d08637..e966682bef 100644 --- a/src/Paket.Core/LockFile.fs +++ b/src/Paket.Core/LockFile.fs @@ -284,6 +284,27 @@ module LockFileParser = /// Allows to parse and analyze paket.lock files. type LockFile(fileName:string,options,resolution:PackageResolution,remoteFiles:ResolvedSourceFile list) = + let dependenciesByPackageLazy = lazy ( + let allDependenciesOf package = + let usedPackages = HashSet<_>() + + let rec addPackage packageName = + let identity = NormalizedPackageName packageName + match resolution.TryFind identity with + | Some package -> + if usedPackages.Add packageName then + if not options.Strict then + for d,_,_ in package.Dependencies do + addPackage d + | None -> () + + addPackage package + + usedPackages + + resolution + |> Map.map (fun _ package -> allDependenciesOf package.Name)) + member __.SourceFiles = remoteFiles member __.ResolvedPackages = resolution member __.FileName = fileName @@ -308,24 +329,17 @@ type LockFile(fileName:string,options,resolution:PackageResolution,remoteFiles:R usedPackages /// Gets all dependencies of the given package - member this.GetAllDependenciesOf(package) = - let usedPackages = HashSet<_>() - - let rec addPackage (packageName:PackageName) = - let identity = NormalizedPackageName packageName - match resolution.TryFind identity with - | Some package -> - if usedPackages.Add packageName then - if not this.Options.Strict then - for d,_,_ in package.Dependencies do - addPackage d - | None -> - let (PackageName name) = packageName - failwithf "Package %s was referenced, but it was not found in the paket.lock file." name - - addPackage package + member this.GetAllDependenciesOf(package) = + match this.GetAllDependenciesOfSafe package with + | Some packages -> packages + | None -> + let (PackageName name) = package + failwithf "Package %s was referenced, but it was not found in the paket.lock file." name - usedPackages + /// Gets all dependencies of the given package + member this.GetAllDependenciesOfSafe(package) = + dependenciesByPackageLazy.Value + |> Map.tryFind (NormalizedPackageName package) member this.GetAllNormalizedDependenciesOf(package:PackageName) = this.GetAllDependenciesOf(package) @@ -396,3 +410,11 @@ type LockFile(fileName:string,options,resolution:PackageResolution,remoteFiles:R with exn -> failwithf "%s - in %s" exn.Message referencesFile.FileName) usedPackages + + member this.GetPackageHullSafe referencesFile = + referencesFile.NugetPackages + |> Seq.map (fun package -> + this.GetAllDependenciesOfSafe(package) + |> Rop.failIfNone (ReferenceNotFoundInLockFile(referencesFile.FileName, package))) + |> Rop.collect + |> Rop.lift (Seq.concat >> Set.ofSeq) diff --git a/src/Paket.Core/PublicAPI.fs b/src/Paket.Core/PublicAPI.fs index ee7195936e..ed9aea8100 100644 --- a/src/Paket.Core/PublicAPI.fs +++ b/src/Paket.Core/PublicAPI.fs @@ -94,6 +94,16 @@ type Dependencies(dependenciesFileName: string) = /// Get the root path member this.RootPath with get() = Path.GetDirectoryName(dependenciesFileName) + /// Get the root directory + member private this.RootDirectory with get() = DirectoryInfo(this.RootPath) + + /// Binds the given processing ROP function to current environment and executes it. + /// Throws on failure. + member private this.Process f = + PaketEnv.fromRootDirectory(this.RootDirectory) + >>= f + |> returnOrFail + /// Adds the given package without version requirements to the dependencies file. member this.Add(package: string): unit = this.Add(package,"") @@ -199,8 +209,8 @@ type Dependencies(dependenciesFileName: string) = /// Shows all references for the given packages. member this.ShowReferencesFor(packages: string list): unit = - FindReferences.ShowReferencesFor(dependenciesFileName,packages |> List.map PackageName) + FindReferences.ShowReferencesFor (packages |> List.map PackageName) |> this.Process /// Finds all references for a given package. member this.FindReferencesFor(package: string): string list = - FindReferences.FindReferencesForPackage(dependenciesFileName, PackageName package) + FindReferences.FindReferencesForPackage (PackageName package) |> this.Process diff --git a/src/Paket.Core/Rop.fs b/src/Paket.Core/Rop.fs index aca19facdb..eec44e12f9 100644 --- a/src/Paket.Core/Rop.fs +++ b/src/Paket.Core/Rop.fs @@ -87,6 +87,7 @@ let () = lift let (<*>) = apply type RopBuilder() = + member __.Zero() = succeed () member __.Bind(m, f) = bind f m member __.Return(x) = succeed x member __.ReturnFrom(x) = x