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.")
|
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)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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) =
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue