diff --git a/src/nimble.nim b/src/nimble.nim index 407b207..edb3b3d 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -434,13 +434,16 @@ proc installFromDir(dir: string, requestedVer: VersionRange, options: Options, Success, HighPriority) proc getDownloadInfo*(pv: PkgTuple, options: Options, - doPrompt: bool): (DownloadMethod, string) = + doPrompt: bool): (DownloadMethod, string, + Table[string, string]) = if pv.name.isURL: - return (checkUrlType(pv.name), pv.name) + let (url, metadata) = getUrlData(pv.name) + return (checkUrlType(url), url, metadata) else: var pkg: Package if getPackage(pv.name, options, pkg): - return (pkg.downloadMethod.getDownloadMethod(), pkg.url) + let (url, metadata) = getUrlData(pkg.url) + return (pkg.downloadMethod.getDownloadMethod(), url, metadata) else: # If package is not found give the user a chance to refresh # package.json @@ -464,9 +467,10 @@ proc install(packages: seq[PkgTuple], else: # Install each package. for pv in packages: - let (meth, url) = getDownloadInfo(pv, options, doPrompt) + let (meth, url, metadata) = getDownloadInfo(pv, options, doPrompt) + let subdir = metadata.getOrDefault("subdir") let (downloadDir, downloadVersion) = - downloadPkg(url, pv.ver, meth, options) + downloadPkg(url, pv.ver, meth, subdir, options) try: # Run pre-install hook in download directory now that package is downloaded cd downloadDir: @@ -1005,8 +1009,9 @@ proc develop(options: Options) = let hint = "Remove the directory, or run this command somewhere else." raiseNimbleError(msg, hint) - let (meth, url) = getDownloadInfo(pv, options, true) - discard downloadPkg(url, pv.ver, meth, options, downloadDir) + let (meth, url, metadata) = getDownloadInfo(pv, options, true) + let subdir = metadata.getOrDefault("subdir") + discard downloadPkg(url, pv.ver, meth, subdir, options, downloadDir) developFromDir(downloadDir, options) proc test(options: Options) = diff --git a/src/nimblepkg/download.nim b/src/nimblepkg/download.nim index 216c36e..cad8d3d 100644 --- a/src/nimblepkg/download.nim +++ b/src/nimblepkg/download.nim @@ -1,7 +1,7 @@ # Copyright (C) Dominik Picheta. All rights reserved. # BSD License. Look at license.txt for more info. -import parseutils, os, osproc, strutils, tables, pegs +import parseutils, os, osproc, strutils, tables, pegs, uri import packageinfo, packageparser, version, tools, common, options, cli @@ -132,13 +132,24 @@ proc checkUrlType*(url: string): DownloadMethod = elif doCmdEx("hg identify " & url).exitCode == QuitSuccess: return DownloadMethod.hg else: - raise newException(NimbleError, "Unable to identify url.") + raise newException(NimbleError, "Unable to identify url: " & url) + +proc getUrlData*(url: string): (string, Table[string, string]) = + var uri = parseUri(url) + # TODO: use uri.parseQuery once it lands... this code is quick and dirty. + var subdir = "" + if uri.query.startsWith("subdir="): + subdir = uri.query[7 .. ^1] + + uri.query = "" + return ($uri, {"subdir": subdir}.toTable()) proc isURL*(name: string): bool = name.startsWith(peg" @'://' ") -proc doDownload*(url: string, downloadDir: string, verRange: VersionRange, - downMethod: DownloadMethod, options: Options): Version = +proc doDownload(url: string, downloadDir: string, verRange: VersionRange, + downMethod: DownloadMethod, + options: Options): Version = ## Downloads the repository specified by ``url`` using the specified download ## method. ## @@ -159,16 +170,6 @@ proc doDownload*(url: string, downloadDir: string, verRange: VersionRange, # Result should already be set to #head here. assert(not result.isNil) - proc verifyClone() = - ## Makes sure that the downloaded package's version satisfies the requested - ## version range. - let pkginfo = getPkgInfo(downloadDir, options) - if pkginfo.version.newVersion notin verRange: - raise newException(NimbleError, - "Downloaded package's version does not satisfy requested version " & - "range: wanted $1 got $2." % - [$verRange, $pkginfo.version]) - removeDir(downloadDir) if verRange.kind == verSpecial: # We want a specific commit/branch/tag here. @@ -197,8 +198,6 @@ proc doDownload*(url: string, downloadDir: string, verRange: VersionRange, else: # If no commits have been tagged on the repo we just clone HEAD. doClone(downMethod, url, downloadDir) # Grab HEAD. - - verifyClone() of DownloadMethod.hg: doClone(downMethod, url, downloadDir) result = getHeadName(downMethod) @@ -210,10 +209,9 @@ proc doDownload*(url: string, downloadDir: string, verRange: VersionRange, priority = MediumPriority) doCheckout(downMethod, downloadDir, latest.tag) - verifyClone() - proc downloadPkg*(url: string, verRange: VersionRange, downMethod: DownloadMethod, + subdir: string, options: Options, downloadPath = ""): (string, Version) = ## Downloads the repository as specified by ``url`` and ``verRange`` using @@ -221,8 +219,8 @@ proc downloadPkg*(url: string, verRange: VersionRange, ## ## If `downloadPath` isn't specified a location in /tmp/ will be used. ## - ## Returns the directory where it was downloaded and the concrete version - ## which was downloaded. + ## Returns the directory where it was downloaded (subdir is appended) and + ## the concrete version which was downloaded. let downloadDir = if downloadPath == "": (getNimbleTempDir() / getDownloadDirName(url, verRange)) @@ -241,13 +239,28 @@ proc downloadPkg*(url: string, verRange: VersionRange, if modUrl.contains("github.com") and modUrl.endswith("/"): modUrl = modUrl[0 .. ^2] - display("Downloading", "$1 using $2" % [modUrl, $downMethod], - priority = HighPriority) + if subdir.len > 0: + display("Downloading", "$1 using $2 (subdir is '$3')" % + [modUrl, $downMethod, subdir], + priority = HighPriority) + else: + display("Downloading", "$1 using $2" % [modUrl, $downMethod], + priority = HighPriority) result = ( - downloadDir, + downloadDir / subdir, doDownload(modUrl, downloadDir, verRange, downMethod, options) ) + if verRange.kind != verSpecial: + ## Makes sure that the downloaded package's version satisfies the requested + ## version range. + let pkginfo = getPkgInfo(result[0], options) + if pkginfo.version.newVersion notin verRange: + raise newException(NimbleError, + "Downloaded package's version does not satisfy requested version " & + "range: wanted $1 got $2." % + [$verRange, $pkginfo.version]) + proc echoPackageVersions*(pkg: Package) = let downMethod = pkg.downloadMethod.getDownloadMethod() case downMethod diff --git a/src/nimblepkg/packageinfo.nim b/src/nimblepkg/packageinfo.nim index 9c384ff..10e8bfa 100644 --- a/src/nimblepkg/packageinfo.nim +++ b/src/nimblepkg/packageinfo.nim @@ -304,7 +304,7 @@ proc findNimbleFile*(dir: string; error: bool): string = elif hits == 0: if error: raise newException(NimbleError, - "Specified directory does not contain a .nimble file.") + "Specified directory ($1) does not contain a .nimble file." % dir) else: display("Warning:", "No .nimble or .nimble-link file found for " & dir, Warning, HighPriority) diff --git a/tests/tester.nim b/tests/tester.nim index 68f2e08..c907348 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -675,3 +675,8 @@ suite "check command": check outp.processOutput.inLines("failure") check outp.processOutput.inLines("validation failed") check outp.processOutput.inLines("package 'x' has an incorrect structure") + +suite "multi": + test "can install package from git subdir": + let args = ["install", "-y", "https://github.com/nimble-test/multi?subdir=alpha"] + check execNimble(args).exitCode == QuitSuccess \ No newline at end of file