diff --git a/docs/content/nuget-dependencies.md b/docs/content/nuget-dependencies.md index d8efec2447..4a9a743fa2 100644 --- a/docs/content/nuget-dependencies.md +++ b/docs/content/nuget-dependencies.md @@ -38,6 +38,10 @@ Paket also supports file paths such as local directories or references to UNC sh source C:\Nugets source ~/project/nugets + +As well Paket supports the source directory to be specified relative to the `paket.dependencies` file: + + source ext/nugets ## Dependencies diff --git a/src/Paket.Core/DependenciesFile.fs b/src/Paket.Core/DependenciesFile.fs index 0e46590ae2..e454493832 100644 --- a/src/Paket.Core/DependenciesFile.fs +++ b/src/Paket.Core/DependenciesFile.fs @@ -271,7 +271,8 @@ type DependenciesFile(fileName,options,sources,packages : PackageRequirement lis member __.Sources = sources member this.Resolve(force) = let getSha1 origin owner repo branch = RemoteDownload.getSHA1OfBranch origin owner repo branch |> Async.RunSynchronously - this.Resolve(getSha1,NuGetV2.GetVersions,NuGetV2.GetPackageDetails force) + let root = Path.GetDirectoryName this.FileName + this.Resolve(getSha1,NuGetV2.GetVersions root,NuGetV2.GetPackageDetails root force) member __.Resolve(getSha1,getVersionF, getPackageDetailsF) = let resolveSourceFile(file:ResolvedSourceFile) : PackageRequirement list = diff --git a/src/Paket.Core/NuGetV2.fs b/src/Paket.Core/NuGetV2.fs index f4dd8c9ad4..726fa906c5 100644 --- a/src/Paket.Core/NuGetV2.fs +++ b/src/Paket.Core/NuGetV2.fs @@ -130,12 +130,12 @@ let getAllVersions(auth, nugetURL, package) = async { // } /// Gets versions of the given package from local Nuget feed. -let getAllVersionsFromLocalPath (localNugetPath, package) = +let getAllVersionsFromLocalPath (localNugetPath, package, root) = async { let localNugetPath = Utils.normalizeLocalPath localNugetPath - let di = DirectoryInfo(localNugetPath) + let di = getDirectoryInfo localNugetPath root if not di.Exists then - failwithf "The directory %s doesn't exist.%sPlease check the NuGet source feed definition in your paket.dependencies file." localNugetPath Environment.NewLine + failwithf "The directory %s doesn't exist.%sPlease check the NuGet source feed definition in your paket.dependencies file." di.FullName Environment.NewLine let versions= Directory.EnumerateFiles(di.FullName,"*.nupkg",SearchOption.AllDirectories) @@ -293,17 +293,18 @@ let getDetailsFromNuget force auth nugetURL package (version:SemVerInfo) = } /// Reads direct dependencies from a nupkg file -let getDetailsFromLocalFile localNugetPath package (version:SemVerInfo) = +let getDetailsFromLocalFile root localNugetPath package (version:SemVerInfo) = async { let localNugetPath = Utils.normalizeLocalPath localNugetPath + let di = getDirectoryInfo localNugetPath root let nupkg = - let v1 = FileInfo(Path.Combine(localNugetPath, sprintf "%s.%s.nupkg" package (version.ToString()))) + let v1 = FileInfo(Path.Combine(di.FullName, sprintf "%s.%s.nupkg" package (version.ToString()))) if v1.Exists then v1 else let version = version.Normalize() - FileInfo(Path.Combine(localNugetPath, sprintf "%s.%s.nupkg" package version)) + FileInfo(Path.Combine(di.FullName, sprintf "%s.%s.nupkg" package version)) if not nupkg.Exists then - failwithf "The package %s %s can't be found in %s.%sPlease check the feed definition in your paket.dependencies file." package (version.ToString()) localNugetPath Environment.NewLine + failwithf "The package %s %s can't be found in %s.%sPlease check the feed definition in your paket.dependencies file." package (version.ToString()) di.FullName Environment.NewLine let zip = ZipFile.OpenRead(nupkg.FullName) let zippedNuspec = zip.Entries |> Seq.find (fun f -> f.FullName.EndsWith ".nuspec") let fileName = FileInfo(Path.Combine(Path.GetTempPath(), zippedNuspec.Name)).FullName @@ -318,7 +319,7 @@ let getDetailsFromLocalFile localNugetPath package (version:SemVerInfo) = { PackageName = nuspec.OfficialName DownloadUrl = package Dependencies = Requirements.optimizeRestrictions nuspec.Dependencies - SourceUrl = localNugetPath + SourceUrl = di.FullName CacheVersion = NugetPackageCache.CurrentCacheVersion LicenseUrl = nuspec.LicenseUrl Unlisted = false } @@ -548,7 +549,7 @@ let GetTargetsFiles(targetFolder) = targetsFiles -let GetPackageDetails force sources (PackageName package) (version:SemVerInfo) : PackageResolver.PackageDetails = +let GetPackageDetails root force sources (PackageName package) (version:SemVerInfo) : PackageResolver.PackageDetails = let rec tryNext xs = match xs with | source :: rest -> @@ -564,7 +565,7 @@ let GetPackageDetails force sources (PackageName package) (version:SemVerInfo) : version |> Async.RunSynchronously | LocalNuget path -> - getDetailsFromLocalFile path package version + getDetailsFromLocalFile root path package version |> Async.RunSynchronously |> fun x -> source,x with e -> @@ -584,7 +585,7 @@ let GetPackageDetails force sources (PackageName package) (version:SemVerInfo) : |> Set.ofList } /// Allows to retrieve all version no. for a package from the given sources. -let GetVersions(sources, PackageName packageName) = +let GetVersions root (sources, PackageName packageName) = let versions = sources |> Seq.map (fun source -> @@ -593,7 +594,7 @@ let GetVersions(sources, PackageName packageName) = source.Authentication |> Option.map toBasicAuth, source.Url, packageName) - | LocalNuget path -> getAllVersionsFromLocalPath (path, packageName)) + | LocalNuget path -> getAllVersionsFromLocalPath (path, packageName, root)) |> Async.Parallel |> Async.RunSynchronously |> Seq.choose id diff --git a/src/Paket.Core/RestoreProcess.fs b/src/Paket.Core/RestoreProcess.fs index 9702c282bf..9b43b593c2 100644 --- a/src/Paket.Core/RestoreProcess.fs +++ b/src/Paket.Core/RestoreProcess.fs @@ -30,7 +30,8 @@ let ExtractPackage(root, sources, force, package : ResolvedPackage) = return package, NuGetV2.GetLibFiles folder, NuGetV2.GetTargetsFiles folder | LocalNuget path -> let path = Utils.normalizeLocalPath path - let packageFile = Path.Combine(root, path, sprintf "%s.%A.nupkg" name v) + let di = Utils.getDirectoryInfo path root + let packageFile = Path.Combine(di.FullName, sprintf "%s.%A.nupkg" name v) let! folder = NuGetV2.CopyFromCache(root, packageFile, "", name, v, force) // TODO: Restore license return package, NuGetV2.GetLibFiles folder, NuGetV2.GetTargetsFiles folder } diff --git a/src/Paket.Core/Utils.fs b/src/Paket.Core/Utils.fs index 9acf7645f8..16a6e4194d 100644 --- a/src/Paket.Core/Utils.fs +++ b/src/Paket.Core/Utils.fs @@ -36,11 +36,22 @@ let GetHomeDirectory() = else Environment.ExpandEnvironmentVariables("%HOMEDRIVE%%HOMEPATH%") -let normalizeLocalPath(path:string)= +type PathReference = + | AbsolutePath of string + | RelativePath of string + +let normalizeLocalPath(path:string) = if path.StartsWith("~/") then - Path.Combine(GetHomeDirectory(), path.Substring(2)) - else - path + AbsolutePath (Path.Combine(GetHomeDirectory(), path.Substring(2))) + else if Path.IsPathRooted(path) then + AbsolutePath path + else + RelativePath path + +let getDirectoryInfo pathInfo root = + match pathInfo with + | AbsolutePath s -> DirectoryInfo(s) + | RelativePath s -> DirectoryInfo(Path.Combine(root, s)) /// Creates a directory if it does not exist. let createDir path = @@ -373,4 +384,4 @@ module ObservableExtensions = { new IDisposable with member this.Dispose() = cts.Cancel() } - } + } \ No newline at end of file diff --git a/tests/Paket.Tests/UtilsSpecs.fs b/tests/Paket.Tests/UtilsSpecs.fs index 7eb5399fa6..e1dbf17489 100644 --- a/tests/Paket.Tests/UtilsSpecs.fs +++ b/tests/Paket.Tests/UtilsSpecs.fs @@ -10,10 +10,56 @@ let ``createRelativePath should handle spaces``() = "C:/some file" |> createRelativePath "C:/a/b" |> shouldEqual "..\\some file" - - + [] let ``normalize path with home directory``() = "~/data" |> Utils.normalizeLocalPath - |> shouldEqual (GetHomeDirectory() + Path.DirectorySeparatorChar.ToString() + "data") + |> shouldEqual (AbsolutePath (GetHomeDirectory() + Path.DirectorySeparatorChar.ToString() + "data")) + +[] +let ``relative local path is returned as is``() = + "Externals/NugetStore" + |> normalizeLocalPath + |> shouldEqual (RelativePath "Externals/NugetStore") + +[] +let ``absolute path with drive letter``() = + "c:\\Store" + |> normalizeLocalPath + |> match System.Environment.OSVersion.Platform with + | System.PlatformID.Win32NT -> shouldEqual (AbsolutePath "c:\\Store") + | _ -> shouldEqual (RelativePath "c:\\Store") + +[] +let ``relative path with drive letter``() = + "..\\Store" + |> normalizeLocalPath + |> shouldEqual (RelativePath "..\\Store") + +[] +let ``relative path with local identifier``() = + ".\\Store" + |> normalizeLocalPath + |> shouldEqual (RelativePath ".\\Store") + +[] +let ``SMB path is returned as absolute path``() = + "\\\\server\\Store" + |> normalizeLocalPath + |> match System.Environment.OSVersion.Platform with + | System.PlatformID.Win32NT | System.PlatformID.Win32S -> shouldEqual (AbsolutePath "\\\\server\\Store") + | _ -> shouldEqual (RelativePath "\\\\server\\Store") + +[] +let ``absolute path on unixoid systems``() = + "/server/Store" + |> normalizeLocalPath + |> shouldEqual (AbsolutePath "/server/Store") + +[] +let ``relative path with local identifier on unxoid systems``() = + "./Store" + |> normalizeLocalPath + |> shouldEqual (RelativePath "./Store") + \ No newline at end of file