VCS commit hash, branch or tag can now be specified when installing

packages.
This commit is contained in:
Dominik Picheta 2013-12-14 20:56:00 +00:00
commit b6bde8b0e7
4 changed files with 138 additions and 67 deletions

View file

@ -136,7 +136,6 @@ proc prompt(options: TOptions, question: string): bool =
let babelDir = getHomeDir() / ".babel"
let pkgsDir = babelDir / "pkgs"
let binDir = babelDir / "bin"
let nimVer = getNimrodVersion()
proc update(url: string = defaultPackageURL) =
## Downloads the package list from the specified URL.
@ -227,8 +226,8 @@ proc copyFilesRec(origDir, currentDir, dest: string, pkgInfo: TPackageInfo) =
copyFileD(pkgInfo.mypath,
changeRoot(pkgInfo.mypath.splitFile.dir, dest, pkgInfo.mypath))
proc install(packages: seq[String], verRange: PVersionRange, options: TOptions,
doPrompt = true): string {.discardable.}
proc install(packages: seq[tuple[name: string, verRange: PVersionRange]],
options: TOptions, doPrompt = true): string {.discardable.}
proc processDeps(pkginfo: TPackageInfo, options: TOptions): seq[string] =
## Verifies and installs dependencies.
##
@ -237,6 +236,7 @@ proc processDeps(pkginfo: TPackageInfo, options: TOptions): seq[string] =
let pkglist = getInstalledPkgs(pkgsDir)
for dep in pkginfo.requires:
if dep.name == "nimrod":
let nimVer = getNimrodVersion()
if not withinRange(nimVer, dep.ver):
quit("Unsatisfied dependency: " & dep.name & " (" & $dep.ver & ")")
else:
@ -244,7 +244,7 @@ proc processDeps(pkginfo: TPackageInfo, options: TOptions): seq[string] =
var pkg: TPackageInfo
if not findPkg(pkglist, dep, pkg):
echo("None found, installing...")
let dest = install(@[dep.name], dep.ver, options)
let dest = install(@[(dep.name, dep.ver)], options)
result.add(dest)
else:
echo("Dependency already satisfied.")
@ -328,8 +328,8 @@ proc downloadPkg(pkg: TPackage, verRange: PVersionRange): string =
doDownload(pkg, downloadDir, verRange)
result = downloadDir
proc install(packages: seq[String], verRange: PVersionRange, options: TOptions,
doPrompt = true): string =
proc install(packages: seq[tuple[name: string, verRange: PVersionRange]],
options: TOptions, doPrompt = true): string =
if packages == @[]:
result = installFromDir(getCurrentDir(), false, options)
else:
@ -337,19 +337,20 @@ proc install(packages: seq[String], verRange: PVersionRange, options: TOptions,
if doPrompt and
options.prompt("Local packages.json not found, download it from internet?"):
update()
install(packages, verRange, options, false)
install(packages, options, false)
else:
quit("Please run babel update.", QuitFailure)
for p in packages:
for pv in packages:
var pkg: TPackage
if getPackage(p, babelDir / "packages.json", pkg):
let downloadDir = downloadPkg(pkg, verRange)
if getPackage(pv.name, babelDir / "packages.json", pkg):
let downloadDir = downloadPkg(pkg, pv.verRange)
result = installFromDir(downloadDir, false, options)
else:
if doPrompt and
options.prompt(p & " not found in local packages.json, check internet for updated packages?"):
options.prompt(pv.name & " not found in local packages.json, check internet for updated packages?"):
update()
install(@[p], verRange, options, false)
install(@[pv], options, false)
else:
raise newException(EBabel, "Package not found.")
@ -437,8 +438,15 @@ proc doAction(options: TOptions) =
else:
update()
of ActionInstall:
# TODO: Allow user to specify version.
install(options.action.optionalName, PVersionRange(kind: verAny), options)
var installList: seq[tuple[name: string, verRange: PVersionRange]] = @[]
for name in options.action.optionalName:
if '#' in name:
let i = find(name, '#')
installList.add((name[0 .. i-1], name[i .. -1].parseVersionRange()))
else:
installList.add((name, PVersionRange(kind: verAny)))
install(installList, options)
of ActionSearch:
search(options)
of ActionList:

View file

@ -36,14 +36,16 @@ proc doPull(meth: TDownloadMethod, downloadDir: string) =
cd downloadDir:
doCmd("hg pull")
proc doClone(meth: TDownloadMethod, url, downloadDir: string, branch = "") =
proc doClone(meth: TDownloadMethod, url, downloadDir: string, branch = "", tip = true) =
let branchArg = if branch == "": "" else: "-b " & branch & " "
case meth
of TDownloadMethod.Git:
let depthArg = if tip: "--depth 1 " else: ""
# TODO: Get rid of the annoying 'detached HEAD' message somehow?
doCmd("git clone --depth 1 " & branchArg & url & " " & downloadDir)
doCmd("git clone " & depthArg & branchArg & url & " " & downloadDir)
of TDownloadMethod.Hg:
doCmd("hg clone -r tip " & branchArg & url & " " & downloadDir)
let tipArg = if tip: "-r tip " else: ""
doCmd("hg clone " & tipArg & branchArg & url & " " & downloadDir)
proc getTagsList(dir: string, meth: TDownloadMethod): seq[string] =
cd dir:
@ -100,57 +102,70 @@ proc getDownloadMethod*(meth: string): TDownloadMethod =
else:
raise newException(EBabel, "Invalid download method: " & meth)
proc getHeadName*(meth: TDownloadMethod): string =
## Returns the name of the download method specific head. i.e. for git
## it's ``head`` for hg it's ``tip``.
case meth
of TDownloadMethod.Git: "head"
of TDownloadMethod.Hg: "tip"
proc doDownload*(pkg: TPackage, downloadDir: string, verRange: PVersionRange) =
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 latest.tag != "":
meth
proc verifyHead() =
## Makes sure that HEAD satisfies the requested version range.
let pkginfo = getPkgInfo(downloadDir)
if pkginfo.version.newVersion notin verRange:
raise newException(EBabel,
"No versions of " & pkg.name &
" exist (this usually means that `git tag` returned nothing)." &
"Git HEAD also does not satisfy version range: " & $verRange)
let downMethod = pkg.downloadMethod.getDownloadMethod()
echo "Downloading ", pkg.name, " using ", downMethod, "..."
case downMethod
of TDownloadMethod.Git:
# For Git we have to query the repo remotely for its tags. This is
# necessary as cloning with a --depth of 1 removes all tag info.
let versions = getTagsListRemote(pkg.url, downMethod).getVersionList()
if versions.len > 0:
echo("Found tags...")
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 latest.tag != "":
echo("Cloning latest tagged version: ", latest.tag)
removeDir(downloadDir)
doClone(downMethod, pkg.url, downloadDir, latest.tag)
else:
# If no commits have been tagged on the repo we just clone HEAD.
removeDir(downloadDir)
removeDir(downloadDir)
if verRange.kind == verSpecial:
# We want a specific commit/branch/tag here.
if verRange.spe == newSpecial(getHeadName(downMethod)):
doClone(downMethod, pkg.url, downloadDir) # Grab HEAD.
if verRange.kind != verAny:
# Make sure that HEAD satisfies the requested version range.
let pkginfo = getPkgInfo(downloadDir)
if pkginfo.version.newVersion notin verRange:
raise newException(EBabel,
"No versions of " & pkg.name &
" exist (this usually means that `git tag` returned nothing)." &
"Git HEAD also does not satisfy version range: " & $verRange)
of TDownloadMethod.Hg:
removeDir(downloadDir)
doClone(downMethod, pkg.url, downloadDir)
let versions = getTagsList(downloadDir, downMethod).getVersionList()
if versions.len > 0:
echo("Found tags...")
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 latest.tag != "":
echo("Switching to latest tagged version: ", latest.tag)
doCheckout(downMethod, downloadDir, latest.tag)
elif verRange.kind != verAny:
let pkginfo = getPkgInfo(downloadDir)
if pkginfo.version.newVersion notin verRange:
raise newException(EBabel,
"No versions of " & pkg.name &
" exist (this usually means that `git tag` returned nothing)." &
"Git HEAD also does not satisfy version range: " & $verRange)
# We use GIT HEAD if it satisfies our ver range
else:
# We don't know if we got a commit hash or a branch here, and
# we can't clone a specific commit (with depth 1) according to:
# http://stackoverflow.com/a/7198956/492186
doClone(downMethod, pkg.url, downloadDir, tip = false)
doCheckout(downMethod, downloadDir, $verRange.spe)
else:
case downMethod
of TDownloadMethod.Git:
# For Git we have to query the repo remotely for its tags. This is
# necessary as cloning with a --depth of 1 removes all tag info.
let versions = getTagsListRemote(pkg.url, downMethod).getVersionList()
if versions.len > 0:
getLatestByTag:
echo("Cloning latest tagged version: ", latest.tag)
doClone(downMethod, pkg.url, downloadDir, latest.tag)
else:
# If no commits have been tagged on the repo we just clone HEAD.
doClone(downMethod, pkg.url, downloadDir) # Grab HEAD.
if verRange.kind != verAny:
verifyHead()
of TDownloadMethod.Hg:
doClone(downMethod, pkg.url, downloadDir)
let versions = getTagsList(downloadDir, downMethod).getVersionList()
if versions.len > 0:
getLatestByTag:
echo("Switching to latest tagged version: ", latest.tag)
doCheckout(downMethod, downloadDir, latest.tag)
elif verRange.kind != verAny:
verifyHead()
proc echoPackageVersions*(pkg: TPackage) =
let downMethod = pkg.downloadMethod.getDownloadMethod()

View file

@ -72,6 +72,10 @@ proc parseRequires(req: string): tuple[name: string, ver: PVersionRange] =
var i = skipUntil(req, whitespace)
result.name = req[0 .. i].strip
result.ver = parseVersionRange(req[i .. -1])
elif '#' in req:
var i = skipUntil(req, {'#'})
result.name = req[0 .. i-1]
result.ver = parseVersionRange(req[i .. -1])
else:
result.name = req.strip
result.ver = PVersionRange(kind: verAny)

View file

@ -5,6 +5,7 @@
import strutils, tables, hashes, parseutils
type
TVersion* = distinct string
TSpecial* = distinct string
TVersionRangeEnum* = enum
verLater, # > V
@ -13,13 +14,16 @@ type
verEqEarlier, # <= V -- Equal or earlier
verIntersect, # > V & < V
verEq, # V
verAny # *
verAny, # *
verSpecial # #head
PVersionRange* = ref TVersionRange
TVersionRange* = object
case kind*: TVersionRangeEnum
of verLater, verEarlier, verEqLater, verEqEarlier, verEq:
ver*: TVersion
of verSpecial:
spe*: TSpecial
of verIntersect:
verILeft, verIRight: PVersionRange
of verAny:
@ -28,11 +32,16 @@ type
EParseVersion* = object of EInvalidValue
proc newVersion*(ver: string): TVersion = return TVersion(ver)
proc newSpecial*(spe: string): TSpecial = return TSpecial(spe)
proc `$`*(ver: TVersion): String {.borrow.}
proc hash*(ver: TVersion): THash {.borrow.}
proc `$`*(ver: TSpecial): String {.borrow.}
proc hash*(ver: TSpecial): THash {.borrow.}
proc `<`*(ver: TVersion, ver2: TVersion): Bool =
var sVer = string(ver).split('.')
var sVer2 = string(ver2).split('.')
@ -65,6 +74,9 @@ proc `==`*(ver: TVersion, ver2: TVersion): Bool =
else:
return False
proc `==`*(spe: TSpecial, spe2: TSpecial): bool =
return ($spe).toLower() == ($spe2).toLower()
proc `<=`*(ver: TVersion, ver2: TVersion): Bool =
return (ver == ver2) or (ver < ver2)
@ -80,14 +92,28 @@ proc withinRange*(ver: TVersion, ran: PVersionRange): Bool =
return ver <= ran.ver
of verEq:
return ver == ran.ver
of verSpecial:
return False
of verIntersect:
return withinRange(ver, ran.verILeft) and withinRange(ver, ran.verIRight)
of verAny:
return True
proc withinRange*(spe: TSpecial, ran: PVersionRange): Bool =
case ran.kind
of verLater, verEarlier, verEqLater, verEqEarlier, verEq, verIntersect:
return False
of verSpecial:
return spe == ran.spe
of verAny:
return True
proc contains*(ran: PVersionRange, ver: TVersion): bool =
return withinRange(ver, ran)
proc contains*(ran: PVersionRange, spe: TSpecial): bool =
return withinRange(spe, ran)
proc makeRange*(version: string, op: string): PVersionRange =
new(result)
if version == "":
@ -110,6 +136,10 @@ proc makeRange*(version: string, op: string): PVersionRange =
proc parseVersionRange*(s: string): PVersionRange =
# >= 1.5 & <= 1.8
new(result)
if s[0] == '#':
result.kind = verSpecial
result.spe = s[1 .. -1].TSpecial
return
var i = 0
var op = ""
@ -163,6 +193,8 @@ proc `$`*(verRange: PVersionRange): String =
result = "<= "
of verEq:
result = ""
of verSpecial:
return "#" & $verRange.spe
of verIntersect:
return $verRange.verILeft & " & " & $verRange.verIRight
of verAny:
@ -212,6 +244,7 @@ when isMainModule:
doAssert(newVersion("1") == newVersion("1"))
doAssert(newVersion("1.0.2.4.6.1.2.123") == newVersion("1.0.2.4.6.1.2.123"))
doAssert(newVersion("1.0.2") != newVersion("1.0.2.4.6.1.2.123"))
doAssert(newVersion("1.0.3") != newVersion("1.0.2"))
doAssert(not (newVersion("") < newVersion("0.0.0")))
doAssert(newVersion("") < newVersion("1.0.0"))
@ -220,8 +253,19 @@ when isMainModule:
var versions = toTable[TVersion, string]({newVersion("0.1.1"): "v0.1.1", newVersion("0.2.3"): "v0.2.3", newVersion("0.5"): "v0.5"})
doAssert findLatest(parseVersionRange(">= 0.1 & <= 0.4"), versions) == (newVersion("0.2.3"), "v0.2.3")
# TODO: These fail.
#doAssert newVersion("0.1-rc1") < newVersion("0.2")
#doAssert newVersion("0.1-rc1") < newVersion("0.1")
# Special tests
doAssert newSpecial("ab26sgdt362") != newSpecial("ab26saggdt362")
doAssert newSpecial("ab26saggdt362") == newSpecial("ab26saggdt362")
doAssert newSpecial("head") == newSpecial("HEAD")
doAssert newSpecial("head") == newSpecial("head")
var sp = parseVersionRange("#ab26sgdt362")
doAssert newSpecial("ab26sgdt362") in sp
doAssert newSpecial("ab26saggdt362") notin sp
doAssert newVersion("0.1-rc1") < newVersion("0.2")
doAssert newVersion("0.1-rc1") < newVersion("0.1")
echo("Everything works!")