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 httpclient, parseopt, os, strutils, osproc, pegs, tables, parseutils
|
||||||
|
|
||||||
import packageinfo, version, common, tools
|
import packageinfo, version, common, tools, download
|
||||||
|
|
||||||
type
|
type
|
||||||
TActionType = enum
|
TActionType = enum
|
||||||
|
|
@ -103,29 +103,6 @@ proc update(url: string = defaultPackageURL) =
|
||||||
downloadFile(url, babelDir / "packages.json")
|
downloadFile(url, babelDir / "packages.json")
|
||||||
echo("Done.")
|
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,
|
proc checkInstallFile(pkgInfo: TPackageInfo,
|
||||||
origDir, file: string): bool =
|
origDir, file: string): bool =
|
||||||
## Checks whether ``file`` should be installed.
|
## Checks whether ``file`` should be installed.
|
||||||
|
|
@ -292,61 +269,12 @@ proc installFromDir(dir: string, latest: bool): string =
|
||||||
|
|
||||||
echo(pkgInfo.name & " installed successfully.")
|
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 =
|
proc downloadPkg(pkg: TPackage, verRange: PVersionRange): string =
|
||||||
let downloadDir = (getTempDir() / "babel" / pkg.name)
|
let downloadDir = (getTempDir() / "babel" / pkg.name)
|
||||||
if not existsDir(getTempDir() / "babel"): createDir(getTempDir() / "babel")
|
if not existsDir(getTempDir() / "babel"): createDir(getTempDir() / "babel")
|
||||||
echo("Downloading ", pkg.name, " into ", downloadDir, "...")
|
echo("Downloading ", pkg.name, " into ", downloadDir, "...")
|
||||||
case pkg.downloadMethod
|
doDownload(pkg, downloadDir, verRange)
|
||||||
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)
|
|
||||||
|
|
||||||
# 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
|
result = downloadDir
|
||||||
|
|
||||||
proc install(packages: seq[String], verRange: PVersionRange): string =
|
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.
|
# Copyright (C) Dominik Picheta. All rights reserved.
|
||||||
# BSD License. Look at license.txt for more info.
|
# BSD License. Look at license.txt for more info.
|
||||||
|
|
||||||
|
import os, osproc
|
||||||
|
|
||||||
type
|
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
|
``> 0.2 & < 1.0`` which will install a package with the version greater than 0.2
|
||||||
and less than 1.0.
|
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
|
## .babel reference
|
||||||
|
|
||||||
### [Package]
|
### [Package]
|
||||||
|
|
@ -126,7 +139,7 @@ and less than 1.0.
|
||||||
|
|
||||||
* ``name`` - The name of the package.
|
* ``name`` - The name of the package.
|
||||||
* ``version`` - The *current* version of this package. This should be incremented
|
* ``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.
|
* ``author`` - The name of the author of this package.
|
||||||
* ``description`` - A string describing the package.
|
* ``description`` - A string describing the package.
|
||||||
* ``license`` - The name of the license in which this package is licensed under.
|
* ``license`` - The name of the license in which this package is licensed under.
|
||||||
|
|
|
||||||
|
|
@ -9,4 +9,5 @@
|
||||||
* more package download methods
|
* more package download methods
|
||||||
* Allow for proper versions of packages to download. Reuse 'version' field
|
* Allow for proper versions of packages to download. Reuse 'version' field
|
||||||
in packages.json.
|
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 osproc, pegs, strutils, os
|
||||||
import version
|
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 =
|
proc getNimrodVersion*: TVersion =
|
||||||
let vOutput = execProcess("nimrod -v")
|
let vOutput = execProcess("nimrod -v")
|
||||||
var matches: array[0..MaxSubpatterns, string]
|
var matches: array[0..MaxSubpatterns, string]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue