diff --git a/babel.nim b/babel.nim index 0b8fda3..213c717 100644 --- a/babel.nim +++ b/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 = diff --git a/common.nim b/common.nim index 15e2a02..e7d8d9a 100644 --- a/common.nim +++ b/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 \ No newline at end of file + 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) \ No newline at end of file diff --git a/download.nim b/download.nim new file mode 100644 index 0000000..18ed3ba --- /dev/null +++ b/download.nim @@ -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 diff --git a/readme.markdown b/readme.markdown index 0cd604d..da3dc62 100644 --- a/readme.markdown +++ b/readme.markdown @@ -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. diff --git a/todo.markdown b/todo.markdown index 98c97ae..e3a850f 100644 --- a/todo.markdown +++ b/todo.markdown @@ -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? \ No newline at end of file +* Install only .nim files when installing library packages? +* Force disable --babelPath when building binary packages? \ No newline at end of file diff --git a/tools.nim b/tools.nim index 13eb1e3..e82d98c 100644 --- a/tools.nim +++ b/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]