Versioning support, changes to directory structure.
This commit is contained in:
parent
c1d216a8f4
commit
423e2d3490
3 changed files with 76 additions and 54 deletions
67
babel.nim
67
babel.nim
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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) =
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue