first implementation of NimScript support
This commit is contained in:
parent
e2d959bf9c
commit
2cf03313fd
6 changed files with 384 additions and 223 deletions
334
src/nimble.nim
334
src/nimble.nim
|
|
@ -10,6 +10,8 @@ import nimblepkg/packageinfo, nimblepkg/version, nimblepkg/tools,
|
||||||
nimblepkg/download, nimblepkg/config, nimblepkg/nimbletypes,
|
nimblepkg/download, nimblepkg/config, nimblepkg/nimbletypes,
|
||||||
nimblepkg/publish
|
nimblepkg/publish
|
||||||
|
|
||||||
|
import compiler/options
|
||||||
|
|
||||||
when not defined(windows):
|
when not defined(windows):
|
||||||
from posix import getpid
|
from posix import getpid
|
||||||
else:
|
else:
|
||||||
|
|
@ -40,7 +42,8 @@ type
|
||||||
ActionType = enum
|
ActionType = enum
|
||||||
actionNil, actionUpdate, actionInit, actionPublish,
|
actionNil, actionUpdate, actionInit, actionPublish,
|
||||||
actionInstall, actionSearch,
|
actionInstall, actionSearch,
|
||||||
actionList, actionBuild, actionPath, actionUninstall, actionCompile
|
actionList, actionBuild, actionPath, actionUninstall, actionCompile,
|
||||||
|
actionCustom
|
||||||
|
|
||||||
Action = object
|
Action = object
|
||||||
case typ: ActionType
|
case typ: ActionType
|
||||||
|
|
@ -99,7 +102,7 @@ Options:
|
||||||
For more information read the Github readme:
|
For more information read the Github readme:
|
||||||
https://github.com/nim-lang/nimble#readme
|
https://github.com/nim-lang/nimble#readme
|
||||||
"""
|
"""
|
||||||
nimbleVersion = "0.6.2"
|
nimbleVersion = "0.7.0"
|
||||||
defaultPackageURL =
|
defaultPackageURL =
|
||||||
"https://github.com/nim-lang/packages/raw/master/packages.json"
|
"https://github.com/nim-lang/packages/raw/master/packages.json"
|
||||||
|
|
||||||
|
|
@ -112,21 +115,21 @@ proc writeVersion() =
|
||||||
[nimbleVersion, CompileDate, CompileTime])
|
[nimbleVersion, CompileDate, CompileTime])
|
||||||
quit(QuitSuccess)
|
quit(QuitSuccess)
|
||||||
|
|
||||||
proc getNimbleDir(options: Options): string =
|
proc getNimbleDir(opt: Options): string =
|
||||||
options.config.nimbleDir
|
opt.config.nimbleDir
|
||||||
|
|
||||||
proc getPkgsDir(options: Options): string =
|
proc getPkgsDir(opt: Options): string =
|
||||||
options.config.nimbleDir / "pkgs"
|
opt.config.nimbleDir / "pkgs"
|
||||||
|
|
||||||
proc getBinDir(options: Options): string =
|
proc getBinDir(opt: Options): string =
|
||||||
options.config.nimbleDir / "bin"
|
opt.config.nimbleDir / "bin"
|
||||||
|
|
||||||
proc prompt(options: Options, question: string): bool =
|
proc prompt(opt: Options, question: string): bool =
|
||||||
## Asks an interactive question and returns the result.
|
## Asks an interactive question and returns the result.
|
||||||
##
|
##
|
||||||
## The proc will return immediately without asking the user if the global
|
## The proc will return immediately without asking the user if the global
|
||||||
## forcePrompts has a value different than dontForcePrompt.
|
## forcePrompts has a value different than dontForcePrompt.
|
||||||
case options.forcePrompts
|
case opt.forcePrompts
|
||||||
of forcePromptYes:
|
of forcePromptYes:
|
||||||
echo(question & " -> [forced yes]")
|
echo(question & " -> [forced yes]")
|
||||||
return true
|
return true
|
||||||
|
|
@ -144,11 +147,11 @@ proc prompt(options: Options, question: string): bool =
|
||||||
else:
|
else:
|
||||||
return false
|
return false
|
||||||
|
|
||||||
proc renameBabelToNimble(options: Options) {.deprecated.} =
|
proc renameBabelToNimble(opt: Options) {.deprecated.} =
|
||||||
let babelDir = getHomeDir() / ".babel"
|
let babelDir = getHomeDir() / ".babel"
|
||||||
let nimbleDir = getHomeDir() / ".nimble"
|
let nimbleDir = getHomeDir() / ".nimble"
|
||||||
if dirExists(babelDir):
|
if dirExists(babelDir):
|
||||||
if options.prompt("Found deprecated babel package directory, would you " &
|
if opt.prompt("Found deprecated babel package directory, would you " &
|
||||||
"like to rename it to nimble?"):
|
"like to rename it to nimble?"):
|
||||||
copyDir(babelDir, nimbleDir)
|
copyDir(babelDir, nimbleDir)
|
||||||
copyFile(babelDir / "babeldata.json", nimbleDir / "nimbledata.json")
|
copyFile(babelDir / "babeldata.json", nimbleDir / "nimbledata.json")
|
||||||
|
|
@ -163,9 +166,10 @@ proc parseCmdLine(): Options =
|
||||||
case kind
|
case kind
|
||||||
of cmdArgument:
|
of cmdArgument:
|
||||||
if result.action.typ == actionNil:
|
if result.action.typ == actionNil:
|
||||||
case key
|
options.command = key
|
||||||
|
case key.normalize()
|
||||||
of "install", "path":
|
of "install", "path":
|
||||||
case key
|
case key.normalize()
|
||||||
of "install":
|
of "install":
|
||||||
result.action.typ = actionInstall
|
result.action.typ = actionInstall
|
||||||
of "path":
|
of "path":
|
||||||
|
|
@ -197,7 +201,8 @@ proc parseCmdLine(): Options =
|
||||||
result.action.packages = @[]
|
result.action.packages = @[]
|
||||||
of "publish":
|
of "publish":
|
||||||
result.action.typ = actionPublish
|
result.action.typ = actionPublish
|
||||||
else: writeHelp()
|
else:
|
||||||
|
result.action.typ = actionCustom
|
||||||
else:
|
else:
|
||||||
case result.action.typ
|
case result.action.typ
|
||||||
of actionNil:
|
of actionNil:
|
||||||
|
|
@ -222,7 +227,7 @@ proc parseCmdLine(): Options =
|
||||||
result.action.projName = key
|
result.action.projName = key
|
||||||
of actionCompile:
|
of actionCompile:
|
||||||
result.action.file = key
|
result.action.file = key
|
||||||
of actionList, actionBuild, actionPublish:
|
of actionList, actionBuild:
|
||||||
writeHelp()
|
writeHelp()
|
||||||
else:
|
else:
|
||||||
discard
|
discard
|
||||||
|
|
@ -264,18 +269,18 @@ proc parseCmdLine(): Options =
|
||||||
else:
|
else:
|
||||||
result.nimbleData = %{"reverseDeps": newJObject()}
|
result.nimbleData = %{"reverseDeps": newJObject()}
|
||||||
|
|
||||||
proc update(options: Options) =
|
proc update(opt: Options) =
|
||||||
## Downloads the package list from the specified URL.
|
## Downloads the package list from the specified URL.
|
||||||
##
|
##
|
||||||
## If the download is successful, the global didUpdatePackages is set to
|
## If the download is successful, the global didUpdatePackages is set to
|
||||||
## true. Otherwise an exception is raised on error.
|
## true. Otherwise an exception is raised on error.
|
||||||
let url =
|
let url =
|
||||||
if options.action.typ == actionUpdate and options.action.optionalURL != "":
|
if opt.action.typ == actionUpdate and opt.action.optionalURL != "":
|
||||||
options.action.optionalURL
|
opt.action.optionalURL
|
||||||
else:
|
else:
|
||||||
defaultPackageURL
|
defaultPackageURL
|
||||||
echo("Downloading package list from " & url)
|
echo("Downloading package list from " & url)
|
||||||
downloadFile(url, options.getNimbleDir() / "packages.json")
|
downloadFile(url, opt.getNimbleDir() / "packages.json")
|
||||||
echo("Done.")
|
echo("Done.")
|
||||||
|
|
||||||
proc checkInstallFile(pkgInfo: PackageInfo,
|
proc checkInstallFile(pkgInfo: PackageInfo,
|
||||||
|
|
@ -326,7 +331,7 @@ proc copyWithExt(origDir, currentDir, dest: string,
|
||||||
result.add copyFileD(path, changeRoot(origDir, dest, path))
|
result.add copyFileD(path, changeRoot(origDir, dest, path))
|
||||||
|
|
||||||
proc copyFilesRec(origDir, currentDir, dest: string,
|
proc copyFilesRec(origDir, currentDir, dest: string,
|
||||||
options: Options, pkgInfo: PackageInfo): HashSet[string] =
|
opt: Options, pkgInfo: PackageInfo): HashSet[string] =
|
||||||
## Copies all the required files, skips files specified in the .nimble file
|
## Copies all the required files, skips files specified in the .nimble file
|
||||||
## (PackageInfo).
|
## (PackageInfo).
|
||||||
## Returns a list of filepaths to files which have been installed.
|
## Returns a list of filepaths to files which have been installed.
|
||||||
|
|
@ -339,7 +344,7 @@ proc copyFilesRec(origDir, currentDir, dest: string,
|
||||||
for file in pkgInfo.installFiles:
|
for file in pkgInfo.installFiles:
|
||||||
let src = origDir / file
|
let src = origDir / file
|
||||||
if not src.existsFile():
|
if not src.existsFile():
|
||||||
if options.prompt("Missing file " & src & ". Continue?"):
|
if opt.prompt("Missing file " & src & ". Continue?"):
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
quit(QuitSuccess)
|
quit(QuitSuccess)
|
||||||
|
|
@ -350,7 +355,7 @@ proc copyFilesRec(origDir, currentDir, dest: string,
|
||||||
# TODO: Allow skipping files inside dirs?
|
# TODO: Allow skipping files inside dirs?
|
||||||
let src = origDir / dir
|
let src = origDir / dir
|
||||||
if not src.existsDir():
|
if not src.existsDir():
|
||||||
if options.prompt("Missing directory " & src & ". Continue?"):
|
if opt.prompt("Missing directory " & src & ". Continue?"):
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
quit(QuitSuccess)
|
quit(QuitSuccess)
|
||||||
|
|
@ -366,7 +371,7 @@ proc copyFilesRec(origDir, currentDir, dest: string,
|
||||||
# Create the dir.
|
# Create the dir.
|
||||||
createDir(changeRoot(origDir, dest, file))
|
createDir(changeRoot(origDir, dest, file))
|
||||||
|
|
||||||
result.incl copyFilesRec(origDir, file, dest, options, pkgInfo)
|
result.incl copyFilesRec(origDir, file, dest, opt, pkgInfo)
|
||||||
else:
|
else:
|
||||||
let skip = pkgInfo.checkInstallFile(origDir, file)
|
let skip = pkgInfo.checkInstallFile(origDir, file)
|
||||||
|
|
||||||
|
|
@ -377,26 +382,26 @@ proc copyFilesRec(origDir, currentDir, dest: string,
|
||||||
result.incl copyFileD(pkgInfo.mypath,
|
result.incl copyFileD(pkgInfo.mypath,
|
||||||
changeRoot(pkgInfo.mypath.splitFile.dir, dest, pkgInfo.mypath))
|
changeRoot(pkgInfo.mypath.splitFile.dir, dest, pkgInfo.mypath))
|
||||||
|
|
||||||
proc saveNimbleData(options: Options) =
|
proc saveNimbleData(opt: Options) =
|
||||||
# TODO: This file should probably be locked.
|
# TODO: This file should probably be locked.
|
||||||
writeFile(options.getNimbleDir() / "nimbledata.json",
|
writeFile(opt.getNimbleDir() / "nimbledata.json",
|
||||||
pretty(options.nimbleData))
|
pretty(opt.nimbleData))
|
||||||
|
|
||||||
proc addRevDep(options: Options, dep: tuple[name, version: string],
|
proc addRevDep(opt: Options, dep: tuple[name, version: string],
|
||||||
pkg: PackageInfo) =
|
pkg: PackageInfo) =
|
||||||
# let depNameVer = dep.name & '-' & dep.version
|
# let depNameVer = dep.name & '-' & dep.version
|
||||||
if not options.nimbleData["reverseDeps"].hasKey(dep.name):
|
if not opt.nimbleData["reverseDeps"].hasKey(dep.name):
|
||||||
options.nimbleData["reverseDeps"][dep.name] = newJObject()
|
opt.nimbleData["reverseDeps"][dep.name] = newJObject()
|
||||||
if not options.nimbleData["reverseDeps"][dep.name].hasKey(dep.version):
|
if not opt.nimbleData["reverseDeps"][dep.name].hasKey(dep.version):
|
||||||
options.nimbleData["reverseDeps"][dep.name][dep.version] = newJArray()
|
opt.nimbleData["reverseDeps"][dep.name][dep.version] = newJArray()
|
||||||
let revDep = %{ "name": %pkg.name, "version": %pkg.version}
|
let revDep = %{ "name": %pkg.name, "version": %pkg.version}
|
||||||
let thisDep = options.nimbleData["reverseDeps"][dep.name][dep.version]
|
let thisDep = opt.nimbleData["reverseDeps"][dep.name][dep.version]
|
||||||
if revDep notin thisDep:
|
if revDep notin thisDep:
|
||||||
thisDep.add revDep
|
thisDep.add revDep
|
||||||
|
|
||||||
proc removeRevDep(options: Options, pkg: PackageInfo) =
|
proc removeRevDep(opt: Options, pkg: PackageInfo) =
|
||||||
## Removes ``pkg`` from the reverse dependencies of every package.
|
## Removes ``pkg`` from the reverse dependencies of every package.
|
||||||
proc remove(options: Options, pkg: PackageInfo, depTup: PkgTuple,
|
proc remove(opt: Options, pkg: PackageInfo, depTup: PkgTuple,
|
||||||
thisDep: JsonNode) =
|
thisDep: JsonNode) =
|
||||||
for ver, val in thisDep:
|
for ver, val in thisDep:
|
||||||
if ver.newVersion in depTup.ver:
|
if ver.newVersion in depTup.ver:
|
||||||
|
|
@ -410,16 +415,16 @@ proc removeRevDep(options: Options, pkg: PackageInfo) =
|
||||||
for depTup in pkg.requires:
|
for depTup in pkg.requires:
|
||||||
if depTup.name.isURL():
|
if depTup.name.isURL():
|
||||||
# We sadly must go through everything in this case...
|
# We sadly must go through everything in this case...
|
||||||
for key, val in options.nimbleData["reverseDeps"]:
|
for key, val in opt.nimbleData["reverseDeps"]:
|
||||||
options.remove(pkg, depTup, val)
|
opt.remove(pkg, depTup, val)
|
||||||
else:
|
else:
|
||||||
let thisDep = options.nimbleData["reverseDeps"][depTup.name]
|
let thisDep = opt.nimbleData["reverseDeps"][depTup.name]
|
||||||
if thisDep.isNil: continue
|
if thisDep.isNil: continue
|
||||||
options.remove(pkg, depTup, thisDep)
|
opt.remove(pkg, depTup, thisDep)
|
||||||
|
|
||||||
# Clean up empty objects/arrays
|
# Clean up empty objects/arrays
|
||||||
var newData = newJObject()
|
var newData = newJObject()
|
||||||
for key, val in options.nimbleData["reverseDeps"]:
|
for key, val in opt.nimbleData["reverseDeps"]:
|
||||||
if val.len != 0:
|
if val.len != 0:
|
||||||
var newVal = newJObject()
|
var newVal = newJObject()
|
||||||
for ver, elem in val:
|
for ver, elem in val:
|
||||||
|
|
@ -427,19 +432,19 @@ proc removeRevDep(options: Options, pkg: PackageInfo) =
|
||||||
newVal[ver] = elem
|
newVal[ver] = elem
|
||||||
if newVal.len != 0:
|
if newVal.len != 0:
|
||||||
newData[key] = newVal
|
newData[key] = newVal
|
||||||
options.nimbleData["reverseDeps"] = newData
|
opt.nimbleData["reverseDeps"] = newData
|
||||||
|
|
||||||
saveNimbleData(options)
|
saveNimbleData(opt)
|
||||||
|
|
||||||
proc install(packages: seq[PkgTuple],
|
proc install(packages: seq[PkgTuple],
|
||||||
options: Options,
|
opt: Options,
|
||||||
doPrompt = true): tuple[paths: seq[string], pkg: PackageInfo]
|
doPrompt = true): tuple[paths: seq[string], pkg: PackageInfo]
|
||||||
proc processDeps(pkginfo: PackageInfo, options: Options): seq[string] =
|
proc processDeps(pkginfo: PackageInfo, opt: Options): seq[string] =
|
||||||
## Verifies and installs dependencies.
|
## Verifies and installs dependencies.
|
||||||
##
|
##
|
||||||
## Returns the list of paths to pass to the compiler during build phase.
|
## Returns the list of paths to pass to the compiler during build phase.
|
||||||
result = @[]
|
result = @[]
|
||||||
let pkglist = getInstalledPkgs(options.getPkgsDir())
|
let pkglist = getInstalledPkgs(opt.getPkgsDir())
|
||||||
var reverseDeps: seq[tuple[name, version: string]] = @[]
|
var reverseDeps: seq[tuple[name, version: string]] = @[]
|
||||||
for dep in pkginfo.requires:
|
for dep in pkginfo.requires:
|
||||||
if dep.name == "nimrod" or dep.name == "nim":
|
if dep.name == "nimrod" or dep.name == "nim":
|
||||||
|
|
@ -451,7 +456,7 @@ proc processDeps(pkginfo: PackageInfo, options: Options): seq[string] =
|
||||||
var pkg: PackageInfo
|
var pkg: PackageInfo
|
||||||
if not findPkg(pkglist, dep, pkg):
|
if not findPkg(pkglist, dep, pkg):
|
||||||
echo("None found, installing...")
|
echo("None found, installing...")
|
||||||
let (paths, installedPkg) = install(@[(dep.name, dep.ver)], options)
|
let (paths, installedPkg) = install(@[(dep.name, dep.ver)], opt)
|
||||||
result.add(paths)
|
result.add(paths)
|
||||||
|
|
||||||
pkg = installedPkg # For addRevDep
|
pkg = installedPkg # For addRevDep
|
||||||
|
|
@ -459,7 +464,7 @@ proc processDeps(pkginfo: PackageInfo, options: Options): seq[string] =
|
||||||
echo("Dependency already satisfied.")
|
echo("Dependency already satisfied.")
|
||||||
result.add(pkg.mypath.splitFile.dir)
|
result.add(pkg.mypath.splitFile.dir)
|
||||||
# Process the dependencies of this dependency.
|
# Process the dependencies of this dependency.
|
||||||
result.add(processDeps(pkg, options))
|
result.add(processDeps(pkg, opt))
|
||||||
reverseDeps.add((pkg.name, pkg.version))
|
reverseDeps.add((pkg.name, pkg.version))
|
||||||
|
|
||||||
# Check if two packages of the same name (but different version) are listed
|
# Check if two packages of the same name (but different version) are listed
|
||||||
|
|
@ -477,8 +482,8 @@ proc processDeps(pkginfo: PackageInfo, options: Options): seq[string] =
|
||||||
# them added if the above errorenous condition occurs
|
# them added if the above errorenous condition occurs
|
||||||
# (unsatisfiable dependendencies).
|
# (unsatisfiable dependendencies).
|
||||||
for i in reverseDeps:
|
for i in reverseDeps:
|
||||||
addRevDep(options, i, pkginfo)
|
addRevDep(opt, i, pkginfo)
|
||||||
saveNimbleData(options)
|
saveNimbleData(opt)
|
||||||
|
|
||||||
proc buildFromDir(pkgInfo: PackageInfo, paths: seq[string], forRelease: bool) =
|
proc buildFromDir(pkgInfo: PackageInfo, paths: seq[string], forRelease: bool) =
|
||||||
## Builds a package as specified by ``pkgInfo``.
|
## Builds a package as specified by ``pkgInfo``.
|
||||||
|
|
@ -505,7 +510,7 @@ proc saveNimbleMeta(pkgDestDir, url: string, filesInstalled: HashSet[string]) =
|
||||||
nimblemeta["files"].add(%changeRoot(pkgDestDir, "", file))
|
nimblemeta["files"].add(%changeRoot(pkgDestDir, "", file))
|
||||||
writeFile(pkgDestDir / "nimblemeta.json", $nimblemeta)
|
writeFile(pkgDestDir / "nimblemeta.json", $nimblemeta)
|
||||||
|
|
||||||
proc removePkgDir(dir: string, options: Options) =
|
proc removePkgDir(dir: string, opt: Options) =
|
||||||
## Removes files belonging to the package in ``dir``.
|
## Removes files belonging to the package in ``dir``.
|
||||||
try:
|
try:
|
||||||
var nimblemeta = parseFile(dir / "nimblemeta.json")
|
var nimblemeta = parseFile(dir / "nimblemeta.json")
|
||||||
|
|
@ -525,12 +530,12 @@ proc removePkgDir(dir: string, options: Options) =
|
||||||
". Files not installed by nimble are present.")
|
". Files not installed by nimble are present.")
|
||||||
except OSError, JsonParsingError:
|
except OSError, JsonParsingError:
|
||||||
echo("Error: Unable to read nimblemeta.json: ", getCurrentExceptionMsg())
|
echo("Error: Unable to read nimblemeta.json: ", getCurrentExceptionMsg())
|
||||||
if not options.prompt("Would you like to COMPLETELY remove ALL files " &
|
if not opt.prompt("Would you like to COMPLETELY remove ALL files " &
|
||||||
"in " & dir & "?"):
|
"in " & dir & "?"):
|
||||||
quit(QuitSuccess)
|
quit(QuitSuccess)
|
||||||
removeDir(dir)
|
removeDir(dir)
|
||||||
|
|
||||||
proc installFromDir(dir: string, latest: bool, options: Options,
|
proc installFromDir(dir: string, latest: bool, opt: Options,
|
||||||
url: string): tuple[paths: seq[string], pkg: PackageInfo] =
|
url: string): tuple[paths: seq[string], pkg: PackageInfo] =
|
||||||
## Returns where package has been installed to, together with paths
|
## Returns where package has been installed to, together with paths
|
||||||
## to the packages this package depends on.
|
## to the packages this package depends on.
|
||||||
|
|
@ -538,10 +543,10 @@ proc installFromDir(dir: string, latest: bool, options: Options,
|
||||||
## ``processDeps`` to gather a list of paths to pass to the nim compiler.
|
## ``processDeps`` to gather a list of paths to pass to the nim compiler.
|
||||||
var pkgInfo = getPkgInfo(dir)
|
var pkgInfo = getPkgInfo(dir)
|
||||||
let realDir = pkgInfo.getRealDir()
|
let realDir = pkgInfo.getRealDir()
|
||||||
let binDir = options.getBinDir()
|
let binDir = opt.getBinDir()
|
||||||
let pkgsDir = options.getPkgsDir()
|
let pkgsDir = opt.getPkgsDir()
|
||||||
# Dependencies need to be processed before the creation of the pkg dir.
|
# Dependencies need to be processed before the creation of the pkg dir.
|
||||||
result.paths = processDeps(pkginfo, options)
|
result.paths = processDeps(pkginfo, opt)
|
||||||
|
|
||||||
echo("Installing ", pkginfo.name, "-", pkginfo.version)
|
echo("Installing ", pkginfo.name, "-", pkginfo.version)
|
||||||
|
|
||||||
|
|
@ -552,10 +557,10 @@ proc installFromDir(dir: string, latest: bool, options: Options,
|
||||||
let versionStr = (if latest: "" else: '-' & pkgInfo.version)
|
let versionStr = (if latest: "" else: '-' & pkgInfo.version)
|
||||||
let pkgDestDir = pkgsDir / (pkgInfo.name & versionStr)
|
let pkgDestDir = pkgsDir / (pkgInfo.name & versionStr)
|
||||||
if existsDir(pkgDestDir) and existsFile(pkgDestDir / "nimblemeta.json"):
|
if existsDir(pkgDestDir) and existsFile(pkgDestDir / "nimblemeta.json"):
|
||||||
if not options.prompt(pkgInfo.name & versionStr &
|
if not opt.prompt(pkgInfo.name & versionStr &
|
||||||
" already exists. Overwrite?"):
|
" already exists. Overwrite?"):
|
||||||
quit(QuitSuccess)
|
quit(QuitSuccess)
|
||||||
removePkgDir(pkgDestDir, options)
|
removePkgDir(pkgDestDir, opt)
|
||||||
# Remove any symlinked binaries
|
# Remove any symlinked binaries
|
||||||
for bin in pkgInfo.bin:
|
for bin in pkgInfo.bin:
|
||||||
# TODO: Check that this binary belongs to the package being installed.
|
# TODO: Check that this binary belongs to the package being installed.
|
||||||
|
|
@ -575,7 +580,7 @@ proc installFromDir(dir: string, latest: bool, options: Options,
|
||||||
if pkgInfo.bin.len > 0:
|
if pkgInfo.bin.len > 0:
|
||||||
createDir(binDir)
|
createDir(binDir)
|
||||||
# Copy all binaries and files that are not skipped
|
# Copy all binaries and files that are not skipped
|
||||||
filesInstalled = copyFilesRec(realDir, realDir, pkgDestDir, options,
|
filesInstalled = copyFilesRec(realDir, realDir, pkgDestDir, opt,
|
||||||
pkgInfo)
|
pkgInfo)
|
||||||
# Set file permissions to +x for all binaries built,
|
# Set file permissions to +x for all binaries built,
|
||||||
# and symlink them on *nix OS' to $nimbleDir/bin/
|
# and symlink them on *nix OS' to $nimbleDir/bin/
|
||||||
|
|
@ -607,7 +612,7 @@ proc installFromDir(dir: string, latest: bool, options: Options,
|
||||||
let dest = binDir / cleanBin.changeFileExt("cmd")
|
let dest = binDir / cleanBin.changeFileExt("cmd")
|
||||||
echo("Creating stub: ", pkgDestDir / bin, " -> ", dest)
|
echo("Creating stub: ", pkgDestDir / bin, " -> ", dest)
|
||||||
var contents = "@"
|
var contents = "@"
|
||||||
if options.config.chcp:
|
if opt.config.chcp:
|
||||||
if fixChcp:
|
if fixChcp:
|
||||||
contents.add "chcp 65001 > nul && "
|
contents.add "chcp 65001 > nul && "
|
||||||
else: contents.add "chcp 65001 > nul\n@"
|
else: contents.add "chcp 65001 > nul\n@"
|
||||||
|
|
@ -620,7 +625,7 @@ proc installFromDir(dir: string, latest: bool, options: Options,
|
||||||
else:
|
else:
|
||||||
{.error: "Sorry, your platform is not supported.".}
|
{.error: "Sorry, your platform is not supported.".}
|
||||||
else:
|
else:
|
||||||
filesInstalled = copyFilesRec(realDir, realDir, pkgDestDir, options,
|
filesInstalled = copyFilesRec(realDir, realDir, pkgDestDir, opt,
|
||||||
pkgInfo)
|
pkgInfo)
|
||||||
|
|
||||||
# Save a nimblemeta.json file.
|
# Save a nimblemeta.json file.
|
||||||
|
|
@ -659,46 +664,46 @@ proc downloadPkg(url: string, verRange: VersionRange,
|
||||||
echo("Downloading ", url, " into ", downloadDir, " using ", downMethod, "...")
|
echo("Downloading ", url, " into ", downloadDir, " using ", downMethod, "...")
|
||||||
result = (downloadDir, doDownload(url, downloadDir, verRange, downMethod))
|
result = (downloadDir, doDownload(url, downloadDir, verRange, downMethod))
|
||||||
|
|
||||||
proc getDownloadInfo*(pv: PkgTuple, options: Options,
|
proc getDownloadInfo*(pv: PkgTuple, opt: Options,
|
||||||
doPrompt: bool): (DownloadMethod, string) =
|
doPrompt: bool): (DownloadMethod, string) =
|
||||||
if pv.name.isURL:
|
if pv.name.isURL:
|
||||||
return (checkUrlType(pv.name), pv.name)
|
return (checkUrlType(pv.name), pv.name)
|
||||||
else:
|
else:
|
||||||
var pkg: Package
|
var pkg: Package
|
||||||
if getPackage(pv.name, options.getNimbleDir() / "packages.json", pkg):
|
if getPackage(pv.name, opt.getNimbleDir() / "packages.json", pkg):
|
||||||
return (pkg.downloadMethod.getDownloadMethod(), pkg.url)
|
return (pkg.downloadMethod.getDownloadMethod(), pkg.url)
|
||||||
else:
|
else:
|
||||||
# If package is not found give the user a chance to update
|
# If package is not found give the user a chance to update
|
||||||
# package.json
|
# package.json
|
||||||
if doPrompt and
|
if doPrompt and
|
||||||
options.prompt(pv.name & " not found in local packages.json, " &
|
opt.prompt(pv.name & " not found in local packages.json, " &
|
||||||
"check internet for updated packages?"):
|
"check internet for updated packages?"):
|
||||||
update(options)
|
update(opt)
|
||||||
return getDownloadInfo(pv, options, doPrompt)
|
return getDownloadInfo(pv, opt, doPrompt)
|
||||||
else:
|
else:
|
||||||
raise newException(NimbleError, "Package not found.")
|
raise newException(NimbleError, "Package not found.")
|
||||||
|
|
||||||
proc install(packages: seq[PkgTuple],
|
proc install(packages: seq[PkgTuple],
|
||||||
options: Options,
|
opt: Options,
|
||||||
doPrompt = true): tuple[paths: seq[string], pkg: PackageInfo] =
|
doPrompt = true): tuple[paths: seq[string], pkg: PackageInfo] =
|
||||||
if packages == @[]:
|
if packages == @[]:
|
||||||
result = installFromDir(getCurrentDir(), false, options, "")
|
result = installFromDir(getCurrentDir(), false, opt, "")
|
||||||
else:
|
else:
|
||||||
# If packages.json is not present ask the user if they want to download it.
|
# If packages.json is not present ask the user if they want to download it.
|
||||||
if not existsFile(options.getNimbleDir / "packages.json"):
|
if not existsFile(opt.getNimbleDir / "packages.json"):
|
||||||
if doPrompt and
|
if doPrompt and
|
||||||
options.prompt("Local packages.json not found, download it from " &
|
opt.prompt("Local packages.json not found, download it from " &
|
||||||
"internet?"):
|
"internet?"):
|
||||||
update(options)
|
update(opt)
|
||||||
else:
|
else:
|
||||||
quit("Please run nimble update.", QuitFailure)
|
quit("Please run nimble update.", QuitFailure)
|
||||||
|
|
||||||
# Install each package.
|
# Install each package.
|
||||||
for pv in packages:
|
for pv in packages:
|
||||||
let (meth, url) = getDownloadInfo(pv, options, doPrompt)
|
let (meth, url) = getDownloadInfo(pv, opt, doPrompt)
|
||||||
let (downloadDir, downloadVersion) = downloadPkg(url, pv.ver, meth)
|
let (downloadDir, downloadVersion) = downloadPkg(url, pv.ver, meth)
|
||||||
try:
|
try:
|
||||||
result = installFromDir(downloadDir, false, options, url)
|
result = installFromDir(downloadDir, false, opt, url)
|
||||||
except BuildFailed:
|
except BuildFailed:
|
||||||
# The package failed to build.
|
# The package failed to build.
|
||||||
# Check if we tried building a tagged version of the package.
|
# Check if we tried building a tagged version of the package.
|
||||||
|
|
@ -707,37 +712,37 @@ proc install(packages: seq[PkgTuple],
|
||||||
# If we tried building a tagged version of the package then
|
# If we tried building a tagged version of the package then
|
||||||
# ask the user whether they want to try building #head.
|
# ask the user whether they want to try building #head.
|
||||||
let promptResult = doPrompt and
|
let promptResult = doPrompt and
|
||||||
options.prompt(("Build failed for '$1@$2', would you" &
|
opt.prompt(("Build failed for '$1@$2', would you" &
|
||||||
" like to try installing '$1@#head' (latest unstable)?") %
|
" like to try installing '$1@#head' (latest unstable)?") %
|
||||||
[pv.name, $downloadVersion])
|
[pv.name, $downloadVersion])
|
||||||
if promptResult:
|
if promptResult:
|
||||||
|
|
||||||
result = install(@[(pv.name, headVer)], options, doPrompt)
|
result = install(@[(pv.name, headVer)], opt, doPrompt)
|
||||||
else:
|
else:
|
||||||
raise newException(BuildFailed,
|
raise newException(BuildFailed,
|
||||||
"Aborting installation due to build failure")
|
"Aborting installation due to build failure")
|
||||||
else:
|
else:
|
||||||
raise
|
raise
|
||||||
|
|
||||||
proc build(options: Options) =
|
proc build(opt: Options) =
|
||||||
var pkgInfo = getPkgInfo(getCurrentDir())
|
var pkgInfo = getPkgInfo(getCurrentDir())
|
||||||
let paths = processDeps(pkginfo, options)
|
let paths = processDeps(pkginfo, opt)
|
||||||
buildFromDir(pkgInfo, paths, false)
|
buildFromDir(pkgInfo, paths, false)
|
||||||
|
|
||||||
proc compile(options: Options) =
|
proc compile(opt: Options) =
|
||||||
var pkgInfo = getPkgInfo(getCurrentDir())
|
var pkgInfo = getPkgInfo(getCurrentDir())
|
||||||
let paths = processDeps(pkginfo, options)
|
let paths = processDeps(pkginfo, opt)
|
||||||
let realDir = pkgInfo.getRealDir()
|
let realDir = pkgInfo.getRealDir()
|
||||||
|
|
||||||
var args = ""
|
var args = ""
|
||||||
for path in paths: args.add("--path:\"" & path & "\" ")
|
for path in paths: args.add("--path:\"" & path & "\" ")
|
||||||
for option in options.action.compileOptions:
|
for option in opt.action.compileOptions:
|
||||||
args.add(option & " ")
|
args.add(option & " ")
|
||||||
|
|
||||||
let bin = options.action.file
|
let bin = opt.action.file
|
||||||
let backend =
|
let backend =
|
||||||
if options.action.backend.len > 0:
|
if opt.action.backend.len > 0:
|
||||||
options.action.backend
|
opt.action.backend
|
||||||
else:
|
else:
|
||||||
pkgInfo.backend
|
pkgInfo.backend
|
||||||
|
|
||||||
|
|
@ -749,27 +754,27 @@ proc compile(options: Options) =
|
||||||
doCmd(getNimBin() & " $# --noBabelPath $# \"$#\"" %
|
doCmd(getNimBin() & " $# --noBabelPath $# \"$#\"" %
|
||||||
[backend, args, bin])
|
[backend, args, bin])
|
||||||
|
|
||||||
proc search(options: Options) =
|
proc search(opt: Options) =
|
||||||
## Searches for matches in ``options.action.search``.
|
## Searches for matches in ``opt.action.search``.
|
||||||
##
|
##
|
||||||
## Searches are done in a case insensitive way making all strings lower case.
|
## Searches are done in a case insensitive way making all strings lower case.
|
||||||
assert options.action.typ == actionSearch
|
assert opt.action.typ == actionSearch
|
||||||
if options.action.search == @[]:
|
if opt.action.search == @[]:
|
||||||
raise newException(NimbleError, "Please specify a search string.")
|
raise newException(NimbleError, "Please specify a search string.")
|
||||||
if not existsFile(options.getNimbleDir() / "packages.json"):
|
if not existsFile(opt.getNimbleDir() / "packages.json"):
|
||||||
raise newException(NimbleError, "Please run nimble update.")
|
raise newException(NimbleError, "Please run nimble update.")
|
||||||
let pkgList = getPackageList(options.getNimbleDir() / "packages.json")
|
let pkgList = getPackageList(opt.getNimbleDir() / "packages.json")
|
||||||
var found = false
|
var found = false
|
||||||
template onFound: stmt =
|
template onFound: stmt =
|
||||||
echoPackage(pkg)
|
echoPackage(pkg)
|
||||||
if options.queryVersions:
|
if opt.queryVersions:
|
||||||
echoPackageVersions(pkg)
|
echoPackageVersions(pkg)
|
||||||
echo(" ")
|
echo(" ")
|
||||||
found = true
|
found = true
|
||||||
break
|
break
|
||||||
|
|
||||||
for pkg in pkgList:
|
for pkg in pkgList:
|
||||||
for word in options.action.search:
|
for word in opt.action.search:
|
||||||
# Search by name.
|
# Search by name.
|
||||||
if word.toLower() in pkg.name.toLower():
|
if word.toLower() in pkg.name.toLower():
|
||||||
onFound()
|
onFound()
|
||||||
|
|
@ -781,19 +786,19 @@ proc search(options: Options) =
|
||||||
if not found:
|
if not found:
|
||||||
echo("No package found.")
|
echo("No package found.")
|
||||||
|
|
||||||
proc list(options: Options) =
|
proc list(opt: Options) =
|
||||||
if not existsFile(options.getNimbleDir() / "packages.json"):
|
if not existsFile(opt.getNimbleDir() / "packages.json"):
|
||||||
raise newException(NimbleError, "Please run nimble update.")
|
raise newException(NimbleError, "Please run nimble update.")
|
||||||
let pkgList = getPackageList(options.getNimbleDir() / "packages.json")
|
let pkgList = getPackageList(opt.getNimbleDir() / "packages.json")
|
||||||
for pkg in pkgList:
|
for pkg in pkgList:
|
||||||
echoPackage(pkg)
|
echoPackage(pkg)
|
||||||
if options.queryVersions:
|
if opt.queryVersions:
|
||||||
echoPackageVersions(pkg)
|
echoPackageVersions(pkg)
|
||||||
echo(" ")
|
echo(" ")
|
||||||
|
|
||||||
proc listInstalled(options: Options) =
|
proc listInstalled(opt: Options) =
|
||||||
var h = initTable[string, seq[string]]()
|
var h = initTable[string, seq[string]]()
|
||||||
let pkgs = getInstalledPkgs(options.getPkgsDir())
|
let pkgs = getInstalledPkgs(opt.getPkgsDir())
|
||||||
for x in pkgs.items():
|
for x in pkgs.items():
|
||||||
let
|
let
|
||||||
pName = x.pkginfo.name
|
pName = x.pkginfo.name
|
||||||
|
|
@ -807,7 +812,7 @@ proc listInstalled(options: Options) =
|
||||||
|
|
||||||
type VersionAndPath = tuple[version: Version, path: string]
|
type VersionAndPath = tuple[version: Version, path: string]
|
||||||
|
|
||||||
proc listPaths(options: Options) =
|
proc listPaths(opt: Options) =
|
||||||
## Loops over installing packages displaying their installed paths.
|
## Loops over installing packages displaying their installed paths.
|
||||||
##
|
##
|
||||||
## If there are several packages installed, only the last one (the version
|
## If there are several packages installed, only the last one (the version
|
||||||
|
|
@ -816,25 +821,27 @@ proc listPaths(options: Options) =
|
||||||
## but at the end quits with a non zero exit error.
|
## but at the end quits with a non zero exit error.
|
||||||
##
|
##
|
||||||
## On success the proc returns normally.
|
## On success the proc returns normally.
|
||||||
assert options.action.typ == actionPath
|
assert opt.action.typ == actionPath
|
||||||
assert(not options.action.packages.isNil)
|
assert(not opt.action.packages.isNil)
|
||||||
var errors = 0
|
var errors = 0
|
||||||
for name, version in options.action.packages.items:
|
for name, version in opt.action.packages.items:
|
||||||
var installed: seq[VersionAndPath] = @[]
|
var installed: seq[VersionAndPath] = @[]
|
||||||
# There may be several, list all available ones and sort by version.
|
# There may be several, list all available ones and sort by version.
|
||||||
for kind, path in walkDir(options.getPkgsDir):
|
for kind, path in walkDir(opt.getPkgsDir):
|
||||||
if kind != pcDir or not path.startsWith(options.getPkgsDir / name):
|
if kind != pcDir or not path.startsWith(opt.getPkgsDir / name):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
let
|
let
|
||||||
|
nimScriptFile = path / name.addFileExt("nims")
|
||||||
babelFile = path / name.addFileExt("babel")
|
babelFile = path / name.addFileExt("babel")
|
||||||
nimbleFile = path / name.addFileExt("nimble")
|
nimbleFile = path / name.addFileExt("nimble")
|
||||||
hasSpec = nimbleFile.existsFile or babelFile.existsFile
|
hasSpec = nimScriptFile.existsFile or
|
||||||
|
nimbleFile.existsFile or babelFile.existsFile
|
||||||
if hasSpec:
|
if hasSpec:
|
||||||
var pkgInfo = getPkgInfo(path)
|
var pkgInfo = getPkgInfo(path)
|
||||||
var v: VersionAndPath
|
var v: VersionAndPath
|
||||||
v.version = newVersion(pkgInfo.version)
|
v.version = newVersion(pkgInfo.version)
|
||||||
v.path = options.getPkgsDir / (pkgInfo.name & '-' & pkgInfo.version)
|
v.path = opt.getPkgsDir / (pkgInfo.name & '-' & pkgInfo.version)
|
||||||
installed.add(v)
|
installed.add(v)
|
||||||
else:
|
else:
|
||||||
echo "Warning: No .nimble file found for ", path
|
echo "Warning: No .nimble file found for ", path
|
||||||
|
|
@ -849,56 +856,64 @@ proc listPaths(options: Options) =
|
||||||
raise newException(NimbleError,
|
raise newException(NimbleError,
|
||||||
"At least one of the specified packages was not found")
|
"At least one of the specified packages was not found")
|
||||||
|
|
||||||
proc init(options: Options) =
|
proc guessAuthor(): string =
|
||||||
|
if dirExists(os.getCurrentDir() / ".git"):
|
||||||
|
let (output, exitCode) = doCmdEx("git config user.name")
|
||||||
|
if exitCode == 0:
|
||||||
|
return output.string.strip
|
||||||
|
return "Anonymous"
|
||||||
|
|
||||||
|
proc init(opt: Options) =
|
||||||
echo("Initializing new Nimble project!")
|
echo("Initializing new Nimble project!")
|
||||||
var
|
var
|
||||||
pkgName, fName: string = ""
|
pkgName, fName: string = ""
|
||||||
outFile: File
|
outFile: File
|
||||||
|
|
||||||
if (options.action.projName != ""):
|
if opt.action.projName != "":
|
||||||
pkgName = options.action.projName
|
pkgName = opt.action.projName
|
||||||
fName = pkgName & ".nimble"
|
fName = pkgName & NimsExt
|
||||||
if (existsFile(os.getCurrentDir() / fName)):
|
if (existsFile(os.getCurrentDir() / fName)):
|
||||||
raise newException(NimbleError, "Already have a nimble file.")
|
raise newException(NimbleError, "Already have a nimscript file.")
|
||||||
else:
|
else:
|
||||||
echo("Enter a project name for this (blank to use working directory), " &
|
echo("Enter a project name for this (blank to use working directory), " &
|
||||||
"Ctrl-C to abort:")
|
"Ctrl-C to abort:")
|
||||||
pkgName = readline(stdin)
|
pkgName = readline(stdin)
|
||||||
if (pkgName == ""):
|
if pkgName == "":
|
||||||
pkgName = os.getCurrentDir().splitPath.tail
|
pkgName = os.getCurrentDir().splitPath.tail
|
||||||
if (pkgName == ""):
|
if pkgName == "":
|
||||||
raise newException(NimbleError, "Could not get default file path.")
|
raise newException(NimbleError, "Could not get default file path.")
|
||||||
fName = pkgName & ".nimble"
|
fName = pkgName & NimsExt
|
||||||
|
|
||||||
# Now need to write out .nimble file with projName and other details
|
# Now need to write out .nimble file with projName and other details
|
||||||
|
|
||||||
if (not existsFile(os.getCurrentDir() / fName) and
|
if (not existsFile(os.getCurrentDir() / fName) and
|
||||||
open(f=outFile, filename = fName, mode = fmWrite)):
|
open(f=outFile, filename = fName, mode = fmWrite)):
|
||||||
outFile.writeln("[Package]")
|
outFile.writeLine """# Package
|
||||||
outFile.writeln("name = \"" & pkgName & "\"")
|
|
||||||
outFile.writeln("version = \"0.1.0\"")
|
|
||||||
outFile.writeln("author = \"Anonymous\"")
|
|
||||||
outFile.writeln("description = \"New Nimble project for Nim\"")
|
|
||||||
outFile.writeln("license = \"MIT\"")
|
|
||||||
outFile.writeln("")
|
|
||||||
outFile.writeln("[Deps]")
|
|
||||||
outFile.writeln("Requires: \"nim >= 0.10.0\"")
|
|
||||||
close(outFile)
|
|
||||||
|
|
||||||
|
version = "1.0.0"
|
||||||
|
author = $1
|
||||||
|
description = ""
|
||||||
|
license = "MIT"
|
||||||
|
|
||||||
|
# Dependencies
|
||||||
|
|
||||||
|
requires "nim >= "0.11.2"
|
||||||
|
""" % guessAuthor().escape()
|
||||||
|
close(outFile)
|
||||||
else:
|
else:
|
||||||
raise newException(NimbleError, "Unable to open file " & fName &
|
raise newException(NimbleError, "Unable to open file " & fName &
|
||||||
" for writing: " & osErrorMsg(osLastError()))
|
" for writing: " & osErrorMsg(osLastError()))
|
||||||
|
|
||||||
proc uninstall(options: Options) =
|
proc uninstall(opt: Options) =
|
||||||
if options.action.packages.len == 0:
|
if opt.action.packages.len == 0:
|
||||||
raise newException(NimbleError,
|
raise newException(NimbleError,
|
||||||
"Please specify the package(s) to uninstall.")
|
"Please specify the package(s) to uninstall.")
|
||||||
|
|
||||||
var pkgsToDelete: seq[PackageInfo] = @[]
|
var pkgsToDelete: seq[PackageInfo] = @[]
|
||||||
# Do some verification.
|
# Do some verification.
|
||||||
for pkgTup in options.action.packages:
|
for pkgTup in opt.action.packages:
|
||||||
echo("Looking for ", pkgTup.name, " (", $pkgTup.ver, ")...")
|
echo("Looking for ", pkgTup.name, " (", $pkgTup.ver, ")...")
|
||||||
let installedPkgs = getInstalledPkgs(options.getPkgsDir())
|
let installedPkgs = getInstalledPkgs(opt.getPkgsDir())
|
||||||
var pkgList = findAllPkgs(installedPkgs, pkgTup)
|
var pkgList = findAllPkgs(installedPkgs, pkgTup)
|
||||||
if pkgList.len == 0:
|
if pkgList.len == 0:
|
||||||
raise newException(NimbleError, "Package not found")
|
raise newException(NimbleError, "Package not found")
|
||||||
|
|
@ -908,7 +923,7 @@ proc uninstall(options: Options) =
|
||||||
for pkg in pkgList:
|
for pkg in pkgList:
|
||||||
# Check whether any packages depend on the ones the user is trying to
|
# Check whether any packages depend on the ones the user is trying to
|
||||||
# uninstall.
|
# uninstall.
|
||||||
let thisPkgsDep = options.nimbleData["reverseDeps"]{pkg.name}{pkg.version}
|
let thisPkgsDep = opt.nimbleData["reverseDeps"]{pkg.name}{pkg.version}
|
||||||
if not thisPkgsDep.isNil:
|
if not thisPkgsDep.isNil:
|
||||||
var reason = ""
|
var reason = ""
|
||||||
if thisPkgsDep.len == 1:
|
if thisPkgsDep.len == 1:
|
||||||
|
|
@ -936,47 +951,50 @@ proc uninstall(options: Options) =
|
||||||
pkgNames.add pkg.name & " (" & pkg.version & ")"
|
pkgNames.add pkg.name & " (" & pkg.version & ")"
|
||||||
|
|
||||||
# Let's confirm that the user wants these packages removed.
|
# Let's confirm that the user wants these packages removed.
|
||||||
if not options.prompt("The following packages will be removed:\n " &
|
if not opt.prompt("The following packages will be removed:\n " &
|
||||||
pkgNames & "\nDo you wish to continue?"):
|
pkgNames & "\nDo you wish to continue?"):
|
||||||
quit(QuitSuccess)
|
quit(QuitSuccess)
|
||||||
|
|
||||||
for pkg in pkgsToDelete:
|
for pkg in pkgsToDelete:
|
||||||
# If we reach this point then the package can be safely removed.
|
# If we reach this point then the package can be safely removed.
|
||||||
removeRevDep(options, pkg)
|
removeRevDep(opt, pkg)
|
||||||
removePkgDir(options.getPkgsDir / (pkg.name & '-' & pkg.version), options)
|
removePkgDir(opt.getPkgsDir / (pkg.name & '-' & pkg.version), opt)
|
||||||
echo("Removed ", pkg.name, " (", $pkg.version, ")")
|
echo("Removed ", pkg.name, " (", $pkg.version, ")")
|
||||||
|
|
||||||
proc doAction(options: Options) =
|
proc getCommand: string = options.command
|
||||||
if not existsDir(options.getNimbleDir()):
|
|
||||||
createDir(options.getNimbleDir())
|
|
||||||
if not existsDir(options.getPkgsDir):
|
|
||||||
createDir(options.getPkgsDir)
|
|
||||||
|
|
||||||
case options.action.typ
|
proc doAction(opt: Options) =
|
||||||
of actionUpdate:
|
if not existsDir(opt.getNimbleDir()):
|
||||||
update(options)
|
createDir(opt.getNimbleDir())
|
||||||
of actionInstall:
|
if not existsDir(opt.getPkgsDir):
|
||||||
discard install(options.action.packages, options)
|
createDir(opt.getPkgsDir)
|
||||||
of actionUninstall:
|
|
||||||
uninstall(options)
|
case getCommand().normalize
|
||||||
of actionSearch:
|
of "udpate":
|
||||||
search(options)
|
update(opt)
|
||||||
of actionList:
|
of "install":
|
||||||
if options.queryInstalled: listInstalled(options)
|
discard install(opt.action.packages, opt)
|
||||||
else: list(options)
|
of "uninstall", "remove", "delete", "del", "rm":
|
||||||
of actionPath:
|
uninstall(opt)
|
||||||
listPaths(options)
|
of "search":
|
||||||
of actionBuild:
|
search(opt)
|
||||||
build(options)
|
of "list":
|
||||||
of actionCompile:
|
if opt.queryInstalled: listInstalled(opt)
|
||||||
compile(options)
|
else: list(opt)
|
||||||
of actionInit:
|
of "path":
|
||||||
init(options)
|
listPaths(opt)
|
||||||
of actionPublish:
|
of "build":
|
||||||
|
build(opt)
|
||||||
|
of "c", "compile", "js", "cpp", "cc":
|
||||||
|
compile(opt)
|
||||||
|
of "init":
|
||||||
|
init(opt)
|
||||||
|
of "publish":
|
||||||
var pkgInfo = getPkgInfo(getCurrentDir())
|
var pkgInfo = getPkgInfo(getCurrentDir())
|
||||||
publish(pkgInfo)
|
publish(pkgInfo)
|
||||||
of actionNil:
|
of "nop": discard
|
||||||
assert false
|
else:
|
||||||
|
raise newException(NimbleError, "Unknown command: " & getCommand())
|
||||||
|
|
||||||
when isMainModule:
|
when isMainModule:
|
||||||
when defined(release):
|
when defined(release):
|
||||||
|
|
|
||||||
|
|
@ -1 +1,2 @@
|
||||||
-d:ssl
|
-d:ssl
|
||||||
|
--path:"$lib/packages/docutils"
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,9 @@
|
||||||
# recursive imports
|
# recursive imports
|
||||||
|
|
||||||
import version
|
import version
|
||||||
|
export version.NimbleError
|
||||||
|
|
||||||
type
|
type
|
||||||
NimbleError* = object of Exception
|
|
||||||
BuildFailed* = object of NimbleError
|
BuildFailed* = object of NimbleError
|
||||||
|
|
||||||
PackageInfo* = object
|
PackageInfo* = object
|
||||||
|
|
@ -27,4 +27,3 @@ type
|
||||||
binDir*: string
|
binDir*: string
|
||||||
srcDir*: string
|
srcDir*: string
|
||||||
backend*: string
|
backend*: string
|
||||||
|
|
||||||
|
|
|
||||||
114
src/nimblepkg/nimscriptsupport.nim
Normal file
114
src/nimblepkg/nimscriptsupport.nim
Normal file
|
|
@ -0,0 +1,114 @@
|
||||||
|
# Copyright (C) Andreas Rumpf. All rights reserved.
|
||||||
|
# BSD License. Look at license.txt for more info.
|
||||||
|
|
||||||
|
## Implements the new configuration system for Nimble. Uses Nim as a
|
||||||
|
## scripting language.
|
||||||
|
|
||||||
|
import
|
||||||
|
compiler/ast, compiler/modules, compiler/passes, compiler/passaux,
|
||||||
|
compiler/condsyms, compiler/options, compiler/sem, compiler/semdata,
|
||||||
|
compiler/llstream, compiler/vm, compiler/vmdef, compiler/commands,
|
||||||
|
compiler/msgs, compiler/magicsys, compiler/lists
|
||||||
|
|
||||||
|
from compiler/scriptconfig import setupVM
|
||||||
|
|
||||||
|
import nimbletypes, version
|
||||||
|
import os, strutils
|
||||||
|
|
||||||
|
proc raiseVariableError(ident, typ: string) {.noinline.} =
|
||||||
|
raise newException(NimbleError,
|
||||||
|
"NimScript's variable '" & ident & "' needs a value of type '" & typ & "'.")
|
||||||
|
|
||||||
|
proc isStrLit(n: PNode): bool = n.kind in {nkStrLit..nkTripleStrLit}
|
||||||
|
|
||||||
|
proc getGlobal(ident: string): string =
|
||||||
|
let n = vm.globalCtx.getGlobalValue(getSysSym ident)
|
||||||
|
if n.isStrLit:
|
||||||
|
result = n.strVal
|
||||||
|
else:
|
||||||
|
raiseVariableError(ident, "string")
|
||||||
|
|
||||||
|
proc getGlobalAsSeq(ident: string): seq[string] =
|
||||||
|
let n = vm.globalCtx.getGlobalValue(getSysSym ident)
|
||||||
|
result = @[]
|
||||||
|
if n.kind == nkBracket:
|
||||||
|
for x in n:
|
||||||
|
if x.isStrLit:
|
||||||
|
result.add n.strVal
|
||||||
|
else:
|
||||||
|
raiseVariableError(ident, "seq[string]")
|
||||||
|
else:
|
||||||
|
raiseVariableError(ident, "seq[string]")
|
||||||
|
|
||||||
|
proc extractRequires(result: var seq[PkgTuple]) =
|
||||||
|
let n = vm.globalCtx.getGlobalValue(getSysSym "requiresData")
|
||||||
|
if n.kind == nkBracket:
|
||||||
|
for x in n:
|
||||||
|
if x.kind == nkPar and x.len == 2 and x[0].isStrLit and x[1].isStrLit:
|
||||||
|
result.add(parseRequires(x[0].strVal & x[1].strVal))
|
||||||
|
elif x.isStrLit:
|
||||||
|
result.add(parseRequires(x.strVal))
|
||||||
|
else:
|
||||||
|
raiseVariableError("requiresData", "seq[(string, VersionReq)]")
|
||||||
|
else:
|
||||||
|
raiseVariableError("requiresData", "seq[(string, VersionReq)]")
|
||||||
|
|
||||||
|
proc readPackageInfoFromNims*(scriptName: string; result: var PackageInfo) =
|
||||||
|
passes.gIncludeFile = includeModule
|
||||||
|
passes.gImportModule = importModule
|
||||||
|
initDefines()
|
||||||
|
|
||||||
|
defineSymbol("nimscript")
|
||||||
|
defineSymbol("nimconfig")
|
||||||
|
defineSymbol("nimble")
|
||||||
|
registerPass(semPass)
|
||||||
|
registerPass(evalPass)
|
||||||
|
|
||||||
|
appendStr(searchPaths, options.libpath)
|
||||||
|
|
||||||
|
var m = makeModule(scriptName)
|
||||||
|
incl(m.flags, sfMainModule)
|
||||||
|
vm.globalCtx = setupVM(m, scriptName)
|
||||||
|
|
||||||
|
compileSystemModule()
|
||||||
|
processModule(m, llStreamOpen(scriptName, fmRead), nil)
|
||||||
|
|
||||||
|
template trivialField(field) =
|
||||||
|
result.field = getGlobal(astToStr field)
|
||||||
|
|
||||||
|
template trivialFieldSeq(field) =
|
||||||
|
result.field.add getGlobalAsSeq(astToStr field)
|
||||||
|
|
||||||
|
# keep reasonable default:
|
||||||
|
let name = getGlobal"packageName"
|
||||||
|
if name.len > 0: result.name = name
|
||||||
|
|
||||||
|
trivialField version
|
||||||
|
trivialField author
|
||||||
|
trivialField description
|
||||||
|
trivialField license
|
||||||
|
trivialField srcdir
|
||||||
|
trivialField bindir
|
||||||
|
trivialFieldSeq skipDirs
|
||||||
|
trivialFieldSeq skipFiles
|
||||||
|
trivialFieldSeq skipExt
|
||||||
|
trivialFieldSeq installDirs
|
||||||
|
trivialFieldSeq installFiles
|
||||||
|
trivialFieldSeq installExt
|
||||||
|
|
||||||
|
extractRequires result.requires
|
||||||
|
|
||||||
|
let binSeq = getGlobalAsSeq("bin")
|
||||||
|
for i in binSeq:
|
||||||
|
result.bin.add(i.addFileExt(ExeExt))
|
||||||
|
|
||||||
|
let backend = getGlobal("backend")
|
||||||
|
if cmpIgnoreStyle(backend, "javascript") == 0:
|
||||||
|
result.backend = "js"
|
||||||
|
else:
|
||||||
|
result.backend = backend.toLower()
|
||||||
|
|
||||||
|
# ensure everything can be called again:
|
||||||
|
resetAllModulesHard()
|
||||||
|
vm.globalCtx = nil
|
||||||
|
initDefines()
|
||||||
|
|
@ -1,7 +1,11 @@
|
||||||
# Copyright (C) Dominik Picheta. All rights reserved.
|
# Copyright (C) Dominik Picheta. All rights reserved.
|
||||||
# BSD License. Look at license.txt for more info.
|
# BSD License. Look at license.txt for more info.
|
||||||
import parsecfg, json, streams, strutils, parseutils, os
|
import parsecfg, json, streams, strutils, parseutils, os
|
||||||
import version, tools, nimbletypes
|
import version, tools, nimbletypes, nimscriptsupport
|
||||||
|
|
||||||
|
const
|
||||||
|
NimsExt* = ".nims"
|
||||||
|
|
||||||
type
|
type
|
||||||
Package* = object
|
Package* = object
|
||||||
# Required fields in a package.
|
# Required fields in a package.
|
||||||
|
|
@ -11,7 +15,7 @@ type
|
||||||
downloadMethod*: string
|
downloadMethod*: string
|
||||||
description*: string
|
description*: string
|
||||||
tags*: seq[string] # Even if empty, always a valid non nil seq. \
|
tags*: seq[string] # Even if empty, always a valid non nil seq. \
|
||||||
# From here on, optional fields set to the emtpy string if not available.
|
# From here on, optional fields set to the empty string if not available.
|
||||||
version*: string
|
version*: string
|
||||||
dvcsTag*: string
|
dvcsTag*: string
|
||||||
web*: string # Info url for humans.
|
web*: string # Info url for humans.
|
||||||
|
|
@ -19,9 +23,12 @@ type
|
||||||
MetaData* = object
|
MetaData* = object
|
||||||
url*: string
|
url*: string
|
||||||
|
|
||||||
proc initPackageInfo(): PackageInfo =
|
NimbleFile* = tuple[isNimScript: bool; file: string]
|
||||||
result.mypath = ""
|
|
||||||
result.name = ""
|
proc initPackageInfo(path: string): PackageInfo =
|
||||||
|
result.mypath = path
|
||||||
|
# reasonable default:
|
||||||
|
result.name = path.splitFile.name
|
||||||
result.version = ""
|
result.version = ""
|
||||||
result.author = ""
|
result.author = ""
|
||||||
result.description = ""
|
result.description = ""
|
||||||
|
|
@ -63,23 +70,6 @@ proc validatePackageInfo(pkgInfo: PackageInfo, path: string) =
|
||||||
"Version may only consist of numbers and the '.' character " &
|
"Version may only consist of numbers and the '.' character " &
|
||||||
"but found '" & c & "'.")
|
"but found '" & c & "'.")
|
||||||
|
|
||||||
proc parseRequires(req: string): PkgTuple =
|
|
||||||
try:
|
|
||||||
if ' ' in req:
|
|
||||||
var i = skipUntil(req, Whitespace)
|
|
||||||
result.name = req[0 .. i].strip
|
|
||||||
result.ver = parseVersionRange(req[i .. req.len-1])
|
|
||||||
elif '#' in req:
|
|
||||||
var i = skipUntil(req, {'#'})
|
|
||||||
result.name = req[0 .. i-1]
|
|
||||||
result.ver = parseVersionRange(req[i .. req.len-1])
|
|
||||||
else:
|
|
||||||
result.name = req.strip
|
|
||||||
result.ver = VersionRange(kind: verAny)
|
|
||||||
except ParseVersionError:
|
|
||||||
raise newException(NimbleError,
|
|
||||||
"Unable to parse dependency version range: " & getCurrentExceptionMsg())
|
|
||||||
|
|
||||||
proc multiSplit(s: string): seq[string] =
|
proc multiSplit(s: string): seq[string] =
|
||||||
## Returns ``s`` split by newline and comma characters.
|
## Returns ``s`` split by newline and comma characters.
|
||||||
##
|
##
|
||||||
|
|
@ -96,9 +86,7 @@ proc multiSplit(s: string): seq[string] =
|
||||||
if len(result) < 1:
|
if len(result) < 1:
|
||||||
return @[s]
|
return @[s]
|
||||||
|
|
||||||
proc readPackageInfo*(path: string): PackageInfo =
|
proc readPackageInfoFromNimble(path: string; result: var PackageInfo) =
|
||||||
result = initPackageInfo()
|
|
||||||
result.mypath = path
|
|
||||||
var fs = newFileStream(path, fmRead)
|
var fs = newFileStream(path, fmRead)
|
||||||
if fs != nil:
|
if fs != nil:
|
||||||
var p: CfgParser
|
var p: CfgParser
|
||||||
|
|
@ -160,7 +148,35 @@ proc readPackageInfo*(path: string): PackageInfo =
|
||||||
close(p)
|
close(p)
|
||||||
else:
|
else:
|
||||||
raise newException(ValueError, "Cannot open package info: " & path)
|
raise newException(ValueError, "Cannot open package info: " & path)
|
||||||
validatePackageInfo(result, path)
|
|
||||||
|
proc getNameVersion*(pkgpath: string): tuple[name, version: string] =
|
||||||
|
## Splits ``pkgpath`` in the format ``/home/user/.nimble/pkgs/package-0.1``
|
||||||
|
## into ``(packagea, 0.1)``
|
||||||
|
result.name = ""
|
||||||
|
result.version = ""
|
||||||
|
let tail = pkgpath.splitPath.tail
|
||||||
|
if '-' notin tail:
|
||||||
|
result.name = tail
|
||||||
|
return
|
||||||
|
|
||||||
|
for i in countdown(tail.len-1, 0):
|
||||||
|
if tail[i] == '-':
|
||||||
|
result.name = tail[0 .. i-1]
|
||||||
|
result.version = tail[i+1 .. tail.len-1]
|
||||||
|
break
|
||||||
|
|
||||||
|
proc readPackageInfo*(nf: NimbleFile; onlyMinimalInfo=false): PackageInfo =
|
||||||
|
result = initPackageInfo(nf.file)
|
||||||
|
if nf.isNimScript:
|
||||||
|
if onlyMinimalInfo:
|
||||||
|
let tmp = getNameVersion(nf.file)
|
||||||
|
result.name = tmp.name
|
||||||
|
result.version = tmp.version
|
||||||
|
else:
|
||||||
|
readPackageInfoFromNims(nf.file, result)
|
||||||
|
else:
|
||||||
|
readPackageInfoFromNimble(nf.file, result)
|
||||||
|
validatePackageInfo(result, nf.file)
|
||||||
|
|
||||||
proc optionalField(obj: JsonNode, name: string, default = ""): string =
|
proc optionalField(obj: JsonNode, name: string, default = ""): string =
|
||||||
## Queries ``obj`` for the optional ``name`` string.
|
## Queries ``obj`` for the optional ``name`` string.
|
||||||
|
|
@ -237,21 +253,34 @@ proc getPackageList*(packagesPath: string): seq[Package] =
|
||||||
let pkg: Package = p.fromJson()
|
let pkg: Package = p.fromJson()
|
||||||
result.add(pkg)
|
result.add(pkg)
|
||||||
|
|
||||||
proc findNimbleFile*(dir: string): string =
|
proc findNimbleFile*(dir: string; error: bool): NimbleFile =
|
||||||
result = ""
|
result = (false, "")
|
||||||
|
var hits = 0
|
||||||
for kind, path in walkDir(dir):
|
for kind, path in walkDir(dir):
|
||||||
if kind == pcFile and path.splitFile.ext in [".babel", ".nimble"]:
|
if kind == pcFile:
|
||||||
if result != "":
|
let ext = path.splitFile.ext
|
||||||
|
case ext
|
||||||
|
of ".babel", ".nimble":
|
||||||
|
result = (false, path)
|
||||||
|
inc hits
|
||||||
|
of NimsExt:
|
||||||
|
result = (true, path)
|
||||||
|
inc hits
|
||||||
|
else: discard
|
||||||
|
if hits >= 2:
|
||||||
raise newException(NimbleError,
|
raise newException(NimbleError,
|
||||||
"Only one .nimble file should be present in " & dir)
|
"Only one .nimble file should be present in " & dir)
|
||||||
result = path
|
elif hits == 0:
|
||||||
|
if error:
|
||||||
|
raise newException(NimbleError,
|
||||||
|
"Specified directory does not contain a .nimble file.")
|
||||||
|
else:
|
||||||
|
# TODO: Abstract logging.
|
||||||
|
echo("WARNING: No .nimble file found for ", dir)
|
||||||
|
|
||||||
proc getPkgInfo*(dir: string): PackageInfo =
|
proc getPkgInfo*(dir: string): PackageInfo =
|
||||||
## Find the .nimble file in ``dir`` and parses it, returning a PackageInfo.
|
## Find the .nimble file in ``dir`` and parses it, returning a PackageInfo.
|
||||||
let nimbleFile = findNimbleFile(dir)
|
let nimbleFile = findNimbleFile(dir, true)
|
||||||
if nimbleFile == "":
|
|
||||||
raise newException(NimbleError,
|
|
||||||
"Specified directory does not contain a .nimble file.")
|
|
||||||
result = readPackageInfo(nimbleFile)
|
result = readPackageInfo(nimbleFile)
|
||||||
|
|
||||||
proc getInstalledPkgs*(libsDir: string):
|
proc getInstalledPkgs*(libsDir: string):
|
||||||
|
|
@ -262,13 +291,10 @@ proc getInstalledPkgs*(libsDir: string):
|
||||||
result = @[]
|
result = @[]
|
||||||
for kind, path in walkDir(libsDir):
|
for kind, path in walkDir(libsDir):
|
||||||
if kind == pcDir:
|
if kind == pcDir:
|
||||||
let nimbleFile = findNimbleFile(path)
|
let nimbleFile = findNimbleFile(path, false)
|
||||||
if nimbleFile != "":
|
if nimbleFile.file != "":
|
||||||
let meta = readMetaData(path)
|
let meta = readMetaData(path)
|
||||||
result.add((readPackageInfo(nimbleFile), meta))
|
result.add((readPackageInfo(nimbleFile, true), meta))
|
||||||
else:
|
|
||||||
# TODO: Abstract logging.
|
|
||||||
echo("WARNING: No .nimble file found for ", path)
|
|
||||||
|
|
||||||
proc findPkg*(pkglist: seq[tuple[pkginfo: PackageInfo, meta: MetaData]],
|
proc findPkg*(pkglist: seq[tuple[pkginfo: PackageInfo, meta: MetaData]],
|
||||||
dep: PkgTuple,
|
dep: PkgTuple,
|
||||||
|
|
@ -280,8 +306,8 @@ proc findPkg*(pkglist: seq[tuple[pkginfo: PackageInfo, meta: MetaData]],
|
||||||
##
|
##
|
||||||
## **Note**: dep.name here could be a URL, hence the need for pkglist.meta.
|
## **Note**: dep.name here could be a URL, hence the need for pkglist.meta.
|
||||||
for pkg in pkglist:
|
for pkg in pkglist:
|
||||||
if pkg.pkginfo.name.normalize != dep.name.normalize and
|
if cmpIgnoreStyle(pkg.pkginfo.name, dep.name) != 0 and
|
||||||
pkg.meta.url.normalize != dep.name.normalize: continue
|
cmpIgnoreStyle(pkg.meta.url, dep.name) != 0: continue
|
||||||
if withinRange(newVersion(pkg.pkginfo.version), dep.ver):
|
if withinRange(newVersion(pkg.pkginfo.version), dep.ver):
|
||||||
if not result or newVersion(r.version) < newVersion(pkg.pkginfo.version):
|
if not result or newVersion(r.version) < newVersion(pkg.pkginfo.version):
|
||||||
r = pkg.pkginfo
|
r = pkg.pkginfo
|
||||||
|
|
@ -294,8 +320,8 @@ proc findAllPkgs*(pkglist: seq[tuple[pkginfo: PackageInfo, meta: MetaData]],
|
||||||
## packages if multiple are found.
|
## packages if multiple are found.
|
||||||
result = @[]
|
result = @[]
|
||||||
for pkg in pkglist:
|
for pkg in pkglist:
|
||||||
if pkg.pkginfo.name.normalize != dep.name.normalize and
|
if cmpIgnoreStyle(pkg.pkginfo.name, dep.name) != 0 and
|
||||||
pkg.meta.url.normalize != dep.name.normalize: continue
|
cmpIgnoreStyle(pkg.meta.url, dep.name) != 0: continue
|
||||||
if withinRange(newVersion(pkg.pkginfo.version), dep.ver):
|
if withinRange(newVersion(pkg.pkginfo.version), dep.ver):
|
||||||
result.add pkg.pkginfo
|
result.add pkg.pkginfo
|
||||||
|
|
||||||
|
|
@ -314,22 +340,6 @@ proc getOutputDir*(pkgInfo: PackageInfo, bin: string): string =
|
||||||
else:
|
else:
|
||||||
result = pkgInfo.mypath.splitFile.dir / bin
|
result = pkgInfo.mypath.splitFile.dir / bin
|
||||||
|
|
||||||
proc getNameVersion*(pkgpath: string): tuple[name, version: string] =
|
|
||||||
## Splits ``pkgpath`` in the format ``/home/user/.nimble/pkgs/package-0.1``
|
|
||||||
## into ``(packagea, 0.1)``
|
|
||||||
result.name = ""
|
|
||||||
result.version = ""
|
|
||||||
let tail = pkgpath.splitPath.tail
|
|
||||||
if '-' notin tail:
|
|
||||||
result.name = tail
|
|
||||||
return
|
|
||||||
|
|
||||||
for i in countdown(tail.len-1, 0):
|
|
||||||
if tail[i] == '-':
|
|
||||||
result.name = tail[0 .. i-1]
|
|
||||||
result.version = tail[i+1 .. tail.len-1]
|
|
||||||
break
|
|
||||||
|
|
||||||
proc echoPackage*(pkg: Package) =
|
proc echoPackage*(pkg: Package) =
|
||||||
echo(pkg.name & ":")
|
echo(pkg.name & ":")
|
||||||
echo(" url: " & pkg.url & " (" & pkg.downloadMethod & ")")
|
echo(" url: " & pkg.url & " (" & pkg.downloadMethod & ")")
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ type
|
||||||
PkgTuple* = tuple[name: string, ver: VersionRange]
|
PkgTuple* = tuple[name: string, ver: VersionRange]
|
||||||
|
|
||||||
ParseVersionError* = object of ValueError
|
ParseVersionError* = object of ValueError
|
||||||
|
NimbleError* = object of Exception
|
||||||
|
|
||||||
proc newVersion*(ver: string): Version = return Version(ver)
|
proc newVersion*(ver: string): Version = return Version(ver)
|
||||||
proc newSpecial*(spe: string): Special = return Special(spe)
|
proc newSpecial*(spe: string): Special = return Special(spe)
|
||||||
|
|
@ -198,6 +199,24 @@ proc parseVersionRange*(s: string): VersionRange =
|
||||||
"Unexpected char in version range: " & s[i])
|
"Unexpected char in version range: " & s[i])
|
||||||
inc(i)
|
inc(i)
|
||||||
|
|
||||||
|
|
||||||
|
proc parseRequires*(req: string): PkgTuple =
|
||||||
|
try:
|
||||||
|
if ' ' in req:
|
||||||
|
var i = skipUntil(req, Whitespace)
|
||||||
|
result.name = req[0 .. i].strip
|
||||||
|
result.ver = parseVersionRange(req[i .. req.len-1])
|
||||||
|
elif '#' in req:
|
||||||
|
var i = skipUntil(req, {'#'})
|
||||||
|
result.name = req[0 .. i-1]
|
||||||
|
result.ver = parseVersionRange(req[i .. req.len-1])
|
||||||
|
else:
|
||||||
|
result.name = req.strip
|
||||||
|
result.ver = VersionRange(kind: verAny)
|
||||||
|
except ParseVersionError:
|
||||||
|
raise newException(NimbleError,
|
||||||
|
"Unable to parse dependency version range: " & getCurrentExceptionMsg())
|
||||||
|
|
||||||
proc `$`*(verRange: VersionRange): string =
|
proc `$`*(verRange: VersionRange): string =
|
||||||
case verRange.kind
|
case verRange.kind
|
||||||
of verLater:
|
of verLater:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue