Various optimisations to PackageInfo reading and bug fixes.

* PackageInfo objects are now cached because NimScript evaluation is expensive.
* before/after hooks now return `true` by default.
* Bugfix: when hooks weren't found Nimble would still think that a hook told it
  to skip an action.
* PackageInfo now includes info about which hooks are defined to prevent
  unnecessary execution of those hooks.
* Probably more.
This commit is contained in:
Dominik Picheta 2015-12-30 19:43:20 +00:00
commit 42ef358459
8 changed files with 47 additions and 20 deletions

View file

@ -12,13 +12,6 @@ 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"

View file

@ -860,11 +860,16 @@ proc execHook(options: Options, before: bool): bool =
## Returns whether to continue. ## Returns whether to continue.
result = true result = true
let nimbleFile = findNimbleFile(getCurrentDir(), true) let nimbleFile = findNimbleFile(getCurrentDir(), true)
# TODO: Optimise this, there are two (three?) calls to readPackageInfo. # PackageInfos are cached so we can read them as many times as we want.
if nimbleFile.isNimScript(options): let pkgInfo = readPackageInfo(nimbleFile, options)
let actionName = ($options.action.typ)[6 .. ^1] let actionName = ($options.action.typ)[6 .. ^1]
let hookExists =
if before: actionName.normalize in pkgInfo.preHooks
else: actionName.normalize in pkgInfo.postHooks
if pkgInfo.isNimScript and hookExists:
let res = execHook(nimbleFile, actionName, before, options) let res = execHook(nimbleFile, actionName, before, options)
result = res.retVal if res.success:
result = res.retVal
proc doAction(options: Options) = proc doAction(options: Options) =
if not existsDir(options.getNimbleDir()): if not existsDir(options.getNimbleDir()):

View file

@ -3,6 +3,8 @@
# Various miscellaneous common types reside here, to avoid problems with # Various miscellaneous common types reside here, to avoid problems with
# recursive imports # recursive imports
import sets
import version import version
export version.NimbleError export version.NimbleError
@ -14,6 +16,8 @@ type
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 isInstalled*: bool ## Determines if the pkg this info belongs to is installed
postHooks*: HashSet[string] ## Useful to know so that Nimble doesn't execHook unnecessarily
preHooks*: HashSet[string]
name*: string name*: string
version*: string version*: string
author*: string author*: string

View file

@ -27,12 +27,13 @@ proc requires*(deps: varargs[string]) =
template before*(action: untyped, body: untyped): untyped = template before*(action: untyped, body: untyped): untyped =
## Defines a block of code which is evaluated before ``action`` is executed. ## Defines a block of code which is evaluated before ``action`` is executed.
proc `action Before`*(): bool = proc `action Before`*(): bool =
result = false result = true
body body
template after*(action: untyped, body: untyped): untyped = template after*(action: untyped, body: untyped): untyped =
## Defines a block of code which is evaluated after ``action`` is executed. ## Defines a block of code which is evaluated after ``action`` is executed.
proc `action After`*(): bool = proc `action After`*(): bool =
result = true
body body
template builtin = discard template builtin = discard

View file

@ -12,13 +12,11 @@ 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, sets
type type
ExecutionResult*[T] = object ExecutionResult*[T] = object
@ -277,7 +275,9 @@ proc readPackageInfoFromNims*(scriptName: string, options: 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 = proc getSym(thisModule: PSym, ident: string): PSym =
thisModule.tab.strTableGet(getIdent(ident)) result = thisModule.tab.strTableGet(getIdent(ident))
if result.isNil:
raise newException(NimbleError, "Ident not found: " & ident)
template trivialField(field) = template trivialField(field) =
result.field = getGlobal(getSym(thisModule, astToStr field)) result.field = getGlobal(getSym(thisModule, astToStr field))
@ -322,6 +322,15 @@ proc readPackageInfoFromNims*(scriptName: string, options: Options,
else: else:
result.backend = backend.toLower() result.backend = backend.toLower()
# Grab all the global procs
for i in thisModule.tab.data:
if not i.isNil():
let name = i.name.s.normalize()
if name.endsWith("before"):
result.preHooks.incl(name[0 .. ^7])
if name.endsWith("after"):
result.postHooks.incl(name[0 .. ^6])
cleanup() cleanup()
proc execTask*(scriptName, taskName: string, proc execTask*(scriptName, taskName: string,
@ -377,6 +386,7 @@ proc execHook*(scriptName, actionName: string, before: bool,
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
cleanup()
return return
let returnVal = vm.globalCtx.execProc(prc, []) let returnVal = vm.globalCtx.execProc(prc, [])
case returnVal.kind case returnVal.kind

View file

@ -1,11 +1,11 @@
# Copyright (C) Dominik Picheta. All rights reserved. # Copyright (C) Dominik Picheta. All rights reserved.
# BSD License. Look at license.txt for more info. # BSD License. Look at license.txt for more info.
import json, strutils, os, parseopt, strtabs, uri import json, strutils, os, parseopt, strtabs, uri, tables
from httpclient import Proxy, newProxy from httpclient import Proxy, newProxy
import nimblepkg/config, nimblepkg/version, import nimblepkg/config, nimblepkg/version,
nimblepkg/tools nimblepkg/tools, nimblepkg/nimbletypes
type type
Options* = object Options* = object
@ -15,6 +15,7 @@ type
action*: Action action*: Action
config*: Config config*: Config
nimbleData*: JsonNode ## Nimbledata.json nimbleData*: JsonNode ## Nimbledata.json
pkgInfoCache*: TableRef[string, PackageInfo]
ActionType* = enum ActionType* = enum
actionNil, actionUpdate, actionInit, actionDump, actionPublish, actionNil, actionUpdate, actionInit, actionDump, actionPublish,
@ -258,6 +259,7 @@ proc parseFlag*(flag, val: string, result: var Options) =
proc initOptions*(): Options = proc initOptions*(): Options =
result.action.typ = actionNil result.action.typ = actionNil
result.pkgInfoCache = newTable[string, PackageInfo]()
proc parseMisc(): Options = proc parseMisc(): Options =
result = initOptions() result = initOptions()

View file

@ -22,6 +22,8 @@ type
proc initPackageInfo*(path: string): PackageInfo = proc initPackageInfo*(path: string): PackageInfo =
result.mypath = path result.mypath = path
result.preHooks.init()
result.postHooks.init()
# reasonable default: # reasonable default:
result.name = path.splitFile.name result.name = path.splitFile.name
result.version = "" result.version = ""

View file

@ -1,6 +1,6 @@
# 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, tables
import version, tools, nimbletypes, nimscriptsupport, options, packageinfo import version, tools, nimbletypes, nimscriptsupport, options, packageinfo
## Contains procedures for parsing .nimble files. Moved here from ``packageinfo`` ## Contains procedures for parsing .nimble files. Moved here from ``packageinfo``
@ -187,6 +187,15 @@ proc readPackageInfo*(nf: NimbleFile, options: Options,
## ##
## When ``onlyMinimalInfo`` is true, only the `name` and `version` fields are ## When ``onlyMinimalInfo`` is true, only the `name` and `version` fields are
## populated. The isNimScript field can also be relied on. ## populated. The isNimScript field can also be relied on.
##
## This version uses a cache stored in ``options``, so calling it multiple
## times on the same ``nf`` shouldn't require re-evaluation of the Nimble
## file.
# Check the cache.
if options.pkgInfoCache.hasKey(nf):
return options.pkgInfoCache[nf]
result = initPackageInfo(nf) result = initPackageInfo(nf)
validatePackageName(nf.splitFile.name) validatePackageName(nf.splitFile.name)
@ -221,6 +230,7 @@ proc readPackageInfo*(nf: NimbleFile, options: Options,
raise newException(NimbleError, msg) raise newException(NimbleError, msg)
validatePackageInfo(result, nf) validatePackageInfo(result, nf)
options.pkgInfoCache[nf] = result
proc getPkgInfo*(dir: string, options: Options): PackageInfo = proc getPkgInfo*(dir: string, options: Options): PackageInfo =
## Find the .nimble file in ``dir`` and parses it, returning a PackageInfo. ## Find the .nimble file in ``dir`` and parses it, returning a PackageInfo.