diff --git a/src/nimble.nim b/src/nimble.nim index 4e7cb1c..130f31b 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -467,8 +467,13 @@ proc buildFromDir(pkgInfo: PackageInfo, paths: seq[string], forRelease: bool) = let outputOpt = "-o:\"" & pkgInfo.getOutputDir(bin) & "\"" echo("Building ", pkginfo.name, "/", bin, " using ", pkgInfo.backend, " backend...") - doCmd(getNimBin() & " $# $# --noBabelPath $# $# \"$#\"" % - [pkgInfo.backend, releaseOpt, args, outputOpt, realDir / bin.changeFileExt("nim")]) + try: + doCmd(getNimBin() & " $# $# --noBabelPath $# $# \"$#\"" % + [pkgInfo.backend, releaseOpt, args, outputOpt, + realDir / bin.changeFileExt("nim")]) + except NimbleError: + raise newException(BuildFailed, "Build failed for package: " & + pkgInfo.name) proc saveNimbleMeta(pkgDestDir, url: string, filesInstalled: HashSet[string]) = var nimblemeta = %{"url": %url} @@ -608,28 +613,42 @@ proc getNimbleTempDir(): string = result.add($getpid()) proc downloadPkg(url: string, verRange: VersionRange, - downMethod: DownloadMethod): string = + downMethod: DownloadMethod): (string, VersionRange) = + ## Downloads the repository as specified by ``url`` and ``verRange`` using + ## the download method specified. + ## + ## Returns the directory where it was downloaded and the concrete version + ## which was downloaded. let downloadDir = (getNimbleTempDir() / getDownloadDirName(url, verRange)) createDir(downloadDir) echo("Downloading ", url, " into ", downloadDir, " using ", downMethod, "...") - doDownload(url, downloadDir, verRange, downMethod) - result = downloadDir + result = (downloadDir, doDownload(url, downloadDir, verRange, downMethod)) -proc downloadPkg(pkg: Package, verRange: VersionRange): string = - let downloadDir = (getNimbleTempDir() / getDownloadDirName(pkg, verRange)) - let downMethod = pkg.downloadMethod.getDownloadMethod() - createDir(downloadDir) - echo("Downloading ", pkg.name, " into ", downloadDir, " using ", downMethod, - "...") - doDownload(pkg.url, downloadDir, verRange, downMethod) - result = downloadDir +proc getDownloadInfo*(pv: PkgTuple, options: Options, + doPrompt: bool): (DownloadMethod, string) = + if pv.name.isURL: + return (checkUrlType(pv.name), pv.name) + else: + var pkg: Package + if getPackage(pv.name, options.getNimbleDir() / "packages.json", pkg): + return (pkg.downloadMethod.getDownloadMethod(), pkg.url) + else: + # If package is not found give the user a chance to update + # package.json + if doPrompt and + options.prompt(pv.name & " not found in local packages.json, " & + "check internet for updated packages?"): + update(options) + return getDownloadInfo(pv, options, doPrompt) + else: + raise newException(NimbleError, "Package not found.") proc install(packages: seq[PkgTuple], options: Options, doPrompt = true): tuple[paths: seq[string], pkg: PackageInfo] = - if packages == @[]: + if packages == @[]: result = installFromDir(getCurrentDir(), false, options, "") - else: + else: # If packages.json is not present ask the user if they want to download it. if not existsFile(options.getNimbleDir / "packages.json"): if doPrompt and @@ -641,25 +660,28 @@ proc install(packages: seq[PkgTuple], # Install each package. for pv in packages: - if pv.name.isURL: - let meth = checkUrlType(pv.name) - let downloadDir = downloadPkg(pv.name, pv.ver, meth) - result = installFromDir(downloadDir, false, options, pv.name) - else: - var pkg: Package - if getPackage(pv.name, options.getNimbleDir() / "packages.json", pkg): - let downloadDir = downloadPkg(pkg, pv.ver) - result = installFromDir(downloadDir, false, options, pkg.url) - else: - # If package is not found give the user a chance to update - # package.json - if doPrompt and - options.prompt(pv.name & " not found in local packages.json, " & - "check internet for updated packages?"): - update(options) - result = install(@[pv], options, false) + let (meth, url) = getDownloadInfo(pv, options, doPrompt) + let (downloadDir, downloadVersion) = downloadPkg(url, pv.ver, meth) + try: + result = installFromDir(downloadDir, false, options, url) + except BuildFailed: + # The package failed to build. + # Check if we tried building a tagged version of the package. + if pv.ver.kind != verSpecial: + # If we tried building a tagged version of the package then + # ask the user whether they want to try building #head. + let promptResult = doPrompt and + options.prompt(("Build failed for '$1@$2', would you" & + " like to try installing '$1@#head' (latest unstable)?") % + [pv.name, $downloadVersion]) + if promptResult: + let verRange = parseVersionRange("#" & getHeadName(meth)) + result = install(@[(pv.name, verRange)], options, doPrompt) else: - raise newException(NimbleError, "Package not found.") + raise newException(BuildFailed, + "Aborting installation due to build failure") + else: + raise proc build(options: Options) = var pkgInfo = getPkgInfo(getCurrentDir()) diff --git a/src/nimblepkg/download.nim b/src/nimblepkg/download.nim index 75bba52..9f3f27e 100644 --- a/src/nimblepkg/download.nim +++ b/src/nimblepkg/download.nim @@ -5,7 +5,7 @@ import parseutils, os, osproc, strutils, tables, pegs import packageinfo, version, tools, nimbletypes -type +type DownloadMethod* {.pure.} = enum git = "git", hg = "hg" @@ -106,11 +106,11 @@ proc getTagsListRemote*(url: string, meth: DownloadMethod): seq[string] = let start = i.find("refs/tags/")+"refs/tags/".len let tag = i[start .. i.len-1] if not tag.endswith("^{}"): result.add(tag) - + of DownloadMethod.hg: # http://stackoverflow.com/questions/2039150/show-tags-for-remote-hg-repository raise newException(ValueError, "Hg doesn't support remote tag querying.") - + proc getVersionList*(tags: seq[string]): Table[Version, string] = # Returns: TTable of version -> git tag name result = initTable[Version, string]() @@ -147,18 +147,23 @@ proc isURL*(name: string): bool = name.startsWith(peg" @'://' ") proc doDownload*(url: string, downloadDir: string, verRange: VersionRange, - downMethod: DownloadMethod) = + downMethod: DownloadMethod): VersionRange = + ## Downloads the repository specified by ``url`` using the specified download + ## method. + ## + ## Returns the version of the repository which has been downloaded. template getLatestByTag(meth: stmt): stmt {.dirty, immediate.} = echo("Found tags...") # Find latest version that fits our ``verRange``. var latest = findLatest(verRange, versions) ## Note: HEAD is not used when verRange.kind is verAny. This is ## intended behaviour, the latest tagged version will be used in this case. - + # If no tagged versions satisfy our range latest.tag will be "". # We still clone in that scenario because we want to try HEAD in that case. # https://github.com/nimrod-code/nimble/issues/22 meth + result = parseVersionRange($latest.ver) proc verifyClone() = ## Makes sure that the downloaded package's version satisfies the requested @@ -169,7 +174,7 @@ proc doDownload*(url: string, downloadDir: string, verRange: VersionRange, "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. @@ -183,6 +188,7 @@ proc doDownload*(url: string, downloadDir: string, verRange: VersionRange, else: doClone(downMethod, url, downloadDir, tip = false) doCheckout(downMethod, downloadDir, $verRange.spe) + result = verRange else: case downMethod of DownloadMethod.git: @@ -196,17 +202,19 @@ 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. - + result = parseVersionRange("#head") + verifyClone() of DownloadMethod.hg: doClone(downMethod, url, downloadDir) + result = parseVersionRange("#tip") let versions = getTagsList(downloadDir, downMethod).getVersionList() - + if versions.len > 0: getLatestByTag: echo("Switching to latest tagged version: ", latest.tag) doCheckout(downMethod, downloadDir, latest.tag) - + verifyClone() proc echoPackageVersions*(pkg: Package) = diff --git a/src/nimblepkg/nimbletypes.nim b/src/nimblepkg/nimbletypes.nim index cdfc646..3ee3fc8 100644 --- a/src/nimblepkg/nimbletypes.nim +++ b/src/nimblepkg/nimbletypes.nim @@ -5,3 +5,4 @@ type NimbleError* = object of Exception + BuildFailed* = object of NimbleError