Versioning support, changes to directory structure.

This commit is contained in:
Dominik Picheta 2012-12-07 21:05:30 +00:00
commit 423e2d3490
3 changed files with 76 additions and 54 deletions

View file

@ -97,10 +97,11 @@ proc update(url: string = defaultPackageURL) =
echo("Done.") echo("Done.")
proc findBabelFile(dir: string): string = proc findBabelFile(dir: string): string =
result = ""
for kind, path in walkDir(dir): for kind, path in walkDir(dir):
if kind == pcFile and path.splitFile.ext == ".babel": if kind == pcFile and path.splitFile.ext == ".babel":
return path if result != "": quit("Only one .babel file should be present in " & dir)
return "" result = path
proc copyFileD(fro, to: string) = proc copyFileD(fro, to: string) =
echo(fro, " -> ", to) echo(fro, " -> ", to)
@ -127,7 +128,7 @@ proc changeRoot(origRoot, newRoot, path: string): string =
raise newException(EInvalidValue, raise newException(EInvalidValue,
"Cannot change root of path: Path does not begin with original root.") "Cannot change root of path: Path does not begin with original root.")
proc copyFilesRec(origDir, currentDir: string, pkgInfo: TPackageInfo) = proc copyFilesRec(origDir, currentDir, dest: string, pkgInfo: TPackageInfo) =
for kind, file in walkDir(currentDir): for kind, file in walkDir(currentDir):
if kind == pcDir: if kind == pcDir:
var skip = false var skip = false
@ -142,9 +143,9 @@ proc copyFilesRec(origDir, currentDir: string, pkgInfo: TPackageInfo) =
if skip: continue if skip: continue
# Create the dir. # Create the dir.
createDir(changeRoot(origDir, getLibsDir() / pkgInfo.name, file)) createDir(changeRoot(origDir, dest, file))
copyFilesRec(origDir, file, pkgInfo) copyFilesRec(origDir, file, dest, pkgInfo)
else: else:
var skip = false var skip = false
if file.splitFile().name[0] == '.': skip = true if file.splitFile().name[0] == '.': skip = true
@ -155,46 +156,40 @@ proc copyFilesRec(origDir, currentDir: string, pkgInfo: TPackageInfo) =
break break
if not skip: if not skip:
copyFileD(file, changeRoot(origDir, getLibsDir() / pkgInfo.name, file)) copyFileD(file, changeRoot(origDir, dest, file))
proc installFromDir(dir: string) = proc installFromDir(dir: string, latest: bool) =
let babelFile = findBabelFile(dir) let babelFile = findBabelFile(dir)
if babelFile == "": if babelFile == "":
quit("Specified directory does not contain a .babel file.", QuitFailure) quit("Specified directory does not contain a .babel file.", QuitFailure)
var pkgInfo = readPackageInfo(babelFile) var pkgInfo = readPackageInfo(babelFile)
if not existsDir(dir / pkgInfo.name): let pkgDestDir = getLibsDir() / (pkgInfo.name &
quit("Package modules should be placed in a " & pkgInfo.name & dirSep & (if latest: "" else: '-' & pkgInfo.version))
" directory.", QuitFailure) if not existsDir(pkgDestDir):
createDir(pkgDestDir)
if not existsDir(getLibsDir() / pkgInfo.name):
createDir(getLibsDir() / pkgInfo.name)
else: else:
if not prompt("Package already exists. Overwrite?"): if not prompt("Package already exists. Overwrite?"):
quit(QuitSuccess) quit(QuitSuccess)
removeDir(getLibsDir() / pkgInfo.name) removeDir(pkgDestDir)
createDir(getLibsDir() / pkgInfo.name) createDir(pkgDestDir)
# Find main project file. copyFilesRec(dir, dir, pkgDestDir, pkgInfo)
let nimFile = dir / pkgInfo.name.addFileExt("nim")
let nimrodFile = dir / pkgInfo.name.addFileExt("nimrod")
if existsFile(nimFile) or existsFile(nimrodFile):
if existsFile(nimFile):
copyFileD(nimFile, changeRoot(dir, getLibsDir(), nimFile))
pkgInfo.skipFiles.add(changeRoot(dir, "", nimFile))
elif existsFile(nimrodFile):
copyFileD(nimrodFile, changeRoot(dir, getLibsDir(), nimrodFile))
pkgInfo.skipFiles.add(changeRoot(dir, "", nimrodFile))
else:
# TODO: Make this an error? Which can be overriden in .babel file?
echo("Warning: Could not find main package file.")
copyFilesRec(dir / pkgInfo.name, dir / pkgInfo.name, pkgInfo)
echo(pkgInfo.name & " installed successfully.") echo(pkgInfo.name & " installed successfully.")
proc doCmd(cmd: string) =
let exitCode = execCmd(cmd)
if exitCode != QuitSuccess:
quit("Execution failed with exit code " & $exitCode, QuitFailure)
proc getDVCSTag(pkg: TPackage): string =
result = pkg.dvcsTag
if result == "":
result = pkg.version
proc install(packages: seq[String]) = proc install(packages: seq[String]) =
if packages == @[]: if packages == @[]:
installFromDir(getCurrentDir()) installFromDir(getCurrentDir(), false)
else: else:
if not existsFile(getBabelDir() / "packages.json"): if not existsFile(getBabelDir() / "packages.json"):
quit("Please run babel update.", QuitFailure) quit("Please run babel update.", QuitFailure)
@ -202,15 +197,17 @@ proc install(packages: seq[String]) =
var pkg: TPackage var pkg: TPackage
if getPackage(p, getBabelDir() / "packages.json", pkg): if getPackage(p, getBabelDir() / "packages.json", pkg):
let downloadDir = (getTempDir() / "babel" / pkg.name) let downloadDir = (getTempDir() / "babel" / pkg.name)
let dvcsTag = getDVCSTag(pkg)
case pkg.downloadMethod case pkg.downloadMethod
of "git": of "git":
echo("Executing git...") echo("Executing git...")
removeDir(downloadDir) removeDir(downloadDir)
let exitCode = execCmd("git clone " & pkg.url & " " & downloadDir) doCmd("git clone " & pkg.url & " " & downloadDir)
if exitCode != QuitSuccess: if dvcsTag != "":
quit("Execution of git failed.", QuitFailure) doCmd("cd \"" & downloadDir & "\" && git checkout " & dvcsTag)
else: quit("Unknown download method: " & pkg.downloadMethod, QuitFailure) else: quit("Unknown download method: " & pkg.downloadMethod, QuitFailure)
installFromDir(downloadDir)
installFromDir(downloadDir, dvcsTag == "")
else: else:
quit("Package not found.", QuitFailure) quit("Package not found.", QuitFailure)

View file

@ -11,7 +11,9 @@ type
TPackage* = object TPackage* = object
name*: string name*: string
version*: string
url*: string url*: string
dvcsTag*: string
downloadMethod*: string downloadMethod*: string
tags*: seq[string] tags*: seq[string]
description*: string description*: string
@ -53,17 +55,36 @@ proc readPackageInfo*(path: string): TPackageInfo =
else: else:
quit("Cannot open package info: " & path, QuitFailure) quit("Cannot open package info: " & path, QuitFailure)
proc optionalField(obj: PJsonNode, name: string): string =
if existsKey(obj, name):
if obj[name].kind == JString:
return obj[name].str
else:
quit("Corrupted packages.json file. " & name & " field is of unexpected type.")
else: return ""
proc requiredField(obj: PJsonNode, name: string): string =
if existsKey(obj, name):
if obj[name].kind == JString:
return obj[name].str
else:
quit("Corrupted packages.json file. " & name & " field is of unexpected type.")
else:
quit("Package in packages.json file does not contain a " & name & " field.")
proc getPackage*(pkg: string, packagesPath: string, resPkg: var TPackage): bool = proc getPackage*(pkg: string, packagesPath: string, resPkg: var TPackage): bool =
let packages = parseFile(packagesPath) let packages = parseFile(packagesPath)
for p in packages: for p in packages:
if p["name"].str != pkg: continue if p["name"].str != pkg: continue
resPkg.name = pkg resPkg.name = pkg
resPkg.url = p["url"].str resPkg.url = p.requiredField("url")
resPkg.downloadMethod = p["method"].str resPkg.version = p.optionalField("version")
resPkg.downloadMethod = p.requiredField("method")
resPkg.dvcsTag = p.optionalField("dvcs-tag")
resPkg.tags = @[] resPkg.tags = @[]
for t in p["tags"]: for t in p["tags"]:
resPkg.tags.add(t.str) resPkg.tags.add(t.str)
resPkg.description = p["description"].str resPkg.description = p.requiredField("description")
return true return true
return false return false
@ -72,13 +93,15 @@ proc getPackageList*(packagesPath: string): seq[TPackage] =
let packages = parseFile(packagesPath) let packages = parseFile(packagesPath)
for p in packages: for p in packages:
var pkg: TPackage var pkg: TPackage
pkg.name = p["name"].str pkg.name = p.requiredField("name")
pkg.url = p["url"].str pkg.version = p.optionalField("version")
pkg.downloadMethod = p["method"].str pkg.url = p.requiredField("url")
pkg.downloadMethod = p.requiredField("method")
pkg.dvcsTag = p.optionalField("dvcs-tag")
pkg.tags = @[] pkg.tags = @[]
for t in p["tags"]: for t in p["tags"]:
pkg.tags.add(t.str) pkg.tags.add(t.str)
pkg.description = p["description"].str pkg.description = p.requiredField("description")
result.add(pkg) result.add(pkg)
proc echoPackage*(pkg: TPackage) = proc echoPackage*(pkg: TPackage) =

View file

@ -11,21 +11,23 @@ Babel stores everything that has been installed in ~/.babel on Unix systems and
in your $home/.babel on Windows. Libraries are stored in $babelDir/libs. in your $home/.babel on Windows. Libraries are stored in $babelDir/libs.
## Libraries ## Libraries
Libraries may contain a ``ProjectName.nim`` file, this file will be copied
to ~/.babel/libs/ProjectName.nim allowing anyone to import it with
``import ProjectName``, it is recommended to include such a file, however
it's not a requirement.
All modules should be placed in a ``ProjectName/`` folder. The reason for By convention, if you have a single file with the same filename as your package
this is that the main project file can then import the modules that it needs name, then you can include it in the same directory as the .babel file.
with confidence that the filename of those modules will not change after However, if you have other public modules whose names are quite common,
installation. they should be included in a separate directory by the name of "PackageName", so
as to not pollute the namespace. This will mean that your main file can be
imported by simply writing ``import PackageName`` and all other public modules
can be imported by writing ``import PackageName/module``. This structure can be
seen being used by (jester)[https://github.com/dom96/jester].
All private modules should be placed, by convention, in All private modules should be placed, by convention, in
a ``private`` folder inside the ``ProjectName/`` folder, these are modules which a ``private`` folder, these are modules which
the user of your library should not be importing. All files and folders in the user of your library should not be importing.
``ProjectName/`` will be copied as-is, you can however specify to skip some
directories or files in your .babel file. All files and folders in the directory of where the .babel file resides will be
copied as-is, you can however skip some directories or files in your by setting
the 'SkipDirs' or 'SkipFiles' options in your .babel file.
## Example .babel file ## Example .babel file