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.")
proc findBabelFile(dir: string): string =
result = ""
for kind, path in walkDir(dir):
if kind == pcFile and path.splitFile.ext == ".babel":
return path
return ""
if result != "": quit("Only one .babel file should be present in " & dir)
result = path
proc copyFileD(fro, to: string) =
echo(fro, " -> ", to)
@ -127,7 +128,7 @@ proc changeRoot(origRoot, newRoot, path: string): string =
raise newException(EInvalidValue,
"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):
if kind == pcDir:
var skip = false
@ -142,9 +143,9 @@ proc copyFilesRec(origDir, currentDir: string, pkgInfo: TPackageInfo) =
if skip: continue
# 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:
var skip = false
if file.splitFile().name[0] == '.': skip = true
@ -155,46 +156,40 @@ proc copyFilesRec(origDir, currentDir: string, pkgInfo: TPackageInfo) =
break
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)
if babelFile == "":
quit("Specified directory does not contain a .babel file.", QuitFailure)
var pkgInfo = readPackageInfo(babelFile)
if not existsDir(dir / pkgInfo.name):
quit("Package modules should be placed in a " & pkgInfo.name & dirSep &
" directory.", QuitFailure)
if not existsDir(getLibsDir() / pkgInfo.name):
createDir(getLibsDir() / pkgInfo.name)
let pkgDestDir = getLibsDir() / (pkgInfo.name &
(if latest: "" else: '-' & pkgInfo.version))
if not existsDir(pkgDestDir):
createDir(pkgDestDir)
else:
if not prompt("Package already exists. Overwrite?"):
quit(QuitSuccess)
removeDir(getLibsDir() / pkgInfo.name)
createDir(getLibsDir() / pkgInfo.name)
removeDir(pkgDestDir)
createDir(pkgDestDir)
# Find main project file.
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)
copyFilesRec(dir, dir, pkgDestDir, pkgInfo)
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]) =
if packages == @[]:
installFromDir(getCurrentDir())
installFromDir(getCurrentDir(), false)
else:
if not existsFile(getBabelDir() / "packages.json"):
quit("Please run babel update.", QuitFailure)
@ -202,15 +197,17 @@ proc install(packages: seq[String]) =
var pkg: TPackage
if getPackage(p, getBabelDir() / "packages.json", pkg):
let downloadDir = (getTempDir() / "babel" / pkg.name)
let dvcsTag = getDVCSTag(pkg)
case pkg.downloadMethod
of "git":
echo("Executing git...")
removeDir(downloadDir)
let exitCode = execCmd("git clone " & pkg.url & " " & downloadDir)
if exitCode != QuitSuccess:
quit("Execution of git failed.", QuitFailure)
doCmd("git clone " & pkg.url & " " & downloadDir)
if dvcsTag != "":
doCmd("cd \"" & downloadDir & "\" && git checkout " & dvcsTag)
else: quit("Unknown download method: " & pkg.downloadMethod, QuitFailure)
installFromDir(downloadDir)
installFromDir(downloadDir, dvcsTag == "")
else:
quit("Package not found.", QuitFailure)

View file

@ -11,7 +11,9 @@ type
TPackage* = object
name*: string
version*: string
url*: string
dvcsTag*: string
downloadMethod*: string
tags*: seq[string]
description*: string
@ -53,17 +55,36 @@ proc readPackageInfo*(path: string): TPackageInfo =
else:
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 =
let packages = parseFile(packagesPath)
for p in packages:
if p["name"].str != pkg: continue
resPkg.name = pkg
resPkg.url = p["url"].str
resPkg.downloadMethod = p["method"].str
resPkg.url = p.requiredField("url")
resPkg.version = p.optionalField("version")
resPkg.downloadMethod = p.requiredField("method")
resPkg.dvcsTag = p.optionalField("dvcs-tag")
resPkg.tags = @[]
for t in p["tags"]:
resPkg.tags.add(t.str)
resPkg.description = p["description"].str
resPkg.description = p.requiredField("description")
return true
return false
@ -72,13 +93,15 @@ proc getPackageList*(packagesPath: string): seq[TPackage] =
let packages = parseFile(packagesPath)
for p in packages:
var pkg: TPackage
pkg.name = p["name"].str
pkg.url = p["url"].str
pkg.downloadMethod = p["method"].str
pkg.name = p.requiredField("name")
pkg.version = p.optionalField("version")
pkg.url = p.requiredField("url")
pkg.downloadMethod = p.requiredField("method")
pkg.dvcsTag = p.optionalField("dvcs-tag")
pkg.tags = @[]
for t in p["tags"]:
pkg.tags.add(t.str)
pkg.description = p["description"].str
pkg.description = p.requiredField("description")
result.add(pkg)
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.
## 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
this is that the main project file can then import the modules that it needs
with confidence that the filename of those modules will not change after
installation.
By convention, if you have a single file with the same filename as your package
name, then you can include it in the same directory as the .babel file.
However, if you have other public modules whose names are quite common,
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
a ``private`` folder inside the ``ProjectName/`` folder, these are modules which
the user of your library should not be importing. All files and folders in
``ProjectName/`` will be copied as-is, you can however specify to skip some
directories or files in your .babel file.
a ``private`` folder, these are modules which
the user of your library should not be importing.
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