Moved Nimble-specific Nimscript definitions to nimscriptapi module.

* Moved package info reading procedures to a packageparser module. This is to prevent recu
rsive dependencies between nimscriptsupport and packageinfo modules.
* Passed the Options object to all procedures which read package info (necessary for nimscriptsupport module, to find the path of the nimscriptapi module)
* Introduced an ``isInstalled`` field to the ``PackageInfo`` type. This is a bug fix for g
etRealDir: it no longer uses the ``src`` field in the path it returns for installed packag
es' PackageInfo objects.
* Improved error reporting from NimScript evaluator.
* Renamed compiler/options import to ``compiler_options`` in ``nimscriptsupport`` module.
* Backward compatibility for .babel packages in getNameVersion proc.
* Introduced a getInstalledPkgsMin procedure which does not read package info, but only pr
ovides minimal info instead.
This commit is contained in:
Dominik Picheta 2015-12-28 16:33:34 +00:00
commit ca99ad7d21
9 changed files with 426 additions and 300 deletions

View file

@ -8,7 +8,7 @@ from sequtils import toSeq
import nimblepkg/packageinfo, nimblepkg/version, nimblepkg/tools, import nimblepkg/packageinfo, nimblepkg/version, nimblepkg/tools,
nimblepkg/download, nimblepkg/config, nimblepkg/nimbletypes, nimblepkg/download, nimblepkg/config, nimblepkg/nimbletypes,
nimblepkg/publish, nimblepkg/options nimblepkg/publish, nimblepkg/options, nimblepkg/packageparser
import nimblepkg/nimscriptsupport import nimblepkg/nimscriptsupport
@ -227,7 +227,7 @@ proc processDeps(pkginfo: PackageInfo, options: Options): seq[string] =
## ##
## 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(options.getPkgsDir(), options)
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":
@ -328,7 +328,7 @@ proc installFromDir(dir: string, latest: bool, options: Options,
## to the packages this package depends on. ## to the packages this package depends on.
## The return value of this function is used by ## The return value of this function is used by
## ``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, options)
let realDir = pkgInfo.getRealDir() let realDir = pkgInfo.getRealDir()
let binDir = options.getBinDir() let binDir = options.getBinDir()
let pkgsDir = options.getPkgsDir() let pkgsDir = options.getPkgsDir()
@ -440,7 +440,8 @@ proc getNimbleTempDir(): string =
result.add($getpid()) result.add($getpid())
proc downloadPkg(url: string, verRange: VersionRange, proc downloadPkg(url: string, verRange: VersionRange,
downMethod: DownloadMethod): (string, VersionRange) = downMethod: DownloadMethod,
options: Options): (string, VersionRange) =
## Downloads the repository as specified by ``url`` and ``verRange`` using ## Downloads the repository as specified by ``url`` and ``verRange`` using
## the download method specified. ## the download method specified.
## ##
@ -449,7 +450,10 @@ proc downloadPkg(url: string, verRange: VersionRange,
let downloadDir = (getNimbleTempDir() / getDownloadDirName(url, verRange)) let downloadDir = (getNimbleTempDir() / getDownloadDirName(url, verRange))
createDir(downloadDir) createDir(downloadDir)
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, options)
)
proc getDownloadInfo*(pv: PkgTuple, options: Options, proc getDownloadInfo*(pv: PkgTuple, options: Options,
doPrompt: bool): (DownloadMethod, string) = doPrompt: bool): (DownloadMethod, string) =
@ -488,7 +492,8 @@ proc install(packages: seq[PkgTuple],
# 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, options, doPrompt)
let (downloadDir, downloadVersion) = downloadPkg(url, pv.ver, meth) let (downloadDir, downloadVersion) =
downloadPkg(url, pv.ver, meth, options)
try: try:
result = installFromDir(downloadDir, false, options, url) result = installFromDir(downloadDir, false, options, url)
except BuildFailed: except BuildFailed:
@ -512,13 +517,13 @@ proc install(packages: seq[PkgTuple],
raise raise
proc build(options: Options) = proc build(options: Options) =
var pkgInfo = getPkgInfo(getCurrentDir()) var pkgInfo = getPkgInfo(getCurrentDir(), options)
nimScriptHint(pkgInfo) nimScriptHint(pkgInfo)
let paths = processDeps(pkginfo, options) let paths = processDeps(pkginfo, options)
buildFromDir(pkgInfo, paths, false) buildFromDir(pkgInfo, paths, false)
proc compile(options: Options) = proc compile(options: Options) =
var pkgInfo = getPkgInfo(getCurrentDir()) var pkgInfo = getPkgInfo(getCurrentDir(), options)
nimScriptHint(pkgInfo) nimScriptHint(pkgInfo)
let paths = processDeps(pkginfo, options) let paths = processDeps(pkginfo, options)
let realDir = pkgInfo.getRealDir() let realDir = pkgInfo.getRealDir()
@ -587,7 +592,7 @@ proc list(options: Options) =
proc listInstalled(options: Options) = proc listInstalled(options: Options) =
var h = initTable[string, seq[string]]() var h = initTable[string, seq[string]]()
let pkgs = getInstalledPkgs(options.getPkgsDir()) let pkgs = getInstalledPkgs(options.getPkgsDir(), options)
for x in pkgs.items(): for x in pkgs.items():
let let
pName = x.pkginfo.name pName = x.pkginfo.name
@ -627,7 +632,7 @@ proc listPaths(options: Options) =
hasSpec = nimScriptFile.existsFile or hasSpec = nimScriptFile.existsFile or
nimbleFile.existsFile or babelFile.existsFile nimbleFile.existsFile or babelFile.existsFile
if hasSpec: if hasSpec:
var pkgInfo = getPkgInfo(path) var pkgInfo = getPkgInfo(path, options)
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 = options.getPkgsDir / (pkgInfo.name & '-' & pkgInfo.version)
@ -654,8 +659,8 @@ proc join(x: seq[PkgTuple]; y: string): string =
proc dump(options: Options) = proc dump(options: Options) =
let proj = addFileExt(options.action.projName, "nimble") let proj = addFileExt(options.action.projName, "nimble")
let p = if fileExists(proj): readPackageInfo(proj) let p = if fileExists(proj): readPackageInfo(proj, options)
else: getPkgInfo(os.getCurrentDir()) else: getPkgInfo(os.getCurrentDir(), options)
echo "name: ", p.name.escape echo "name: ", p.name.escape
echo "version: ", p.version.escape echo "version: ", p.version.escape
echo "author: ", p.author.escape echo "author: ", p.author.escape
@ -755,7 +760,7 @@ proc uninstall(options: Options) =
# Do some verification. # Do some verification.
for pkgTup in options.action.packages: for pkgTup in options.action.packages:
echo("Looking for ", pkgTup.name, " (", $pkgTup.ver, ")...") echo("Looking for ", pkgTup.name, " (", $pkgTup.ver, ")...")
let installedPkgs = getInstalledPkgs(options.getPkgsDir()) let installedPkgs = getInstalledPkgs(options.getPkgsDir(), options)
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")
@ -805,7 +810,7 @@ proc uninstall(options: Options) =
proc listTasks(options: Options) = proc listTasks(options: Options) =
let nimbleFile = findNimbleFile(getCurrentDir(), true) let nimbleFile = findNimbleFile(getCurrentDir(), true)
nimscriptsupport.listTasks(nimbleFile) nimscriptsupport.listTasks(nimbleFile, options)
proc doAction(options: Options) = proc doAction(options: Options) =
if not existsDir(options.getNimbleDir()): if not existsDir(options.getNimbleDir()):
@ -836,7 +841,7 @@ proc doAction(options: Options) =
of actionInit: of actionInit:
init(options) init(options)
of actionPublish: of actionPublish:
var pkgInfo = getPkgInfo(getCurrentDir()) var pkgInfo = getPkgInfo(getCurrentDir(), options)
publish(pkgInfo) publish(pkgInfo)
of actionDump: of actionDump:
dump(options) dump(options)
@ -849,10 +854,11 @@ proc doAction(options: Options) =
of actionCustom: of actionCustom:
# Custom command. Attempt to call a NimScript task. # Custom command. Attempt to call a NimScript task.
let nimbleFile = findNimbleFile(getCurrentDir(), true) let nimbleFile = findNimbleFile(getCurrentDir(), true)
if not nimbleFile.isNimScript(): ## TODO: Optimise this, there are two calls to readPackageInfo here.
if not nimbleFile.isNimScript(options):
writeHelp() writeHelp()
let execResult = execTask(nimbleFile, options.action.command) let execResult = execTask(nimbleFile, options.action.command, options)
if not execResult.success: if not execResult.success:
echo("FAILURE: Could not find task ", options.action.command, " in ", echo("FAILURE: Could not find task ", options.action.command, " in ",
nimbleFile) nimbleFile)

View file

@ -3,7 +3,7 @@
import parseutils, os, osproc, strutils, tables, pegs import parseutils, os, osproc, strutils, tables, pegs
import packageinfo, version, tools, nimbletypes import packageinfo, packageparser, version, tools, nimbletypes, options
type type
DownloadMethod* {.pure.} = enum DownloadMethod* {.pure.} = enum
@ -136,7 +136,7 @@ proc isURL*(name: string): bool =
name.startsWith(peg" @'://' ") name.startsWith(peg" @'://' ")
proc doDownload*(url: string, downloadDir: string, verRange: VersionRange, proc doDownload*(url: string, downloadDir: string, verRange: VersionRange,
downMethod: DownloadMethod): VersionRange = downMethod: DownloadMethod, options: Options): VersionRange =
## Downloads the repository specified by ``url`` using the specified download ## Downloads the repository specified by ``url`` using the specified download
## method. ## method.
## ##
@ -161,7 +161,7 @@ proc doDownload*(url: string, downloadDir: string, verRange: VersionRange,
proc verifyClone() = proc verifyClone() =
## Makes sure that the downloaded package's version satisfies the requested ## Makes sure that the downloaded package's version satisfies the requested
## version range. ## version range.
let pkginfo = getPkgInfo(downloadDir) let pkginfo = getPkgInfo(downloadDir, options)
if pkginfo.version.newVersion notin verRange: if pkginfo.version.newVersion notin verRange:
raise newException(NimbleError, raise newException(NimbleError,
"Downloaded package's version does not satisfy requested version " & "Downloaded package's version does not satisfy requested version " &

View file

@ -13,6 +13,7 @@ type
mypath*: string ## The path of this .nimble file mypath*: string ## The path of this .nimble file
isNimScript*: bool ## Determines if this pkg info was read from a nims file isNimScript*: bool ## Determines if this pkg info was read from a nims file
isMinimal*: bool isMinimal*: bool
isInstalled*: bool ## Determines if the pkg this info belongs to is installed
name*: string name*: string
version*: string version*: string
author*: string author*: string

View file

@ -0,0 +1,30 @@
# Copyright (C) Dominik Picheta. All rights reserved.
# BSD License. Look at license.txt for more info.
## This module is implicitly imported in NimScript .nimble files.
var
packageName* = "" ## Set this to the package name. It
## is usually not required to do that, nims' filename is
## the default.
version*: string ## The package's version.
author*: string ## The package's author.
description*: string ## The package's description.
license*: string ## The package's license.
srcdir*: string ## The package's source directory.
binDir*: string ## The package's binary directory.
backend*: string ## The package's backend.
skipDirs*, skipFiles*, skipExt*, installDirs*, installFiles*,
installExt*, bin*: seq[string] = @[] ## Nimble metadata.
requiresData*: seq[string] = @[] ## The package's dependencies.
proc requires*(deps: varargs[string]) =
## Call this to set the list of requirements of your Nimble
## package.
for d in deps: requiresData.add(d)
template builtin = discard
proc getPkgDir*(): string =
builtin

View file

@ -6,15 +6,16 @@
import import
compiler/ast, compiler/modules, compiler/passes, compiler/passaux, compiler/ast, compiler/modules, compiler/passes, compiler/passaux,
compiler/condsyms, compiler/options, compiler/sem, compiler/semdata, compiler/condsyms, compiler/sem, compiler/semdata,
compiler/llstream, compiler/vm, compiler/vmdef, compiler/commands, compiler/llstream, compiler/vm, compiler/vmdef, compiler/commands,
compiler/msgs, compiler/magicsys, compiler/lists compiler/msgs, compiler/magicsys, compiler/lists
from compiler/scriptconfig import setupVM from compiler/scriptconfig import setupVM
from compiler/idents import getIdent from compiler/idents import getIdent
from compiler/astalgo import strTableGet from compiler/astalgo import strTableGet
import compiler/options as compiler_options
import nimbletypes, version import nimbletypes, version, options, packageinfo
import os, strutils, strtabs, times, osproc import os, strutils, strtabs, times, osproc
type type
@ -33,27 +34,27 @@ proc raiseVariableError(ident, typ: string) {.noinline.} =
proc isStrLit(n: PNode): bool = n.kind in {nkStrLit..nkTripleStrLit} proc isStrLit(n: PNode): bool = n.kind in {nkStrLit..nkTripleStrLit}
proc getGlobal(ident: string): string = proc getGlobal(ident: PSym): string =
let n = vm.globalCtx.getGlobalValue(getSysSym ident) let n = vm.globalCtx.getGlobalValue(ident)
if n.isStrLit: if n.isStrLit:
result = if n.strVal.isNil: "" else: n.strVal result = if n.strVal.isNil: "" else: n.strVal
else: else:
raiseVariableError(ident, "string") raiseVariableError(ident.name.s, "string")
proc getGlobalAsSeq(ident: string): seq[string] = proc getGlobalAsSeq(ident: PSym): seq[string] =
let n = vm.globalCtx.getGlobalValue(getSysSym ident) let n = vm.globalCtx.getGlobalValue(ident)
result = @[] result = @[]
if n.kind == nkBracket: if n.kind == nkBracket:
for x in n: for x in n:
if x.isStrLit: if x.isStrLit:
result.add x.strVal result.add x.strVal
else: else:
raiseVariableError(ident, "seq[string]") raiseVariableError(ident.name.s, "seq[string]")
else: else:
raiseVariableError(ident, "seq[string]") raiseVariableError(ident.name.s, "seq[string]")
proc extractRequires(result: var seq[PkgTuple]) = proc extractRequires(ident: PSym, result: var seq[PkgTuple]) =
let n = vm.globalCtx.getGlobalValue(getSysSym "requiresData") let n = vm.globalCtx.getGlobalValue(ident)
if n.kind == nkBracket: if n.kind == nkBracket:
for x in n: for x in n:
if x.kind == nkPar and x.len == 2 and x[0].isStrLit and x[1].isStrLit: if x.kind == nkPar and x.len == 2 and x[0].isStrLit and x[1].isStrLit:
@ -140,13 +141,13 @@ proc setupVM(module: PSym; scriptName: string,
cbconf thisDir: cbconf thisDir:
setResult(a, vthisDir) setResult(a, vthisDir)
cbconf put: cbconf put:
options.setConfigVar(getString(a, 0), getString(a, 1)) compiler_options.setConfigVar(getString(a, 0), getString(a, 1))
cbconf get: cbconf get:
setResult(a, options.getConfigVar(a.getString 0)) setResult(a, compiler_options.getConfigVar(a.getString 0))
cbconf exists: cbconf exists:
setResult(a, options.existsConfigVar(a.getString 0)) setResult(a, compiler_options.existsConfigVar(a.getString 0))
cbconf nimcacheDir: cbconf nimcacheDir:
setResult(a, options.getNimcacheDir()) setResult(a, compiler_options.getNimcacheDir())
cbconf paramStr: cbconf paramStr:
setResult(a, os.paramStr(int a.getInt 0)) setResult(a, os.paramStr(int a.getInt 0))
cbconf paramCount: cbconf paramCount:
@ -156,7 +157,7 @@ proc setupVM(module: PSym; scriptName: string,
cbconf cmpIgnoreCase: cbconf cmpIgnoreCase:
setResult(a, strutils.cmpIgnoreCase(a.getString 0, a.getString 1)) setResult(a, strutils.cmpIgnoreCase(a.getString 0, a.getString 1))
cbconf setCommand: cbconf setCommand:
options.command = a.getString 0 compiler_options.command = a.getString 0
let arg = a.getString 1 let arg = a.getString 1
if arg.len > 0: if arg.len > 0:
gProjectName = arg gProjectName = arg
@ -165,15 +166,40 @@ proc setupVM(module: PSym; scriptName: string,
except OSError: except OSError:
gProjectFull = gProjectName gProjectFull = gProjectName
cbconf getCommand: cbconf getCommand:
setResult(a, options.command) setResult(a, compiler_options.command)
cbconf switch: cbconf switch:
if not flags.isNil: if not flags.isNil:
flags[a.getString 0] = a.getString 1 flags[a.getString 0] = a.getString 1
proc execScript(scriptName: string, flags: StringTableRef) = proc findNimscriptApi(options: Options): string =
## Returns the directory containing ``nimscriptapi.nim``
var inPath = false
let pkgs = getInstalledPkgsMin(options.getPkgsDir(), options)
var pkg: PackageInfo
if pkgs.findPkg(("nimble", newVRAny()), pkg):
let pkgDir = pkg.getRealDir()
if fileExists(pkgDir / "nimblepkg" / "nimscriptapi.nim"):
result = pkgDir
inPath = true
if not inPath:
# Try finding it in exe's path
if fileExists(getAppDir() / "nimblepkg" / "nimscriptapi.nim"):
result = getAppDir()
inPath = true
if not inPath:
raise newException(NimbleError, "Cannot find nimscriptapi.nim")
proc execScript(scriptName: string, flags: StringTableRef, options: Options) =
## Executes the specified script. ## Executes the specified script.
## ##
## No clean up is performed and must be done manually! ## No clean up is performed and must be done manually!
if "nimblepkg/nimscriptapi" notin compiler_options.implicitIncludes:
compiler_options.implicitIncludes.add("nimblepkg/nimscriptapi")
# Ensure that "nimblepkg/nimscriptapi" is in the PATH.
let nimscriptApiPath = findNimscriptApi(options)
appendStr(searchPaths, nimscriptApiPath)
setDefaultLibpath() setDefaultLibpath()
passes.gIncludeFile = includeModule passes.gIncludeFile = includeModule
passes.gImportModule = importModule passes.gImportModule = importModule
@ -185,19 +211,28 @@ proc execScript(scriptName: string, flags: StringTableRef) =
registerPass(semPass) registerPass(semPass)
registerPass(evalPass) registerPass(evalPass)
appendStr(searchPaths, options.libpath) appendStr(searchPaths, compiler_options.libpath)
var m = makeModule(scriptName) var m = makeModule(scriptName)
incl(m.flags, sfMainModule) incl(m.flags, sfMainModule)
vm.globalCtx = setupVM(m, scriptName, flags) vm.globalCtx = setupVM(m, scriptName, flags)
# Setup builtins defined in nimscriptapi.nim
template cbApi(name, body) {.dirty.} =
vm.globalCtx.registerCallback "stdlib.system." & astToStr(name),
proc (a: VmArgs) =
body
# TODO: This doesn't work.
cbApi getPkgDir:
setResult(a, "FOOBAR")
compileSystemModule() compileSystemModule()
processModule(m, llStreamOpen(scriptName, fmRead), nil) processModule(m, llStreamOpen(scriptName, fmRead), nil)
proc cleanup() = proc cleanup() =
# ensure everything can be called again: # ensure everything can be called again:
options.gProjectName = "" compiler_options.gProjectName = ""
options.command = "" compiler_options.command = ""
resetAllModulesHard() resetAllModulesHard()
clearPasses() clearPasses()
msgs.gErrorMax = 1 msgs.gErrorMax = 1
@ -205,7 +240,8 @@ proc cleanup() =
vm.globalCtx = nil vm.globalCtx = nil
initDefines() initDefines()
proc readPackageInfoFromNims*(scriptName: string; result: var PackageInfo) = proc readPackageInfoFromNims*(scriptName: string, options: Options,
result: var PackageInfo) =
## Executes the `scriptName` nimscript file. Reads the package information ## Executes the `scriptName` nimscript file. Reads the package information
## that it populates. ## that it populates.
@ -217,20 +253,35 @@ proc readPackageInfoFromNims*(scriptName: string; result: var PackageInfo) =
# The error counter is incremented after the writeLnHook is invoked. # The error counter is incremented after the writeLnHook is invoked.
if msgs.gErrorCounter > 0: if msgs.gErrorCounter > 0:
raise newException(NimbleError, previousMsg) raise newException(NimbleError, previousMsg)
elif previousMsg.len > 0:
echo(previousMsg)
if output.normalize.startsWith("error"):
raise newException(NimbleError, output)
previousMsg = output previousMsg = output
compiler_options.command = internalCmd
# Execute the nimscript file. # Execute the nimscript file.
execScript(scriptName, nil) execScript(scriptName, nil, options)
# Extract all the necessary fields populated by the nimscript file. # Extract all the necessary fields populated by the nimscript file.
proc getSym(thisModule: PSym, ident: string): PSym =
thisModule.tab.strTableGet(getIdent(ident))
template trivialField(field) = template trivialField(field) =
result.field = getGlobal(astToStr field) result.field = getGlobal(getSym(thisModule, astToStr field))
template trivialFieldSeq(field) = template trivialFieldSeq(field) =
result.field.add getGlobalAsSeq(astToStr field) result.field.add getGlobalAsSeq(getSym(thisModule, astToStr field))
# Grab the module Sym for .nimble file (nimscriptapi is included in it).
let idx = fileInfoIdx(scriptName)
let thisModule = getModule(idx)
assert(not thisModule.isNil)
assert thisModule.kind == skModule
# keep reasonable default: # keep reasonable default:
let name = getGlobal"packageName" let name = getGlobal(thisModule.tab.strTableGet(getIdent"packageName"))
if name.len > 0: result.name = name if name.len > 0: result.name = name
trivialField version trivialField version
@ -246,13 +297,13 @@ proc readPackageInfoFromNims*(scriptName: string; result: var PackageInfo) =
trivialFieldSeq installFiles trivialFieldSeq installFiles
trivialFieldSeq installExt trivialFieldSeq installExt
extractRequires result.requires extractRequires(getSym(thisModule, "requiresData"), result.requires)
let binSeq = getGlobalAsSeq("bin") let binSeq = getGlobalAsSeq(getSym(thisModule, "bin"))
for i in binSeq: for i in binSeq:
result.bin.add(i.addFileExt(ExeExt)) result.bin.add(i.addFileExt(ExeExt))
let backend = getGlobal("backend") let backend = getGlobal(getSym(thisModule, "backend"))
if backend.len == 0: if backend.len == 0:
result.backend = "c" result.backend = "c"
elif cmpIgnoreStyle(backend, "javascript") == 0: elif cmpIgnoreStyle(backend, "javascript") == 0:
@ -262,19 +313,22 @@ proc readPackageInfoFromNims*(scriptName: string; result: var PackageInfo) =
cleanup() cleanup()
proc execTask*(scriptName, taskName: string): ExecutionResult = proc execTask*(scriptName, taskName: string,
options: Options): ExecutionResult =
## Executes the specified task in the specified script. ## Executes the specified task in the specified script.
## ##
## `scriptName` should be a filename pointing to the nimscript file. ## `scriptName` should be a filename pointing to the nimscript file.
result.success = true result.success = true
result.flags = newStringTable() result.flags = newStringTable()
options.command = internalCmd compiler_options.command = internalCmd
echo("Executing task ", taskName, " in ", scriptName) echo("Executing task ", taskName, " in ", scriptName)
execScript(scriptName, result.flags) execScript(scriptName, result.flags, options)
# Explicitly execute the task procedure, instead of relying on hack. # Explicitly execute the task procedure, instead of relying on hack.
assert vm.globalCtx.module.kind == skModule let idx = fileInfoIdx(scriptName)
let prc = vm.globalCtx.module.tab.strTableGet(getIdent(taskName & "Task")) let thisModule = getModule(idx)
assert thisModule.kind == skModule
let prc = thisModule.tab.strTableGet(getIdent(taskName & "Task"))
if prc.isNil: if prc.isNil:
# Procedure not defined in the NimScript module. # Procedure not defined in the NimScript module.
result.success = false result.success = false
@ -282,27 +336,27 @@ proc execTask*(scriptName, taskName: string): ExecutionResult =
discard vm.globalCtx.execProc(prc, []) discard vm.globalCtx.execProc(prc, [])
# Read the command, arguments and flags set by the executed task. # Read the command, arguments and flags set by the executed task.
result.command = options.command result.command = compiler_options.command
result.arguments = @[] result.arguments = @[]
for arg in options.gProjectName.split(): for arg in compiler_options.gProjectName.split():
result.arguments.add(arg) result.arguments.add(arg)
cleanup() cleanup()
proc getNimScriptCommand(): string = proc getNimScriptCommand(): string =
options.command compiler_options.command
proc setNimScriptCommand(command: string) = proc setNimScriptCommand(command: string) =
options.command = command compiler_options.command = command
proc hasTaskRequestedCommand*(execResult: ExecutionResult): bool = proc hasTaskRequestedCommand*(execResult: ExecutionResult): bool =
## Determines whether the last executed task used ``setCommand`` ## Determines whether the last executed task used ``setCommand``
return execResult.command != internalCmd return execResult.command != internalCmd
proc listTasks*(scriptName: string) = proc listTasks*(scriptName: string, options: Options) =
setNimScriptCommand("help") setNimScriptCommand("help")
execScript(scriptName, nil) execScript(scriptName, nil, options)
# TODO: Make the 'task' template generate explicit data structure containing # TODO: Make the 'task' template generate explicit data structure containing
# all the task names + descriptions. # all the task names + descriptions.
cleanup() cleanup()

View file

@ -3,7 +3,7 @@
import json, strutils, os, parseopt, strtabs import json, strutils, os, parseopt, strtabs
import nimblepkg/config, nimblepkg/version, nimblepkg/nimscriptsupport, import nimblepkg/config, nimblepkg/version,
nimblepkg/tools nimblepkg/tools
type type

View file

@ -1,10 +1,7 @@
# 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, nimscriptsupport import version, tools, nimbletypes, options
when not declared(system.map):
from sequtils import map
type type
Package* = object Package* = object
@ -23,12 +20,7 @@ type
MetaData* = object MetaData* = object
url*: string url*: string
NimbleFile* = string proc initPackageInfo*(path: string): PackageInfo =
ValidationError* = object of NimbleError
warnInstalled*: bool # Determines whether to show a warning for installed pkgs
proc initPackageInfo(path: string): PackageInfo =
result.mypath = path result.mypath = path
# reasonable default: # reasonable default:
result.name = path.splitFile.name result.name = path.splitFile.name
@ -48,37 +40,6 @@ proc initPackageInfo(path: string): PackageInfo =
result.binDir = "" result.binDir = ""
result.backend = "c" result.backend = "c"
proc newValidationError(msg: string, warnInstalled: bool): ref ValidationError =
result = newException(ValidationError, msg)
result.warnInstalled = warnInstalled
proc validatePackageName*(name: string) =
## Raises an error if specified package name contains invalid characters.
##
## A valid package name is one which is a valid nim module name. So only
## underscores, letters and numbers allowed.
if name.len == 0: return
if name[0] in {'0'..'9'}:
raise newValidationError(name &
"\"$1\" is an invalid package name: cannot begin with $2" %
[name, $name[0]], true)
var prevWasUnderscore = false
for c in name:
case c
of '_':
if prevWasUnderscore:
raise newValidationError(
"$1 is an invalid package name: cannot contain \"__\"" % name, true)
prevWasUnderscore = true
of AllChars - IdentChars:
raise newValidationError(
"$1 is an invalid package name: cannot contain '$2'" % [name, $c],
true)
else:
prevWasUnderscore = false
proc toValidPackageName*(name: string): string = proc toValidPackageName*(name: string): string =
result = "" result = ""
for c in name: for c in name:
@ -88,128 +49,6 @@ proc toValidPackageName*(name: string): string =
of AllChars - IdentChars - {'-'}: discard of AllChars - IdentChars - {'-'}: discard
else: result.add(c) else: result.add(c)
proc validateVersion*(ver: string) =
for c in ver:
if c notin ({'.'} + Digits):
raise newValidationError(
"Version may only consist of numbers and the '.' character " &
"but found '" & c & "'.", false)
proc validatePackageInfo(pkgInfo: PackageInfo, path: string) =
if pkgInfo.name == "":
raise newValidationError("Incorrect .nimble file: " & path &
" does not contain a name field.", false)
if pkgInfo.name.normalize != path.splitFile.name.normalize:
raise newValidationError(
"The .nimble file name must match name specified inside " & path, true)
if pkgInfo.version == "":
raise newValidationError("Incorrect .nimble file: " & path &
" does not contain a version field.", false)
if not pkgInfo.isMinimal:
if pkgInfo.author == "":
raise newValidationError("Incorrect .nimble file: " & path &
" does not contain an author field.", false)
if pkgInfo.description == "":
raise newValidationError("Incorrect .nimble file: " & path &
" does not contain a description field.", false)
if pkgInfo.license == "":
raise newValidationError("Incorrect .nimble file: " & path &
" does not contain a license field.", false)
if pkgInfo.backend notin ["c", "cc", "objc", "cpp", "js"]:
raise newValidationError("'" & pkgInfo.backend &
"' is an invalid backend.", false)
validateVersion(pkgInfo.version)
proc nimScriptHint*(pkgInfo: PackageInfo) =
if not pkgInfo.isNimScript:
# TODO: Turn this into a warning.
# TODO: Add a URL explaining more.
echo("NOTE: The .nimble file for this project could make use of " &
"additional features, if converted into the new NimScript format.")
proc multiSplit(s: string): seq[string] =
## Returns ``s`` split by newline and comma characters.
##
## Before returning, all individual entries are stripped of whitespace and
## also empty entries are purged from the list. If after all the cleanups are
## done no entries are found in the list, the proc returns a sequence with
## the original string as the only entry.
result = split(s, {char(0x0A), char(0x0D), ','})
map(result, proc(x: var string) = x = x.strip())
for i in countdown(result.len()-1, 0):
if len(result[i]) < 1:
result.del(i)
# Huh, nothing to return? Return given input.
if len(result) < 1:
return @[s]
proc readPackageInfoFromNimble(path: string; result: var PackageInfo) =
var fs = newFileStream(path, fmRead)
if fs != nil:
var p: CfgParser
open(p, fs, path)
var currentSection = ""
while true:
var ev = next(p)
case ev.kind
of cfgEof:
break
of cfgSectionStart:
currentSection = ev.section
of cfgKeyValuePair:
case currentSection.normalize
of "package":
case ev.key.normalize
of "name": result.name = ev.value
of "version": result.version = ev.value
of "author": result.author = ev.value
of "description": result.description = ev.value
of "license": result.license = ev.value
of "srcdir": result.srcDir = ev.value
of "bindir": result.binDir = ev.value
of "skipdirs":
result.skipDirs.add(ev.value.multiSplit)
of "skipfiles":
result.skipFiles.add(ev.value.multiSplit)
of "skipext":
result.skipExt.add(ev.value.multiSplit)
of "installdirs":
result.installDirs.add(ev.value.multiSplit)
of "installfiles":
result.installFiles.add(ev.value.multiSplit)
of "installext":
result.installExt.add(ev.value.multiSplit)
of "bin":
for i in ev.value.multiSplit:
result.bin.add(i.addFileExt(ExeExt))
of "backend":
result.backend = ev.value.toLower()
case result.backend.normalize
of "javascript": result.backend = "js"
else: discard
else:
raise newException(NimbleError, "Invalid field: " & ev.key)
of "deps", "dependencies":
case ev.key.normalize
of "requires":
for v in ev.value.multiSplit:
result.requires.add(parseRequires(v.strip))
else:
raise newException(NimbleError, "Invalid field: " & ev.key)
else: raise newException(NimbleError,
"Invalid section: " & currentSection)
of cfgOption: raise newException(NimbleError,
"Invalid package info, should not contain --" & ev.value)
of cfgError:
raise newException(NimbleError, "Error parsing .nimble file: " & ev.msg)
close(p)
else:
raise newException(ValueError, "Cannot open package info: " & path)
proc getNameVersion*(pkgpath: string): tuple[name, version: string] = proc getNameVersion*(pkgpath: string): tuple[name, version: string] =
## Splits ``pkgpath`` in the format ``/home/user/.nimble/pkgs/package-0.1`` ## Splits ``pkgpath`` in the format ``/home/user/.nimble/pkgs/package-0.1``
## into ``(packagea, 0.1)`` ## into ``(packagea, 0.1)``
@ -217,7 +56,7 @@ proc getNameVersion*(pkgpath: string): tuple[name, version: string] =
## Also works for file paths like: ## Also works for file paths like:
## ``/home/user/.nimble/pkgs/package-0.1/package.nimble`` ## ``/home/user/.nimble/pkgs/package-0.1/package.nimble``
if pkgPath.splitFile.ext == ".nimble": if pkgPath.splitFile.ext == ".nimble" or pkgPath.splitFile.ext == ".babel":
return getNameVersion(pkgPath.splitPath.head) return getNameVersion(pkgPath.splitPath.head)
result.name = "" result.name = ""
@ -233,51 +72,6 @@ proc getNameVersion*(pkgpath: string): tuple[name, version: string] =
result.version = tail[i+1 .. tail.len-1] result.version = tail[i+1 .. tail.len-1]
break break
proc readPackageInfo*(nf: NimbleFile; onlyMinimalInfo=false): PackageInfo =
## Reads package info from the specified Nimble file.
##
## Attempts to read it using the "old" Nimble ini format first, if that
## fails attempts to evaluate it as a nimscript file.
##
## If both fail then returns an error.
##
## When ``onlyMinimalInfo`` is true, only the `name` and `version` fields are
## populated. The isNimScript field can also be relied on.
result = initPackageInfo(nf)
validatePackageName(nf.splitFile.name)
var success = false
var iniError: ref NimbleError
# Attempt ini-format first.
try:
readPackageInfoFromNimble(nf, result)
success = true
result.isNimScript = false
except NimbleError:
iniError = (ref NimbleError)(getCurrentException())
if not success:
if onlyMinimalInfo:
let tmp = getNameVersion(nf)
result.name = tmp.name
result.version = tmp.version
result.isNimScript = true
result.isMinimal = true
else:
try:
readPackageInfoFromNims(nf, result)
result.isNimScript = true
except NimbleError:
let msg = "Could not read package info file in " & nf & ";\n" &
" Reading as ini file failed with: \n" &
" " & iniError.msg & ".\n" &
" Evaluating as NimScript file failed with: \n" &
" " & getCurrentExceptionMsg() & "."
raise newException(NimbleError, msg)
validatePackageInfo(result, nf)
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.
## ##
@ -353,7 +147,7 @@ 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; error: bool): NimbleFile = proc findNimbleFile*(dir: string; error: bool): string =
result = "" result = ""
var hits = 0 var hits = 0
for kind, path in walkDir(dir): for kind, path in walkDir(dir):
@ -375,14 +169,11 @@ proc findNimbleFile*(dir: string; error: bool): NimbleFile =
# TODO: Abstract logging. # TODO: Abstract logging.
echo("WARNING: No .nimble file found for ", dir) echo("WARNING: No .nimble file found for ", dir)
proc getPkgInfo*(dir: string): PackageInfo = proc getInstalledPkgsMin*(libsDir: string, options: Options):
## Find the .nimble file in ``dir`` and parses it, returning a PackageInfo.
let nimbleFile = findNimbleFile(dir, true)
result = readPackageInfo(nimbleFile)
proc getInstalledPkgs*(libsDir: string):
seq[tuple[pkginfo: PackageInfo, meta: MetaData]] = seq[tuple[pkginfo: PackageInfo, meta: MetaData]] =
## Gets a list of installed packages. ## Gets a list of installed packages. The resulting package info is
## minimal. This has the advantage that it does not depend on the
## ``packageparser`` module, and so can be used by ``nimscriptsupport``.
## ##
## ``libsDir`` is in most cases: ~/.nimble/pkgs/ ## ``libsDir`` is in most cases: ~/.nimble/pkgs/
result = @[] result = @[]
@ -391,23 +182,13 @@ proc getInstalledPkgs*(libsDir: string):
let nimbleFile = findNimbleFile(path, false) let nimbleFile = findNimbleFile(path, false)
if nimbleFile != "": if nimbleFile != "":
let meta = readMetaData(path) let meta = readMetaData(path)
try: let (name, version) = getNameVersion(nimbleFile)
result.add((readPackageInfo(nimbleFile, true), meta)) var pkg = initPackageInfo(nimbleFile)
except ValidationError: pkg.name = name
let exc = (ref ValidationError)(getCurrentException()) pkg.version = version
if exc.warnInstalled: pkg.isMinimal = true
echo("WARNING: Unable to read package info for " & path & "\n" & pkg.isInstalled = true
" Package did not pass validation: " & exc.msg) result.add((pkg, meta))
else:
exc.msg = "Unable to read package info for " & path & "\n" &
" Package did not pass validation: " & exc.msg
raise exc
except:
let exc = getCurrentException()
exc.msg = "Unable to read package info for " & path & "\n" &
" Error: " & exc.msg
raise exc
proc findPkg*(pkglist: seq[tuple[pkginfo: PackageInfo, meta: MetaData]], proc findPkg*(pkglist: seq[tuple[pkginfo: PackageInfo, meta: MetaData]],
dep: PkgTuple, dep: PkgTuple,
@ -441,7 +222,7 @@ proc findAllPkgs*(pkglist: seq[tuple[pkginfo: PackageInfo, meta: MetaData]],
proc getRealDir*(pkgInfo: PackageInfo): string = proc getRealDir*(pkgInfo: PackageInfo): string =
## Returns the ``pkgInfo.srcDir`` or the .mypath directory if package does ## Returns the ``pkgInfo.srcDir`` or the .mypath directory if package does
## not specify the src dir. ## not specify the src dir.
if pkgInfo.srcDir != "": if pkgInfo.srcDir != "" and not pkgInfo.isInstalled:
result = pkgInfo.mypath.splitFile.dir / pkgInfo.srcDir result = pkgInfo.mypath.splitFile.dir / pkgInfo.srcDir
else: else:
result = pkgInfo.mypath.splitFile.dir result = pkgInfo.mypath.splitFile.dir
@ -469,9 +250,6 @@ proc getDownloadDirName*(pkg: Package, verRange: VersionRange): string =
result.add "_" result.add "_"
result.add verSimple result.add verSimple
proc isNimScript*(nf: NimbleFile): bool =
result = readPackageInfo(nf).isNimScript
when isMainModule: when isMainModule:
doAssert getNameVersion("/home/user/.nimble/libs/packagea-0.1") == doAssert getNameVersion("/home/user/.nimble/libs/packagea-0.1") ==
("packagea", "0.1") ("packagea", "0.1")

View file

@ -0,0 +1,254 @@
# 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, nimscriptsupport, options, packageinfo
## Contains procedures for parsing .nimble files. Moved here from ``packageinfo``
## because it depends on ``nimscriptsupport`` (``nimscriptsupport`` also
## depends on other procedures in ``packageinfo``.
when not declared(system.map):
from sequtils import map
type
NimbleFile* = string
ValidationError* = object of NimbleError
warnInstalled*: bool # Determines whether to show a warning for installed pkgs
proc newValidationError(msg: string, warnInstalled: bool): ref ValidationError =
result = newException(ValidationError, msg)
result.warnInstalled = warnInstalled
proc validatePackageName*(name: string) =
## Raises an error if specified package name contains invalid characters.
##
## A valid package name is one which is a valid nim module name. So only
## underscores, letters and numbers allowed.
if name.len == 0: return
if name[0] in {'0'..'9'}:
raise newValidationError(name &
"\"$1\" is an invalid package name: cannot begin with $2" %
[name, $name[0]], true)
var prevWasUnderscore = false
for c in name:
case c
of '_':
if prevWasUnderscore:
raise newValidationError(
"$1 is an invalid package name: cannot contain \"__\"" % name, true)
prevWasUnderscore = true
of AllChars - IdentChars:
raise newValidationError(
"$1 is an invalid package name: cannot contain '$2'" % [name, $c],
true)
else:
prevWasUnderscore = false
proc validateVersion*(ver: string) =
for c in ver:
if c notin ({'.'} + Digits):
raise newValidationError(
"Version may only consist of numbers and the '.' character " &
"but found '" & c & "'.", false)
proc validatePackageInfo(pkgInfo: PackageInfo, path: string) =
if pkgInfo.name == "":
raise newValidationError("Incorrect .nimble file: " & path &
" does not contain a name field.", false)
if pkgInfo.name.normalize != path.splitFile.name.normalize:
raise newValidationError(
"The .nimble file name must match name specified inside " & path, true)
if pkgInfo.version == "":
raise newValidationError("Incorrect .nimble file: " & path &
" does not contain a version field.", false)
if not pkgInfo.isMinimal:
if pkgInfo.author == "":
raise newValidationError("Incorrect .nimble file: " & path &
" does not contain an author field.", false)
if pkgInfo.description == "":
raise newValidationError("Incorrect .nimble file: " & path &
" does not contain a description field.", false)
if pkgInfo.license == "":
raise newValidationError("Incorrect .nimble file: " & path &
" does not contain a license field.", false)
if pkgInfo.backend notin ["c", "cc", "objc", "cpp", "js"]:
raise newValidationError("'" & pkgInfo.backend &
"' is an invalid backend.", false)
validateVersion(pkgInfo.version)
proc nimScriptHint*(pkgInfo: PackageInfo) =
if not pkgInfo.isNimScript:
# TODO: Turn this into a warning.
# TODO: Add a URL explaining more.
echo("NOTE: The .nimble file for this project could make use of " &
"additional features, if converted into the new NimScript format.")
proc multiSplit(s: string): seq[string] =
## Returns ``s`` split by newline and comma characters.
##
## Before returning, all individual entries are stripped of whitespace and
## also empty entries are purged from the list. If after all the cleanups are
## done no entries are found in the list, the proc returns a sequence with
## the original string as the only entry.
result = split(s, {char(0x0A), char(0x0D), ','})
map(result, proc(x: var string) = x = x.strip())
for i in countdown(result.len()-1, 0):
if len(result[i]) < 1:
result.del(i)
# Huh, nothing to return? Return given input.
if len(result) < 1:
return @[s]
proc readPackageInfoFromNimble(path: string; result: var PackageInfo) =
var fs = newFileStream(path, fmRead)
if fs != nil:
var p: CfgParser
open(p, fs, path)
var currentSection = ""
while true:
var ev = next(p)
case ev.kind
of cfgEof:
break
of cfgSectionStart:
currentSection = ev.section
of cfgKeyValuePair:
case currentSection.normalize
of "package":
case ev.key.normalize
of "name": result.name = ev.value
of "version": result.version = ev.value
of "author": result.author = ev.value
of "description": result.description = ev.value
of "license": result.license = ev.value
of "srcdir": result.srcDir = ev.value
of "bindir": result.binDir = ev.value
of "skipdirs":
result.skipDirs.add(ev.value.multiSplit)
of "skipfiles":
result.skipFiles.add(ev.value.multiSplit)
of "skipext":
result.skipExt.add(ev.value.multiSplit)
of "installdirs":
result.installDirs.add(ev.value.multiSplit)
of "installfiles":
result.installFiles.add(ev.value.multiSplit)
of "installext":
result.installExt.add(ev.value.multiSplit)
of "bin":
for i in ev.value.multiSplit:
result.bin.add(i.addFileExt(ExeExt))
of "backend":
result.backend = ev.value.toLower()
case result.backend.normalize
of "javascript": result.backend = "js"
else: discard
else:
raise newException(NimbleError, "Invalid field: " & ev.key)
of "deps", "dependencies":
case ev.key.normalize
of "requires":
for v in ev.value.multiSplit:
result.requires.add(parseRequires(v.strip))
else:
raise newException(NimbleError, "Invalid field: " & ev.key)
else: raise newException(NimbleError,
"Invalid section: " & currentSection)
of cfgOption: raise newException(NimbleError,
"Invalid package info, should not contain --" & ev.value)
of cfgError:
raise newException(NimbleError, "Error parsing .nimble file: " & ev.msg)
close(p)
else:
raise newException(ValueError, "Cannot open package info: " & path)
proc readPackageInfo*(nf: NimbleFile, options: Options,
onlyMinimalInfo=false): PackageInfo =
## Reads package info from the specified Nimble file.
##
## Attempts to read it using the "old" Nimble ini format first, if that
## fails attempts to evaluate it as a nimscript file.
##
## If both fail then returns an error.
##
## When ``onlyMinimalInfo`` is true, only the `name` and `version` fields are
## populated. The isNimScript field can also be relied on.
result = initPackageInfo(nf)
validatePackageName(nf.splitFile.name)
var success = false
var iniError: ref NimbleError
# Attempt ini-format first.
try:
readPackageInfoFromNimble(nf, result)
success = true
result.isNimScript = false
except NimbleError:
iniError = (ref NimbleError)(getCurrentException())
if not success:
if onlyMinimalInfo:
let tmp = getNameVersion(nf)
result.name = tmp.name
result.version = tmp.version
result.isNimScript = true
result.isMinimal = true
else:
try:
readPackageInfoFromNims(nf, options, result)
result.isNimScript = true
except NimbleError:
let msg = "Could not read package info file in " & nf & ";\n" &
" Reading as ini file failed with: \n" &
" " & iniError.msg & ".\n" &
" Evaluating as NimScript file failed with: \n" &
" " & getCurrentExceptionMsg() & "."
raise newException(NimbleError, msg)
validatePackageInfo(result, nf)
proc getPkgInfo*(dir: string, options: Options): PackageInfo =
## Find the .nimble file in ``dir`` and parses it, returning a PackageInfo.
let nimbleFile = findNimbleFile(dir, true)
result = readPackageInfo(nimbleFile, options)
proc getInstalledPkgs*(libsDir: string, options: Options):
seq[tuple[pkginfo: PackageInfo, meta: MetaData]] =
## Gets a list of installed packages.
##
## ``libsDir`` is in most cases: ~/.nimble/pkgs/
result = @[]
for kind, path in walkDir(libsDir):
if kind == pcDir:
let nimbleFile = findNimbleFile(path, false)
if nimbleFile != "":
let meta = readMetaData(path)
try:
var pkg = readPackageInfo(nimbleFile, options, true)
pkg.isInstalled = true
result.add((pkg, meta))
except ValidationError:
let exc = (ref ValidationError)(getCurrentException())
if exc.warnInstalled:
echo("WARNING: Unable to read package info for " & path & "\n" &
" Package did not pass validation: " & exc.msg)
else:
exc.msg = "Unable to read package info for " & path & "\n" &
" Package did not pass validation: " & exc.msg
raise exc
except:
let exc = getCurrentException()
exc.msg = "Unable to read package info for " & path & "\n" &
" Error: " & exc.msg
raise exc
proc isNimScript*(nf: string, options: Options): bool =
result = readPackageInfo(nf, options).isNimScript

View file

@ -19,4 +19,7 @@ task c_test, "Testing `setCommand \"c\", \"nimscript.nim\"`":
task cr, "Testing `nimble c -r nimscript.nim` via setCommand": task cr, "Testing `nimble c -r nimscript.nim` via setCommand":
--r --r
setCommand "c", "nimscript.nim" setCommand "c", "nimscript.nim"
task api, "Testing nimscriptapi module functionality":
echo(getPkgDir())