Implemented download of packages residing in mercurial repos.
* Moved download handling code into a download module. * Documented how versioning works for repos (via tags). * More info during install about what tag is picked. * Refactored download code to be more generic.
This commit is contained in:
parent
d826584f21
commit
07b7f46fd6
6 changed files with 162 additions and 77 deletions
76
babel.nim
76
babel.nim
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
import httpclient, parseopt, os, strutils, osproc, pegs, tables, parseutils
|
||||
|
||||
import packageinfo, version, common, tools
|
||||
import packageinfo, version, common, tools, download
|
||||
|
||||
type
|
||||
TActionType = enum
|
||||
|
|
@ -103,29 +103,6 @@ proc update(url: string = defaultPackageURL) =
|
|||
downloadFile(url, babelDir / "packages.json")
|
||||
echo("Done.")
|
||||
|
||||
proc copyFileD(fro, to: string) =
|
||||
echo(fro, " -> ", to)
|
||||
copyFile(fro, to)
|
||||
|
||||
proc copyDirD(fro, to: string) =
|
||||
echo(fro, " -> ", to)
|
||||
copyDir(fro, to)
|
||||
|
||||
proc doCmd(cmd: string) =
|
||||
let exitCode = execCmd(cmd)
|
||||
if exitCode != QuitSuccess:
|
||||
quit("Execution failed with exit code " & $exitCode, QuitFailure)
|
||||
|
||||
template cd(dir: string, body: stmt) =
|
||||
## Sets the current dir to ``dir``, executes ``body`` and restores the
|
||||
## previous working dir.
|
||||
let lastDir = getCurrentDir()
|
||||
echo("cd ", dir)
|
||||
setCurrentDir(dir)
|
||||
echo(getCurrentDir())
|
||||
body
|
||||
setCurrentDir(lastDir)
|
||||
|
||||
proc checkInstallFile(pkgInfo: TPackageInfo,
|
||||
origDir, file: string): bool =
|
||||
## Checks whether ``file`` should be installed.
|
||||
|
|
@ -292,61 +269,12 @@ proc installFromDir(dir: string, latest: bool): string =
|
|||
|
||||
echo(pkgInfo.name & " installed successfully.")
|
||||
|
||||
proc getTagsList(dir: string): seq[string] =
|
||||
cd dir:
|
||||
let output = execProcess("git tag")
|
||||
if output.len > 0:
|
||||
result = output.splitLines()
|
||||
else:
|
||||
result = @[]
|
||||
|
||||
proc getVersionList(dir: string): TTable[TVersion, string] =
|
||||
# Returns: TTable of version -> git tag name
|
||||
result = initTable[TVersion, string]()
|
||||
let tags = getTagsList(dir)
|
||||
for tag in tags:
|
||||
let i = skipUntil(tag, digits) # skip any chars before the version
|
||||
# TODO: Better checking, tags can have any names. Add warnings and such.
|
||||
result[newVersion(tag[i .. -1])] = tag
|
||||
|
||||
proc downloadPkg(pkg: TPackage, verRange: PVersionRange): string =
|
||||
let downloadDir = (getTempDir() / "babel" / pkg.name)
|
||||
if not existsDir(getTempDir() / "babel"): createDir(getTempDir() / "babel")
|
||||
echo("Downloading ", pkg.name, " into ", downloadDir, "...")
|
||||
case pkg.downloadMethod
|
||||
of "git":
|
||||
echo("Executing git...")
|
||||
if existsDir(downloadDir / ".git"):
|
||||
cd downloadDir:
|
||||
doCmd("git checkout master")
|
||||
doCmd("git pull")
|
||||
else:
|
||||
removeDir(downloadDir)
|
||||
doCmd("git clone --depth 1 " & pkg.url & " " & downloadDir)
|
||||
doDownload(pkg, downloadDir, verRange)
|
||||
|
||||
# TODO: Determine if version is a commit hash, if it is. Move the
|
||||
# git repo to ``babelDir/pkgs``, then babel can simply checkout
|
||||
# the correct hash instead of constantly cloning and copying.
|
||||
# N.B. This may still partly be requires, as one lib may require hash A
|
||||
# whereas another lib requires hash B and they are both required by the
|
||||
# project you want to build.
|
||||
let versions = getVersionList(downloadDir)
|
||||
if versions.len > 0:
|
||||
let latest = findLatest(verRange, versions)
|
||||
|
||||
if latest.tag != "":
|
||||
cd downloadDir:
|
||||
doCmd("git checkout " & 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: raise newException(EBabel, "Unknown download method: " & pkg.downloadMethod)
|
||||
result = downloadDir
|
||||
|
||||
proc install(packages: seq[String], verRange: PVersionRange): string =
|
||||
|
|
|
|||
13
common.nim
13
common.nim
|
|
@ -1,4 +1,15 @@
|
|||
# Copyright (C) Dominik Picheta. All rights reserved.
|
||||
# BSD License. Look at license.txt for more info.
|
||||
|
||||
import os, osproc
|
||||
|
||||
type
|
||||
EBabel* = object of EBase
|
||||
EBabel* = object of EBase
|
||||
|
||||
proc copyFileD*(fro, to: string) =
|
||||
echo(fro, " -> ", to)
|
||||
copyFile(fro, to)
|
||||
|
||||
proc copyDirD*(fro, to: string) =
|
||||
echo(fro, " -> ", to)
|
||||
copyDir(fro, to)
|
||||
117
download.nim
Normal file
117
download.nim
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
# Copyright (C) Dominik Picheta. All rights reserved.
|
||||
# BSD License. Look at license.txt for more info.
|
||||
|
||||
import parseutils, os, osproc, strutils, tables
|
||||
|
||||
import packageinfo, common, version, tools
|
||||
|
||||
type
|
||||
TDownloadMethod {.pure.} = enum
|
||||
Git = "git", Hg = "hg"
|
||||
|
||||
proc getSpecificDir(meth: TDownloadMethod): string =
|
||||
case meth
|
||||
of TDownloadMethod.Git:
|
||||
".git"
|
||||
of TDownloadMethod.Hg:
|
||||
".hg"
|
||||
|
||||
proc doCheckout(meth: TDownloadMethod, downloadDir, branch: string) =
|
||||
case meth
|
||||
of TDownloadMethod.Git:
|
||||
cd downloadDir:
|
||||
doCmd("git checkout " & branch)
|
||||
of TDownloadMethod.Hg:
|
||||
cd downloadDir:
|
||||
doCmd("hg checkout " & branch)
|
||||
|
||||
proc doPull(meth: TDownloadMethod, downloadDir: string) =
|
||||
case meth
|
||||
of TDownloadMethod.Git:
|
||||
doCheckout(meth, downloadDir, "master")
|
||||
cd downloadDir:
|
||||
doCmd("git pull")
|
||||
of TDownloadMethod.Hg:
|
||||
doCheckout(meth, downloadDir, "default")
|
||||
cd downloadDir:
|
||||
doCmd("hg pull")
|
||||
|
||||
proc doClone(meth: TDownloadMethod, url, downloadDir: string) =
|
||||
case meth
|
||||
of TDownloadMethod.Git:
|
||||
doCmd("git clone --depth 1 " & url & " " & downloadDir)
|
||||
of TDownloadMethod.Hg:
|
||||
doCmd("hg clone " & url & " " & downloadDir)
|
||||
|
||||
proc getTagsList(dir: string, meth: TDownloadMethod): seq[string] =
|
||||
cd dir:
|
||||
var output = execProcess("git tag")
|
||||
case meth
|
||||
of TDownloadMethod.Git:
|
||||
output = execProcess("git tag")
|
||||
of TDownloadMethod.Hg:
|
||||
output = execProcess("hg tags")
|
||||
if output.len > 0:
|
||||
case meth
|
||||
of TDownloadMethod.Git:
|
||||
result = output.splitLines()
|
||||
of TDownloadMethod.Hg:
|
||||
result = @[]
|
||||
for i in output.splitLines():
|
||||
var tag = ""
|
||||
discard parseUntil(i, tag, ' ')
|
||||
if tag != "tip":
|
||||
result.add(tag)
|
||||
else:
|
||||
result = @[]
|
||||
|
||||
proc getVersionList(dir: string,
|
||||
meth: TDownloadMethod): TTable[TVersion, string] =
|
||||
# Returns: TTable of version -> git tag name
|
||||
result = initTable[TVersion, string]()
|
||||
let tags = getTagsList(dir, meth)
|
||||
for tag in tags:
|
||||
let i = skipUntil(tag, digits) # skip any chars before the version
|
||||
# TODO: Better checking, tags can have any names. Add warnings and such.
|
||||
result[newVersion(tag[i .. -1])] = tag
|
||||
|
||||
proc getDownloadMethod(meth: string): TDownloadMethod =
|
||||
case meth
|
||||
of "git": return TDownloadMethod.Git
|
||||
of "hg", "mercurial": return TDownloadMethod.Hg
|
||||
else:
|
||||
raise newException(EBabel, "Invalid download method: " & meth)
|
||||
|
||||
proc doDownload*(pkg: TPackage, downloadDir: string, verRange: PVersionRange) =
|
||||
let downMethod = pkg.downloadMethod.getDownloadMethod()
|
||||
echo "Executing ", downMethod, "..."
|
||||
|
||||
if existsDir(downloadDir / getSpecificDir(downMethod)):
|
||||
doPull(downMethod, downloadDir)
|
||||
else:
|
||||
removeDir(downloadDir)
|
||||
doClone(downMethod, pkg.url, downloadDir)
|
||||
|
||||
# TODO: Determine if version is a commit hash, if it is. Move the
|
||||
# git repo to ``babelDir/pkgs``, then babel can simply checkout
|
||||
# the correct hash instead of constantly cloning and copying.
|
||||
# N.B. This may still partly be required, as one lib may require hash A
|
||||
# whereas another lib requires hash B and they are both required by the
|
||||
# project you want to build.
|
||||
let versions = getVersionList(downloadDir, downMethod)
|
||||
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
|
||||
|
|
@ -118,6 +118,19 @@ greater-than (``>``), less-than-or-equal-to (``<=``) and greater-than-or-equal-t
|
|||
``> 0.2 & < 1.0`` which will install a package with the version greater than 0.2
|
||||
and less than 1.0.
|
||||
|
||||
## Versions
|
||||
|
||||
Versions of cloned packages via git or mercurial are determined through
|
||||
the repo's *tags*.
|
||||
|
||||
When installing a package which needs to be downloaded, after the
|
||||
download is complete and if the package is distributed through a VCS, babel
|
||||
will check the cloned repo's tags list. If no tags exist, babel will simply
|
||||
install the HEAD (or tip in mercurial) of the repo. If tags exist, babel will
|
||||
attempt to look for tags which resemble versions (e.g. v0.1) and will then
|
||||
find the latest version out of the available tags, once it does so it will install
|
||||
the package after checking out the latest version.
|
||||
|
||||
## .babel reference
|
||||
|
||||
### [Package]
|
||||
|
|
@ -126,7 +139,7 @@ and less than 1.0.
|
|||
|
||||
* ``name`` - The name of the package.
|
||||
* ``version`` - The *current* version of this package. This should be incremented
|
||||
after tagging the current version using ``git tag``.
|
||||
**after** tagging the current version using ``git tag`` or ``hg tag``.
|
||||
* ``author`` - The name of the author of this package.
|
||||
* ``description`` - A string describing the package.
|
||||
* ``license`` - The name of the license in which this package is licensed under.
|
||||
|
|
|
|||
|
|
@ -9,4 +9,5 @@
|
|||
* more package download methods
|
||||
* Allow for proper versions of packages to download. Reuse 'version' field
|
||||
in packages.json.
|
||||
* Install only .nim files when installing library packages?
|
||||
* Install only .nim files when installing library packages?
|
||||
* Force disable --babelPath when building binary packages?
|
||||
15
tools.nim
15
tools.nim
|
|
@ -5,6 +5,21 @@
|
|||
import osproc, pegs, strutils, os
|
||||
import version
|
||||
|
||||
# TODO: Merge with common.nim?
|
||||
|
||||
proc doCmd*(cmd: string) =
|
||||
let exitCode = execCmd(cmd)
|
||||
if exitCode != QuitSuccess:
|
||||
quit("Execution failed with exit code " & $exitCode, QuitFailure)
|
||||
|
||||
template cd*(dir: string, body: stmt) =
|
||||
## Sets the current dir to ``dir``, executes ``body`` and restores the
|
||||
## previous working dir.
|
||||
let lastDir = getCurrentDir()
|
||||
setCurrentDir(dir)
|
||||
body
|
||||
setCurrentDir(lastDir)
|
||||
|
||||
proc getNimrodVersion*: TVersion =
|
||||
let vOutput = execProcess("nimrod -v")
|
||||
var matches: array[0..MaxSubpatterns, string]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue