Fix NimScriptApi builtins. Implement before/after hooks for NimS.

This commit is contained in:
Dominik Picheta 2015-12-30 18:14:32 +00:00
commit 5d55a5f7a2
5 changed files with 95 additions and 19 deletions

View file

@ -12,6 +12,13 @@ srcDir = "src"
requires "nim >= 0.11.2"
before tasks:
echo("About to list tasks!")
return true
after tasks:
echo("Listed tasks!")
task tests, "Run the Nimble tester!":
withDir "tests":
exec "nim c -r tester"

View file

@ -856,12 +856,23 @@ proc listTasks(options: Options) =
let nimbleFile = findNimbleFile(getCurrentDir(), true)
nimscriptsupport.listTasks(nimbleFile, options)
proc execHook(options: Options, before: bool): bool =
## Returns whether to continue.
result = true
let nimbleFile = findNimbleFile(getCurrentDir(), true)
# TODO: Optimise this, there are two (three?) calls to readPackageInfo.
if nimbleFile.isNimScript(options):
let actionName = ($options.action.typ)[6 .. ^1]
let res = execHook(nimbleFile, actionName, before, options)
result = res.retVal
proc doAction(options: Options) =
if not existsDir(options.getNimbleDir()):
createDir(options.getNimbleDir())
if not existsDir(options.getPkgsDir):
createDir(options.getPkgsDir)
if not execHook(options, true): return
case options.action.typ
of actionUpdate:
update(options)
@ -898,7 +909,6 @@ proc doAction(options: Options) =
of actionCustom:
# Custom command. Attempt to call a NimScript task.
let nimbleFile = findNimbleFile(getCurrentDir(), true)
## TODO: Optimise this, there are two calls to readPackageInfo here.
if not nimbleFile.isNimScript(options):
writeHelp()
@ -910,6 +920,8 @@ proc doAction(options: Options) =
if execResult.command.normalize == "nop":
echo("WARNING: Using `setCommand 'nop'` is not necessary.")
return
if not execHook(options, false):
return
if execResult.hasTaskRequestedCommand():
var newOptions = initOptions()
newOptions.config = options.config
@ -921,6 +933,9 @@ proc doAction(options: Options) =
parseFlag(flag, val, newOptions)
doAction(newOptions)
if options.action.typ != actionCustom:
discard execHook(options, false)
when isMainModule:
when defined(release):
try:

View file

@ -24,6 +24,17 @@ proc requires*(deps: varargs[string]) =
## package.
for d in deps: requiresData.add(d)
template before*(action: untyped, body: untyped): untyped =
## Defines a block of code which is evaluated before ``action`` is executed.
proc `action Before`*(): bool =
result = false
body
template after*(action: untyped, body: untyped): untyped =
## Defines a block of code which is evaluated after ``action`` is executed.
proc `action After`*(): bool =
body
template builtin = discard
proc getPkgDir*(): string =

View file

@ -12,18 +12,21 @@ import
from compiler/scriptconfig import setupVM
from compiler/idents import getIdent
from compiler/astalgo import strTableGet
from compiler/astalgo import strTableGet, `$`
import compiler/options as compiler_options
import compiler/renderer
import nimbletypes, version, options, packageinfo
import os, strutils, strtabs, times, osproc
type
ExecutionResult* = object
ExecutionResult*[T] = object
success*: bool
command*: string
arguments*: seq[string]
flags*: StringTableRef
retVal*: T
const
internalCmd = "NimbleInternal"
@ -174,18 +177,20 @@ proc setupVM(module: PSym; scriptName: string,
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
# Try finding it in exe's path
if fileExists(getAppDir() / "nimblepkg" / "nimscriptapi.nim"):
result = getAppDir()
inPath = true
if not inPath:
# Try finding it in exe's path
if fileExists(getAppDir() / "nimblepkg" / "nimscriptapi.nim"):
result = getAppDir()
inPath = true
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:
raise newException(NimbleError, "Cannot find nimscriptapi.nim")
@ -196,6 +201,8 @@ proc execScript(scriptName: string, flags: StringTableRef, options: Options) =
if "nimblepkg/nimscriptapi" notin compiler_options.implicitIncludes:
compiler_options.implicitIncludes.add("nimblepkg/nimscriptapi")
let pkgName = scriptName.splitFile.name
# Ensure that "nimblepkg/nimscriptapi" is in the PATH.
let nimscriptApiPath = findNimscriptApi(options)
appendStr(searchPaths, nimscriptApiPath)
@ -219,10 +226,10 @@ proc execScript(scriptName: string, flags: StringTableRef, options: Options) =
# Setup builtins defined in nimscriptapi.nim
template cbApi(name, body) {.dirty.} =
vm.globalCtx.registerCallback "stdlib.system." & astToStr(name),
vm.globalCtx.registerCallback pkgName & "." & astToStr(name),
proc (a: VmArgs) =
body
# TODO: This doesn't work.
cbApi getPkgDir:
setResult(a, "FOOBAR")
@ -318,7 +325,7 @@ proc readPackageInfoFromNims*(scriptName: string, options: Options,
cleanup()
proc execTask*(scriptName, taskName: string,
options: Options): ExecutionResult =
options: Options): ExecutionResult[void] =
## Executes the specified task in the specified script.
##
## `scriptName` should be a filename pointing to the nimscript file.
@ -347,6 +354,44 @@ proc execTask*(scriptName, taskName: string,
cleanup()
proc execHook*(scriptName, actionName: string, before: bool,
options: Options): ExecutionResult[bool] =
## Executes the specified action's hook. Depending on ``before``, either
## the "before" or the "after" hook.
##
## `scriptName` should be a filename pointing to the nimscript file.
result.success = true
result.flags = newStringTable()
compiler_options.command = internalCmd
let hookName =
if before: actionName.toLower & "Before"
else: actionName.toLower & "After"
echo("Attempting to execute hook ", hookName, " in ", scriptName)
execScript(scriptName, result.flags, options)
# Explicitly execute the task procedure, instead of relying on hack.
let idx = fileInfoIdx(scriptName)
let thisModule = getModule(idx)
assert thisModule.kind == skModule
let prc = thisModule.tab.strTableGet(getIdent(hookName))
if prc.isNil:
# Procedure not defined in the NimScript module.
result.success = false
return
let returnVal = vm.globalCtx.execProc(prc, [])
case returnVal.kind
of nkCharLit..nkUInt64Lit:
result.retVal = returnVal.intVal == 1
else: assert false
# Read the command, arguments and flags set by the executed task.
result.command = compiler_options.command
result.arguments = @[]
for arg in compiler_options.gProjectName.split():
result.arguments.add(arg)
cleanup()
proc getNimScriptCommand(): string =
compiler_options.command

View file

@ -29,8 +29,6 @@ type
of actionUpdate:
optionalURL*: string # Overrides default package list.
of actionInstall, actionPath, actionUninstall:
optionalName*: seq[string] # \
# When this is @[], installs package from current dir.
packages*: seq[PkgTuple] # Optional only for actionInstall.
of actionSearch:
search*: seq[string] # Search string.