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/publish
|
||||
|
||||
import compiler/options
|
||||
|
||||
when not defined(windows):
|
||||
from posix import getpid
|
||||
else:
|
||||
|
|
@ -40,7 +42,8 @@ type
|
|||
ActionType = enum
|
||||
actionNil, actionUpdate, actionInit, actionPublish,
|
||||
actionInstall, actionSearch,
|
||||
actionList, actionBuild, actionPath, actionUninstall, actionCompile
|
||||
actionList, actionBuild, actionPath, actionUninstall, actionCompile,
|
||||
actionCustom
|
||||
|
||||
Action = object
|
||||
case typ: ActionType
|
||||
|
|
@ -99,7 +102,7 @@ Options:
|
|||
For more information read the Github readme:
|
||||
https://github.com/nim-lang/nimble#readme
|
||||
"""
|
||||
nimbleVersion = "0.6.2"
|
||||
nimbleVersion = "0.7.0"
|
||||
defaultPackageURL =
|
||||
"https://github.com/nim-lang/packages/raw/master/packages.json"
|
||||
|
||||
|
|
@ -112,21 +115,21 @@ proc writeVersion() =
|
|||
[nimbleVersion, CompileDate, CompileTime])
|
||||
quit(QuitSuccess)
|
||||
|
||||
proc getNimbleDir(options: Options): string =
|
||||
options.config.nimbleDir
|
||||
proc getNimbleDir(opt: Options): string =
|
||||
opt.config.nimbleDir
|
||||
|
||||
proc getPkgsDir(options: Options): string =
|
||||
options.config.nimbleDir / "pkgs"
|
||||
proc getPkgsDir(opt: Options): string =
|
||||
opt.config.nimbleDir / "pkgs"
|
||||
|
||||
proc getBinDir(options: Options): string =
|
||||
options.config.nimbleDir / "bin"
|
||||
proc getBinDir(opt: Options): string =
|
||||
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.
|
||||
##
|
||||
## The proc will return immediately without asking the user if the global
|
||||
## forcePrompts has a value different than dontForcePrompt.
|
||||
case options.forcePrompts
|
||||
case opt.forcePrompts
|
||||
of forcePromptYes:
|
||||
echo(question & " -> [forced yes]")
|
||||
return true
|
||||
|
|
@ -144,11 +147,11 @@ proc prompt(options: Options, question: string): bool =
|
|||
else:
|
||||
return false
|
||||
|
||||
proc renameBabelToNimble(options: Options) {.deprecated.} =
|
||||
proc renameBabelToNimble(opt: Options) {.deprecated.} =
|
||||
let babelDir = getHomeDir() / ".babel"
|
||||
let nimbleDir = getHomeDir() / ".nimble"
|
||||
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?"):
|
||||
copyDir(babelDir, nimbleDir)
|
||||
copyFile(babelDir / "babeldata.json", nimbleDir / "nimbledata.json")
|
||||
|
|
@ -163,9 +166,10 @@ proc parseCmdLine(): Options =
|
|||
case kind
|
||||
of cmdArgument:
|
||||
if result.action.typ == actionNil:
|
||||
case key
|
||||
options.command = key
|
||||
case key.normalize()
|
||||
of "install", "path":
|
||||
case key
|
||||
case key.normalize()
|
||||
of "install":
|
||||
result.action.typ = actionInstall
|
||||
of "path":
|
||||
|
|
@ -197,7 +201,8 @@ proc parseCmdLine(): Options =
|
|||
result.action.packages = @[]
|
||||
of "publish":
|
||||
result.action.typ = actionPublish
|
||||
else: writeHelp()
|
||||
else:
|
||||
result.action.typ = actionCustom
|
||||
else:
|
||||
case result.action.typ
|
||||
of actionNil:
|
||||
|
|
@ -222,7 +227,7 @@ proc parseCmdLine(): Options =
|
|||
result.action.projName = key
|
||||
of actionCompile:
|
||||
result.action.file = key
|
||||
of actionList, actionBuild, actionPublish:
|
||||
of actionList, actionBuild:
|
||||
writeHelp()
|
||||
else:
|
||||
discard
|
||||
|
|
@ -264,18 +269,18 @@ proc parseCmdLine(): Options =
|
|||
else:
|
||||
result.nimbleData = %{"reverseDeps": newJObject()}
|
||||
|
||||
proc update(options: Options) =
|
||||
proc update(opt: Options) =
|
||||
## Downloads the package list from the specified URL.
|
||||
##
|
||||
## If the download is successful, the global didUpdatePackages is set to
|
||||
## true. Otherwise an exception is raised on error.
|
||||
let url =
|
||||
if options.action.typ == actionUpdate and options.action.optionalURL != "":
|
||||
options.action.optionalURL
|
||||
if opt.action.typ == actionUpdate and opt.action.optionalURL != "":
|
||||
opt.action.optionalURL
|
||||
else:
|
||||
defaultPackageURL
|
||||
echo("Downloading package list from " & url)
|
||||
downloadFile(url, options.getNimbleDir() / "packages.json")
|
||||
downloadFile(url, opt.getNimbleDir() / "packages.json")
|
||||
echo("Done.")
|
||||
|
||||
proc checkInstallFile(pkgInfo: PackageInfo,
|
||||
|
|
@ -326,7 +331,7 @@ proc copyWithExt(origDir, currentDir, dest: string,
|
|||
result.add copyFileD(path, changeRoot(origDir, dest, path))
|
||||
|
||||
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
|
||||
## (PackageInfo).
|
||||
## 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:
|
||||
let src = origDir / file
|
||||
if not src.existsFile():
|
||||
if options.prompt("Missing file " & src & ". Continue?"):
|
||||
if opt.prompt("Missing file " & src & ". Continue?"):
|
||||
continue
|
||||
else:
|
||||
quit(QuitSuccess)
|
||||
|
|
@ -350,7 +355,7 @@ proc copyFilesRec(origDir, currentDir, dest: string,
|
|||
# TODO: Allow skipping files inside dirs?
|
||||
let src = origDir / dir
|
||||
if not src.existsDir():
|
||||
if options.prompt("Missing directory " & src & ". Continue?"):
|
||||
if opt.prompt("Missing directory " & src & ". Continue?"):
|
||||
continue
|
||||
else:
|
||||
quit(QuitSuccess)
|
||||
|
|
@ -366,7 +371,7 @@ proc copyFilesRec(origDir, currentDir, dest: string,
|
|||
# Create the dir.
|
||||
createDir(changeRoot(origDir, dest, file))
|
||||
|
||||
result.incl copyFilesRec(origDir, file, dest, options, pkgInfo)
|
||||
result.incl copyFilesRec(origDir, file, dest, opt, pkgInfo)
|
||||
else:
|
||||
let skip = pkgInfo.checkInstallFile(origDir, file)
|
||||
|
||||
|
|
@ -377,26 +382,26 @@ proc copyFilesRec(origDir, currentDir, dest: string,
|
|||
result.incl copyFileD(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.
|
||||
writeFile(options.getNimbleDir() / "nimbledata.json",
|
||||
pretty(options.nimbleData))
|
||||
writeFile(opt.getNimbleDir() / "nimbledata.json",
|
||||
pretty(opt.nimbleData))
|
||||
|
||||
proc addRevDep(options: Options, dep: tuple[name, version: string],
|
||||
proc addRevDep(opt: Options, dep: tuple[name, version: string],
|
||||
pkg: PackageInfo) =
|
||||
# let depNameVer = dep.name & '-' & dep.version
|
||||
if not options.nimbleData["reverseDeps"].hasKey(dep.name):
|
||||
options.nimbleData["reverseDeps"][dep.name] = newJObject()
|
||||
if not options.nimbleData["reverseDeps"][dep.name].hasKey(dep.version):
|
||||
options.nimbleData["reverseDeps"][dep.name][dep.version] = newJArray()
|
||||
if not opt.nimbleData["reverseDeps"].hasKey(dep.name):
|
||||
opt.nimbleData["reverseDeps"][dep.name] = newJObject()
|
||||
if not opt.nimbleData["reverseDeps"][dep.name].hasKey(dep.version):
|
||||
opt.nimbleData["reverseDeps"][dep.name][dep.version] = newJArray()
|
||||
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:
|
||||
thisDep.add revDep
|
||||
|
||||
proc removeRevDep(options: Options, pkg: PackageInfo) =
|
||||
proc removeRevDep(opt: Options, pkg: PackageInfo) =
|
||||
## 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) =
|
||||
for ver, val in thisDep:
|
||||
if ver.newVersion in depTup.ver:
|
||||
|
|
@ -410,16 +415,16 @@ proc removeRevDep(options: Options, pkg: PackageInfo) =
|
|||
for depTup in pkg.requires:
|
||||
if depTup.name.isURL():
|
||||
# We sadly must go through everything in this case...
|
||||
for key, val in options.nimbleData["reverseDeps"]:
|
||||
options.remove(pkg, depTup, val)
|
||||
for key, val in opt.nimbleData["reverseDeps"]:
|
||||
opt.remove(pkg, depTup, val)
|
||||
else:
|
||||
let thisDep = options.nimbleData["reverseDeps"][depTup.name]
|
||||
let thisDep = opt.nimbleData["reverseDeps"][depTup.name]
|
||||
if thisDep.isNil: continue
|
||||
options.remove(pkg, depTup, thisDep)
|
||||
opt.remove(pkg, depTup, thisDep)
|
||||
|
||||
# Clean up empty objects/arrays
|
||||
var newData = newJObject()
|
||||
for key, val in options.nimbleData["reverseDeps"]:
|
||||
for key, val in opt.nimbleData["reverseDeps"]:
|
||||
if val.len != 0:
|
||||
var newVal = newJObject()
|
||||
for ver, elem in val:
|
||||
|
|
@ -427,19 +432,19 @@ proc removeRevDep(options: Options, pkg: PackageInfo) =
|
|||
newVal[ver] = elem
|
||||
if newVal.len != 0:
|
||||
newData[key] = newVal
|
||||
options.nimbleData["reverseDeps"] = newData
|
||||
opt.nimbleData["reverseDeps"] = newData
|
||||
|
||||
saveNimbleData(options)
|
||||
saveNimbleData(opt)
|
||||
|
||||
proc install(packages: seq[PkgTuple],
|
||||
options: Options,
|
||||
opt: Options,
|
||||
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.
|
||||
##
|
||||
## Returns the list of paths to pass to the compiler during build phase.
|
||||
result = @[]
|
||||
let pkglist = getInstalledPkgs(options.getPkgsDir())
|
||||
let pkglist = getInstalledPkgs(opt.getPkgsDir())
|
||||
var reverseDeps: seq[tuple[name, version: string]] = @[]
|
||||
for dep in pkginfo.requires:
|
||||
if dep.name == "nimrod" or dep.name == "nim":
|
||||
|
|
@ -451,7 +456,7 @@ proc processDeps(pkginfo: PackageInfo, options: Options): seq[string] =
|
|||
var pkg: PackageInfo
|
||||
if not findPkg(pkglist, dep, pkg):
|
||||
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)
|
||||
|
||||
pkg = installedPkg # For addRevDep
|
||||
|
|
@ -459,7 +464,7 @@ proc processDeps(pkginfo: PackageInfo, options: Options): seq[string] =
|
|||
echo("Dependency already satisfied.")
|
||||
result.add(pkg.mypath.splitFile.dir)
|
||||
# Process the dependencies of this dependency.
|
||||
result.add(processDeps(pkg, options))
|
||||
result.add(processDeps(pkg, opt))
|
||||
reverseDeps.add((pkg.name, pkg.version))
|
||||
|
||||
# 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
|
||||
# (unsatisfiable dependendencies).
|
||||
for i in reverseDeps:
|
||||
addRevDep(options, i, pkginfo)
|
||||
saveNimbleData(options)
|
||||
addRevDep(opt, i, pkginfo)
|
||||
saveNimbleData(opt)
|
||||
|
||||
proc buildFromDir(pkgInfo: PackageInfo, paths: seq[string], forRelease: bool) =
|
||||
## 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))
|
||||
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``.
|
||||
try:
|
||||
var nimblemeta = parseFile(dir / "nimblemeta.json")
|
||||
|
|
@ -525,12 +530,12 @@ proc removePkgDir(dir: string, options: Options) =
|
|||
". Files not installed by nimble are present.")
|
||||
except OSError, JsonParsingError:
|
||||
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 & "?"):
|
||||
quit(QuitSuccess)
|
||||
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] =
|
||||
## Returns where package has been installed to, together with paths
|
||||
## 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.
|
||||
var pkgInfo = getPkgInfo(dir)
|
||||
let realDir = pkgInfo.getRealDir()
|
||||
let binDir = options.getBinDir()
|
||||
let pkgsDir = options.getPkgsDir()
|
||||
let binDir = opt.getBinDir()
|
||||
let pkgsDir = opt.getPkgsDir()
|
||||
# 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)
|
||||
|
||||
|
|
@ -552,10 +557,10 @@ proc installFromDir(dir: string, latest: bool, options: Options,
|
|||
let versionStr = (if latest: "" else: '-' & pkgInfo.version)
|
||||
let pkgDestDir = pkgsDir / (pkgInfo.name & versionStr)
|
||||
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?"):
|
||||
quit(QuitSuccess)
|
||||
removePkgDir(pkgDestDir, options)
|
||||
removePkgDir(pkgDestDir, opt)
|
||||
# Remove any symlinked binaries
|
||||
for bin in pkgInfo.bin:
|
||||
# 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:
|
||||
createDir(binDir)
|
||||
# Copy all binaries and files that are not skipped
|
||||
filesInstalled = copyFilesRec(realDir, realDir, pkgDestDir, options,
|
||||
filesInstalled = copyFilesRec(realDir, realDir, pkgDestDir, opt,
|
||||
pkgInfo)
|
||||
# Set file permissions to +x for all binaries built,
|
||||
# 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")
|
||||
echo("Creating stub: ", pkgDestDir / bin, " -> ", dest)
|
||||
var contents = "@"
|
||||
if options.config.chcp:
|
||||
if opt.config.chcp:
|
||||
if fixChcp:
|
||||
contents.add "chcp 65001 > nul && "
|
||||
else: contents.add "chcp 65001 > nul\n@"
|
||||
|
|
@ -620,7 +625,7 @@ proc installFromDir(dir: string, latest: bool, options: Options,
|
|||
else:
|
||||
{.error: "Sorry, your platform is not supported.".}
|
||||
else:
|
||||
filesInstalled = copyFilesRec(realDir, realDir, pkgDestDir, options,
|
||||
filesInstalled = copyFilesRec(realDir, realDir, pkgDestDir, opt,
|
||||
pkgInfo)
|
||||
|
||||
# Save a nimblemeta.json file.
|
||||
|
|
@ -659,46 +664,46 @@ proc downloadPkg(url: string, verRange: VersionRange,
|
|||
echo("Downloading ", url, " into ", downloadDir, " using ", downMethod, "...")
|
||||
result = (downloadDir, doDownload(url, downloadDir, verRange, downMethod))
|
||||
|
||||
proc getDownloadInfo*(pv: PkgTuple, options: Options,
|
||||
proc getDownloadInfo*(pv: PkgTuple, opt: Options,
|
||||
doPrompt: bool): (DownloadMethod, string) =
|
||||
if pv.name.isURL:
|
||||
return (checkUrlType(pv.name), pv.name)
|
||||
else:
|
||||
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)
|
||||
else:
|
||||
# If package is not found give the user a chance to update
|
||||
# package.json
|
||||
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?"):
|
||||
update(options)
|
||||
return getDownloadInfo(pv, options, doPrompt)
|
||||
update(opt)
|
||||
return getDownloadInfo(pv, opt, doPrompt)
|
||||
else:
|
||||
raise newException(NimbleError, "Package not found.")
|
||||
|
||||
proc install(packages: seq[PkgTuple],
|
||||
options: Options,
|
||||
opt: Options,
|
||||
doPrompt = true): tuple[paths: seq[string], pkg: PackageInfo] =
|
||||
if packages == @[]:
|
||||
result = installFromDir(getCurrentDir(), false, options, "")
|
||||
result = installFromDir(getCurrentDir(), false, opt, "")
|
||||
else:
|
||||
# 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
|
||||
options.prompt("Local packages.json not found, download it from " &
|
||||
opt.prompt("Local packages.json not found, download it from " &
|
||||
"internet?"):
|
||||
update(options)
|
||||
update(opt)
|
||||
else:
|
||||
quit("Please run nimble update.", QuitFailure)
|
||||
|
||||
# Install each package.
|
||||
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)
|
||||
try:
|
||||
result = installFromDir(downloadDir, false, options, url)
|
||||
result = installFromDir(downloadDir, false, opt, url)
|
||||
except BuildFailed:
|
||||
# The package failed to build.
|
||||
# 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
|
||||
# ask the user whether they want to try building #head.
|
||||
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)?") %
|
||||
[pv.name, $downloadVersion])
|
||||
if promptResult:
|
||||
|
||||
result = install(@[(pv.name, headVer)], options, doPrompt)
|
||||
result = install(@[(pv.name, headVer)], opt, doPrompt)
|
||||
else:
|
||||
raise newException(BuildFailed,
|
||||
"Aborting installation due to build failure")
|
||||
else:
|
||||
raise
|
||||
|
||||
proc build(options: Options) =
|
||||
proc build(opt: Options) =
|
||||
var pkgInfo = getPkgInfo(getCurrentDir())
|
||||
let paths = processDeps(pkginfo, options)
|
||||
let paths = processDeps(pkginfo, opt)
|
||||
buildFromDir(pkgInfo, paths, false)
|
||||
|
||||
proc compile(options: Options) =
|
||||
proc compile(opt: Options) =
|
||||
var pkgInfo = getPkgInfo(getCurrentDir())
|
||||
let paths = processDeps(pkginfo, options)
|
||||
let paths = processDeps(pkginfo, opt)
|
||||
let realDir = pkgInfo.getRealDir()
|
||||
|
||||
var args = ""
|
||||
for path in paths: args.add("--path:\"" & path & "\" ")
|
||||
for option in options.action.compileOptions:
|
||||
for option in opt.action.compileOptions:
|
||||
args.add(option & " ")
|
||||
|
||||
let bin = options.action.file
|
||||
let bin = opt.action.file
|
||||
let backend =
|
||||
if options.action.backend.len > 0:
|
||||
options.action.backend
|
||||
if opt.action.backend.len > 0:
|
||||
opt.action.backend
|
||||
else:
|
||||
pkgInfo.backend
|
||||
|
||||
|
|
@ -749,27 +754,27 @@ proc compile(options: Options) =
|
|||
doCmd(getNimBin() & " $# --noBabelPath $# \"$#\"" %
|
||||
[backend, args, bin])
|
||||
|
||||
proc search(options: Options) =
|
||||
## Searches for matches in ``options.action.search``.
|
||||
proc search(opt: Options) =
|
||||
## Searches for matches in ``opt.action.search``.
|
||||
##
|
||||
## Searches are done in a case insensitive way making all strings lower case.
|
||||
assert options.action.typ == actionSearch
|
||||
if options.action.search == @[]:
|
||||
assert opt.action.typ == actionSearch
|
||||
if opt.action.search == @[]:
|
||||
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.")
|
||||
let pkgList = getPackageList(options.getNimbleDir() / "packages.json")
|
||||
let pkgList = getPackageList(opt.getNimbleDir() / "packages.json")
|
||||
var found = false
|
||||
template onFound: stmt =
|
||||
echoPackage(pkg)
|
||||
if options.queryVersions:
|
||||
if opt.queryVersions:
|
||||
echoPackageVersions(pkg)
|
||||
echo(" ")
|
||||
found = true
|
||||
break
|
||||
|
||||
for pkg in pkgList:
|
||||
for word in options.action.search:
|
||||
for word in opt.action.search:
|
||||
# Search by name.
|
||||
if word.toLower() in pkg.name.toLower():
|
||||
onFound()
|
||||
|
|
@ -781,19 +786,19 @@ proc search(options: Options) =
|
|||
if not found:
|
||||
echo("No package found.")
|
||||
|
||||
proc list(options: Options) =
|
||||
if not existsFile(options.getNimbleDir() / "packages.json"):
|
||||
proc list(opt: Options) =
|
||||
if not existsFile(opt.getNimbleDir() / "packages.json"):
|
||||
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:
|
||||
echoPackage(pkg)
|
||||
if options.queryVersions:
|
||||
if opt.queryVersions:
|
||||
echoPackageVersions(pkg)
|
||||
echo(" ")
|
||||
|
||||
proc listInstalled(options: Options) =
|
||||
proc listInstalled(opt: Options) =
|
||||
var h = initTable[string, seq[string]]()
|
||||
let pkgs = getInstalledPkgs(options.getPkgsDir())
|
||||
let pkgs = getInstalledPkgs(opt.getPkgsDir())
|
||||
for x in pkgs.items():
|
||||
let
|
||||
pName = x.pkginfo.name
|
||||
|
|
@ -807,7 +812,7 @@ proc listInstalled(options: Options) =
|
|||
|
||||
type VersionAndPath = tuple[version: Version, path: string]
|
||||
|
||||
proc listPaths(options: Options) =
|
||||
proc listPaths(opt: Options) =
|
||||
## Loops over installing packages displaying their installed paths.
|
||||
##
|
||||
## 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.
|
||||
##
|
||||
## On success the proc returns normally.
|
||||
assert options.action.typ == actionPath
|
||||
assert(not options.action.packages.isNil)
|
||||
assert opt.action.typ == actionPath
|
||||
assert(not opt.action.packages.isNil)
|
||||
var errors = 0
|
||||
for name, version in options.action.packages.items:
|
||||
for name, version in opt.action.packages.items:
|
||||
var installed: seq[VersionAndPath] = @[]
|
||||
# There may be several, list all available ones and sort by version.
|
||||
for kind, path in walkDir(options.getPkgsDir):
|
||||
if kind != pcDir or not path.startsWith(options.getPkgsDir / name):
|
||||
for kind, path in walkDir(opt.getPkgsDir):
|
||||
if kind != pcDir or not path.startsWith(opt.getPkgsDir / name):
|
||||
continue
|
||||
|
||||
let
|
||||
nimScriptFile = path / name.addFileExt("nims")
|
||||
babelFile = path / name.addFileExt("babel")
|
||||
nimbleFile = path / name.addFileExt("nimble")
|
||||
hasSpec = nimbleFile.existsFile or babelFile.existsFile
|
||||
hasSpec = nimScriptFile.existsFile or
|
||||
nimbleFile.existsFile or babelFile.existsFile
|
||||
if hasSpec:
|
||||
var pkgInfo = getPkgInfo(path)
|
||||
var v: VersionAndPath
|
||||
v.version = newVersion(pkgInfo.version)
|
||||
v.path = options.getPkgsDir / (pkgInfo.name & '-' & pkgInfo.version)
|
||||
v.path = opt.getPkgsDir / (pkgInfo.name & '-' & pkgInfo.version)
|
||||
installed.add(v)
|
||||
else:
|
||||
echo "Warning: No .nimble file found for ", path
|
||||
|
|
@ -849,56 +856,64 @@ proc listPaths(options: Options) =
|
|||
raise newException(NimbleError,
|
||||
"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!")
|
||||
var
|
||||
pkgName, fName: string = ""
|
||||
outFile: File
|
||||
|
||||
if (options.action.projName != ""):
|
||||
pkgName = options.action.projName
|
||||
fName = pkgName & ".nimble"
|
||||
if opt.action.projName != "":
|
||||
pkgName = opt.action.projName
|
||||
fName = pkgName & NimsExt
|
||||
if (existsFile(os.getCurrentDir() / fName)):
|
||||
raise newException(NimbleError, "Already have a nimble file.")
|
||||
raise newException(NimbleError, "Already have a nimscript file.")
|
||||
else:
|
||||
echo("Enter a project name for this (blank to use working directory), " &
|
||||
"Ctrl-C to abort:")
|
||||
pkgName = readline(stdin)
|
||||
if (pkgName == ""):
|
||||
if pkgName == "":
|
||||
pkgName = os.getCurrentDir().splitPath.tail
|
||||
if (pkgName == ""):
|
||||
if pkgName == "":
|
||||
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
|
||||
|
||||
if (not existsFile(os.getCurrentDir() / fName) and
|
||||
open(f=outFile, filename = fName, mode = fmWrite)):
|
||||
outFile.writeln("[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)
|
||||
outFile.writeLine """# Package
|
||||
|
||||
version = "1.0.0"
|
||||
author = $1
|
||||
description = ""
|
||||
license = "MIT"
|
||||
|
||||
# Dependencies
|
||||
|
||||
requires "nim >= "0.11.2"
|
||||
""" % guessAuthor().escape()
|
||||
close(outFile)
|
||||
else:
|
||||
raise newException(NimbleError, "Unable to open file " & fName &
|
||||
" for writing: " & osErrorMsg(osLastError()))
|
||||
|
||||
proc uninstall(options: Options) =
|
||||
if options.action.packages.len == 0:
|
||||
proc uninstall(opt: Options) =
|
||||
if opt.action.packages.len == 0:
|
||||
raise newException(NimbleError,
|
||||
"Please specify the package(s) to uninstall.")
|
||||
|
||||
var pkgsToDelete: seq[PackageInfo] = @[]
|
||||
# Do some verification.
|
||||
for pkgTup in options.action.packages:
|
||||
for pkgTup in opt.action.packages:
|
||||
echo("Looking for ", pkgTup.name, " (", $pkgTup.ver, ")...")
|
||||
let installedPkgs = getInstalledPkgs(options.getPkgsDir())
|
||||
let installedPkgs = getInstalledPkgs(opt.getPkgsDir())
|
||||
var pkgList = findAllPkgs(installedPkgs, pkgTup)
|
||||
if pkgList.len == 0:
|
||||
raise newException(NimbleError, "Package not found")
|
||||
|
|
@ -908,7 +923,7 @@ proc uninstall(options: Options) =
|
|||
for pkg in pkgList:
|
||||
# Check whether any packages depend on the ones the user is trying to
|
||||
# uninstall.
|
||||
let thisPkgsDep = options.nimbleData["reverseDeps"]{pkg.name}{pkg.version}
|
||||
let thisPkgsDep = opt.nimbleData["reverseDeps"]{pkg.name}{pkg.version}
|
||||
if not thisPkgsDep.isNil:
|
||||
var reason = ""
|
||||
if thisPkgsDep.len == 1:
|
||||
|
|
@ -936,47 +951,50 @@ proc uninstall(options: Options) =
|
|||
pkgNames.add pkg.name & " (" & pkg.version & ")"
|
||||
|
||||
# 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?"):
|
||||
quit(QuitSuccess)
|
||||
|
||||
for pkg in pkgsToDelete:
|
||||
# If we reach this point then the package can be safely removed.
|
||||
removeRevDep(options, pkg)
|
||||
removePkgDir(options.getPkgsDir / (pkg.name & '-' & pkg.version), options)
|
||||
removeRevDep(opt, pkg)
|
||||
removePkgDir(opt.getPkgsDir / (pkg.name & '-' & pkg.version), opt)
|
||||
echo("Removed ", pkg.name, " (", $pkg.version, ")")
|
||||
|
||||
proc doAction(options: Options) =
|
||||
if not existsDir(options.getNimbleDir()):
|
||||
createDir(options.getNimbleDir())
|
||||
if not existsDir(options.getPkgsDir):
|
||||
createDir(options.getPkgsDir)
|
||||
proc getCommand: string = options.command
|
||||
|
||||
case options.action.typ
|
||||
of actionUpdate:
|
||||
update(options)
|
||||
of actionInstall:
|
||||
discard install(options.action.packages, options)
|
||||
of actionUninstall:
|
||||
uninstall(options)
|
||||
of actionSearch:
|
||||
search(options)
|
||||
of actionList:
|
||||
if options.queryInstalled: listInstalled(options)
|
||||
else: list(options)
|
||||
of actionPath:
|
||||
listPaths(options)
|
||||
of actionBuild:
|
||||
build(options)
|
||||
of actionCompile:
|
||||
compile(options)
|
||||
of actionInit:
|
||||
init(options)
|
||||
of actionPublish:
|
||||
proc doAction(opt: Options) =
|
||||
if not existsDir(opt.getNimbleDir()):
|
||||
createDir(opt.getNimbleDir())
|
||||
if not existsDir(opt.getPkgsDir):
|
||||
createDir(opt.getPkgsDir)
|
||||
|
||||
case getCommand().normalize
|
||||
of "udpate":
|
||||
update(opt)
|
||||
of "install":
|
||||
discard install(opt.action.packages, opt)
|
||||
of "uninstall", "remove", "delete", "del", "rm":
|
||||
uninstall(opt)
|
||||
of "search":
|
||||
search(opt)
|
||||
of "list":
|
||||
if opt.queryInstalled: listInstalled(opt)
|
||||
else: list(opt)
|
||||
of "path":
|
||||
listPaths(opt)
|
||||
of "build":
|
||||
build(opt)
|
||||
of "c", "compile", "js", "cpp", "cc":
|
||||
compile(opt)
|
||||
of "init":
|
||||
init(opt)
|
||||
of "publish":
|
||||
var pkgInfo = getPkgInfo(getCurrentDir())
|
||||
publish(pkgInfo)
|
||||
of actionNil:
|
||||
assert false
|
||||
of "nop": discard
|
||||
else:
|
||||
raise newException(NimbleError, "Unknown command: " & getCommand())
|
||||
|
||||
when isMainModule:
|
||||
when defined(release):
|
||||
|
|
|
|||
|
|
@ -1 +1,2 @@
|
|||
-d:ssl
|
||||
--path:"$lib/packages/docutils"
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@
|
|||
# recursive imports
|
||||
|
||||
import version
|
||||
export version.NimbleError
|
||||
|
||||
type
|
||||
NimbleError* = object of Exception
|
||||
BuildFailed* = object of NimbleError
|
||||
|
||||
PackageInfo* = object
|
||||
|
|
@ -27,4 +27,3 @@ type
|
|||
binDir*: string
|
||||
srcDir*: 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.
|
||||
# BSD License. Look at license.txt for more info.
|
||||
import parsecfg, json, streams, strutils, parseutils, os
|
||||
import version, tools, nimbletypes
|
||||
import version, tools, nimbletypes, nimscriptsupport
|
||||
|
||||
const
|
||||
NimsExt* = ".nims"
|
||||
|
||||
type
|
||||
Package* = object
|
||||
# Required fields in a package.
|
||||
|
|
@ -11,7 +15,7 @@ type
|
|||
downloadMethod*: string
|
||||
description*: string
|
||||
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
|
||||
dvcsTag*: string
|
||||
web*: string # Info url for humans.
|
||||
|
|
@ -19,9 +23,12 @@ type
|
|||
MetaData* = object
|
||||
url*: string
|
||||
|
||||
proc initPackageInfo(): PackageInfo =
|
||||
result.mypath = ""
|
||||
result.name = ""
|
||||
NimbleFile* = tuple[isNimScript: bool; file: string]
|
||||
|
||||
proc initPackageInfo(path: string): PackageInfo =
|
||||
result.mypath = path
|
||||
# reasonable default:
|
||||
result.name = path.splitFile.name
|
||||
result.version = ""
|
||||
result.author = ""
|
||||
result.description = ""
|
||||
|
|
@ -63,23 +70,6 @@ proc validatePackageInfo(pkgInfo: PackageInfo, path: string) =
|
|||
"Version may only consist of numbers and the '.' character " &
|
||||
"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] =
|
||||
## Returns ``s`` split by newline and comma characters.
|
||||
##
|
||||
|
|
@ -96,9 +86,7 @@ proc multiSplit(s: string): seq[string] =
|
|||
if len(result) < 1:
|
||||
return @[s]
|
||||
|
||||
proc readPackageInfo*(path: string): PackageInfo =
|
||||
result = initPackageInfo()
|
||||
result.mypath = path
|
||||
proc readPackageInfoFromNimble(path: string; result: var PackageInfo) =
|
||||
var fs = newFileStream(path, fmRead)
|
||||
if fs != nil:
|
||||
var p: CfgParser
|
||||
|
|
@ -160,7 +148,35 @@ proc readPackageInfo*(path: string): PackageInfo =
|
|||
close(p)
|
||||
else:
|
||||
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 =
|
||||
## Queries ``obj`` for the optional ``name`` string.
|
||||
|
|
@ -237,21 +253,34 @@ proc getPackageList*(packagesPath: string): seq[Package] =
|
|||
let pkg: Package = p.fromJson()
|
||||
result.add(pkg)
|
||||
|
||||
proc findNimbleFile*(dir: string): string =
|
||||
result = ""
|
||||
proc findNimbleFile*(dir: string; error: bool): NimbleFile =
|
||||
result = (false, "")
|
||||
var hits = 0
|
||||
for kind, path in walkDir(dir):
|
||||
if kind == pcFile and path.splitFile.ext in [".babel", ".nimble"]:
|
||||
if result != "":
|
||||
raise newException(NimbleError,
|
||||
"Only one .nimble file should be present in " & dir)
|
||||
result = path
|
||||
if kind == pcFile:
|
||||
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,
|
||||
"Only one .nimble file should be present in " & dir)
|
||||
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 =
|
||||
## Find the .nimble file in ``dir`` and parses it, returning a PackageInfo.
|
||||
let nimbleFile = findNimbleFile(dir)
|
||||
if nimbleFile == "":
|
||||
raise newException(NimbleError,
|
||||
"Specified directory does not contain a .nimble file.")
|
||||
let nimbleFile = findNimbleFile(dir, true)
|
||||
result = readPackageInfo(nimbleFile)
|
||||
|
||||
proc getInstalledPkgs*(libsDir: string):
|
||||
|
|
@ -262,13 +291,10 @@ proc getInstalledPkgs*(libsDir: string):
|
|||
result = @[]
|
||||
for kind, path in walkDir(libsDir):
|
||||
if kind == pcDir:
|
||||
let nimbleFile = findNimbleFile(path)
|
||||
if nimbleFile != "":
|
||||
let nimbleFile = findNimbleFile(path, false)
|
||||
if nimbleFile.file != "":
|
||||
let meta = readMetaData(path)
|
||||
result.add((readPackageInfo(nimbleFile), meta))
|
||||
else:
|
||||
# TODO: Abstract logging.
|
||||
echo("WARNING: No .nimble file found for ", path)
|
||||
result.add((readPackageInfo(nimbleFile, true), meta))
|
||||
|
||||
proc findPkg*(pkglist: seq[tuple[pkginfo: PackageInfo, meta: MetaData]],
|
||||
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.
|
||||
for pkg in pkglist:
|
||||
if pkg.pkginfo.name.normalize != dep.name.normalize and
|
||||
pkg.meta.url.normalize != dep.name.normalize: continue
|
||||
if cmpIgnoreStyle(pkg.pkginfo.name, dep.name) != 0 and
|
||||
cmpIgnoreStyle(pkg.meta.url, dep.name) != 0: continue
|
||||
if withinRange(newVersion(pkg.pkginfo.version), dep.ver):
|
||||
if not result or newVersion(r.version) < newVersion(pkg.pkginfo.version):
|
||||
r = pkg.pkginfo
|
||||
|
|
@ -294,8 +320,8 @@ proc findAllPkgs*(pkglist: seq[tuple[pkginfo: PackageInfo, meta: MetaData]],
|
|||
## packages if multiple are found.
|
||||
result = @[]
|
||||
for pkg in pkglist:
|
||||
if pkg.pkginfo.name.normalize != dep.name.normalize and
|
||||
pkg.meta.url.normalize != dep.name.normalize: continue
|
||||
if cmpIgnoreStyle(pkg.pkginfo.name, dep.name) != 0 and
|
||||
cmpIgnoreStyle(pkg.meta.url, dep.name) != 0: continue
|
||||
if withinRange(newVersion(pkg.pkginfo.version), dep.ver):
|
||||
result.add pkg.pkginfo
|
||||
|
||||
|
|
@ -314,22 +340,6 @@ proc getOutputDir*(pkgInfo: PackageInfo, bin: string): string =
|
|||
else:
|
||||
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) =
|
||||
echo(pkg.name & ":")
|
||||
echo(" url: " & pkg.url & " (" & pkg.downloadMethod & ")")
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ type
|
|||
PkgTuple* = tuple[name: string, ver: VersionRange]
|
||||
|
||||
ParseVersionError* = object of ValueError
|
||||
NimbleError* = object of Exception
|
||||
|
||||
proc newVersion*(ver: string): Version = return Version(ver)
|
||||
proc newSpecial*(spe: string): Special = return Special(spe)
|
||||
|
|
@ -198,6 +199,24 @@ proc parseVersionRange*(s: string): VersionRange =
|
|||
"Unexpected char in version range: " & s[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 =
|
||||
case verRange.kind
|
||||
of verLater:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue