Fix NimScriptApi builtins. Implement before/after hooks for NimS.
This commit is contained in:
parent
c4639fc145
commit
5d55a5f7a2
5 changed files with 95 additions and 19 deletions
|
|
@ -12,6 +12,13 @@ srcDir = "src"
|
||||||
|
|
||||||
requires "nim >= 0.11.2"
|
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!":
|
task tests, "Run the Nimble tester!":
|
||||||
withDir "tests":
|
withDir "tests":
|
||||||
exec "nim c -r tester"
|
exec "nim c -r tester"
|
||||||
|
|
@ -856,12 +856,23 @@ proc listTasks(options: Options) =
|
||||||
let nimbleFile = findNimbleFile(getCurrentDir(), true)
|
let nimbleFile = findNimbleFile(getCurrentDir(), true)
|
||||||
nimscriptsupport.listTasks(nimbleFile, options)
|
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) =
|
proc doAction(options: Options) =
|
||||||
if not existsDir(options.getNimbleDir()):
|
if not existsDir(options.getNimbleDir()):
|
||||||
createDir(options.getNimbleDir())
|
createDir(options.getNimbleDir())
|
||||||
if not existsDir(options.getPkgsDir):
|
if not existsDir(options.getPkgsDir):
|
||||||
createDir(options.getPkgsDir)
|
createDir(options.getPkgsDir)
|
||||||
|
|
||||||
|
if not execHook(options, true): return
|
||||||
case options.action.typ
|
case options.action.typ
|
||||||
of actionUpdate:
|
of actionUpdate:
|
||||||
update(options)
|
update(options)
|
||||||
|
|
@ -898,7 +909,6 @@ 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)
|
||||||
## TODO: Optimise this, there are two calls to readPackageInfo here.
|
|
||||||
if not nimbleFile.isNimScript(options):
|
if not nimbleFile.isNimScript(options):
|
||||||
writeHelp()
|
writeHelp()
|
||||||
|
|
||||||
|
|
@ -910,6 +920,8 @@ proc doAction(options: Options) =
|
||||||
if execResult.command.normalize == "nop":
|
if execResult.command.normalize == "nop":
|
||||||
echo("WARNING: Using `setCommand 'nop'` is not necessary.")
|
echo("WARNING: Using `setCommand 'nop'` is not necessary.")
|
||||||
return
|
return
|
||||||
|
if not execHook(options, false):
|
||||||
|
return
|
||||||
if execResult.hasTaskRequestedCommand():
|
if execResult.hasTaskRequestedCommand():
|
||||||
var newOptions = initOptions()
|
var newOptions = initOptions()
|
||||||
newOptions.config = options.config
|
newOptions.config = options.config
|
||||||
|
|
@ -921,6 +933,9 @@ proc doAction(options: Options) =
|
||||||
parseFlag(flag, val, newOptions)
|
parseFlag(flag, val, newOptions)
|
||||||
doAction(newOptions)
|
doAction(newOptions)
|
||||||
|
|
||||||
|
if options.action.typ != actionCustom:
|
||||||
|
discard execHook(options, false)
|
||||||
|
|
||||||
when isMainModule:
|
when isMainModule:
|
||||||
when defined(release):
|
when defined(release):
|
||||||
try:
|
try:
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,17 @@ proc requires*(deps: varargs[string]) =
|
||||||
## package.
|
## package.
|
||||||
for d in deps: requiresData.add(d)
|
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
|
template builtin = discard
|
||||||
|
|
||||||
proc getPkgDir*(): string =
|
proc getPkgDir*(): string =
|
||||||
|
|
|
||||||
|
|
@ -12,18 +12,21 @@ import
|
||||||
|
|
||||||
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 compiler/options as compiler_options
|
||||||
|
|
||||||
|
import compiler/renderer
|
||||||
|
|
||||||
import nimbletypes, version, options, packageinfo
|
import nimbletypes, version, options, packageinfo
|
||||||
import os, strutils, strtabs, times, osproc
|
import os, strutils, strtabs, times, osproc
|
||||||
|
|
||||||
type
|
type
|
||||||
ExecutionResult* = object
|
ExecutionResult*[T] = object
|
||||||
success*: bool
|
success*: bool
|
||||||
command*: string
|
command*: string
|
||||||
arguments*: seq[string]
|
arguments*: seq[string]
|
||||||
flags*: StringTableRef
|
flags*: StringTableRef
|
||||||
|
retVal*: T
|
||||||
|
|
||||||
const
|
const
|
||||||
internalCmd = "NimbleInternal"
|
internalCmd = "NimbleInternal"
|
||||||
|
|
@ -174,18 +177,20 @@ proc setupVM(module: PSym; scriptName: string,
|
||||||
proc findNimscriptApi(options: Options): string =
|
proc findNimscriptApi(options: Options): string =
|
||||||
## Returns the directory containing ``nimscriptapi.nim``
|
## Returns the directory containing ``nimscriptapi.nim``
|
||||||
var inPath = false
|
var inPath = false
|
||||||
let pkgs = getInstalledPkgsMin(options.getPkgsDir(), options)
|
# Try finding it in exe's path
|
||||||
var pkg: PackageInfo
|
if fileExists(getAppDir() / "nimblepkg" / "nimscriptapi.nim"):
|
||||||
if pkgs.findPkg(("nimble", newVRAny()), pkg):
|
result = getAppDir()
|
||||||
let pkgDir = pkg.getRealDir()
|
inPath = true
|
||||||
if fileExists(pkgDir / "nimblepkg" / "nimscriptapi.nim"):
|
|
||||||
result = pkgDir
|
|
||||||
inPath = true
|
|
||||||
if not inPath:
|
if not inPath:
|
||||||
# Try finding it in exe's path
|
let pkgs = getInstalledPkgsMin(options.getPkgsDir(), options)
|
||||||
if fileExists(getAppDir() / "nimblepkg" / "nimscriptapi.nim"):
|
var pkg: PackageInfo
|
||||||
result = getAppDir()
|
if pkgs.findPkg(("nimble", newVRAny()), pkg):
|
||||||
inPath = true
|
let pkgDir = pkg.getRealDir()
|
||||||
|
if fileExists(pkgDir / "nimblepkg" / "nimscriptapi.nim"):
|
||||||
|
result = pkgDir
|
||||||
|
inPath = true
|
||||||
|
|
||||||
if not inPath:
|
if not inPath:
|
||||||
raise newException(NimbleError, "Cannot find nimscriptapi.nim")
|
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:
|
if "nimblepkg/nimscriptapi" notin compiler_options.implicitIncludes:
|
||||||
compiler_options.implicitIncludes.add("nimblepkg/nimscriptapi")
|
compiler_options.implicitIncludes.add("nimblepkg/nimscriptapi")
|
||||||
|
|
||||||
|
let pkgName = scriptName.splitFile.name
|
||||||
|
|
||||||
# Ensure that "nimblepkg/nimscriptapi" is in the PATH.
|
# Ensure that "nimblepkg/nimscriptapi" is in the PATH.
|
||||||
let nimscriptApiPath = findNimscriptApi(options)
|
let nimscriptApiPath = findNimscriptApi(options)
|
||||||
appendStr(searchPaths, nimscriptApiPath)
|
appendStr(searchPaths, nimscriptApiPath)
|
||||||
|
|
@ -219,10 +226,10 @@ proc execScript(scriptName: string, flags: StringTableRef, options: Options) =
|
||||||
|
|
||||||
# Setup builtins defined in nimscriptapi.nim
|
# Setup builtins defined in nimscriptapi.nim
|
||||||
template cbApi(name, body) {.dirty.} =
|
template cbApi(name, body) {.dirty.} =
|
||||||
vm.globalCtx.registerCallback "stdlib.system." & astToStr(name),
|
vm.globalCtx.registerCallback pkgName & "." & astToStr(name),
|
||||||
proc (a: VmArgs) =
|
proc (a: VmArgs) =
|
||||||
body
|
body
|
||||||
# TODO: This doesn't work.
|
|
||||||
cbApi getPkgDir:
|
cbApi getPkgDir:
|
||||||
setResult(a, "FOOBAR")
|
setResult(a, "FOOBAR")
|
||||||
|
|
||||||
|
|
@ -318,7 +325,7 @@ proc readPackageInfoFromNims*(scriptName: string, options: Options,
|
||||||
cleanup()
|
cleanup()
|
||||||
|
|
||||||
proc execTask*(scriptName, taskName: string,
|
proc execTask*(scriptName, taskName: string,
|
||||||
options: Options): ExecutionResult =
|
options: Options): ExecutionResult[void] =
|
||||||
## 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.
|
||||||
|
|
@ -347,6 +354,44 @@ proc execTask*(scriptName, taskName: string,
|
||||||
|
|
||||||
cleanup()
|
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 =
|
proc getNimScriptCommand(): string =
|
||||||
compiler_options.command
|
compiler_options.command
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,8 +29,6 @@ type
|
||||||
of actionUpdate:
|
of actionUpdate:
|
||||||
optionalURL*: string # Overrides default package list.
|
optionalURL*: string # Overrides default package list.
|
||||||
of actionInstall, actionPath, actionUninstall:
|
of actionInstall, actionPath, actionUninstall:
|
||||||
optionalName*: seq[string] # \
|
|
||||||
# When this is @[], installs package from current dir.
|
|
||||||
packages*: seq[PkgTuple] # Optional only for actionInstall.
|
packages*: seq[PkgTuple] # Optional only for actionInstall.
|
||||||
of actionSearch:
|
of actionSearch:
|
||||||
search*: seq[string] # Search string.
|
search*: seq[string] # Search string.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue