Merge branch 'master' of https://github.com/Araq/nimble into Araq-master
This commit is contained in:
commit
6fcbffd1cc
7 changed files with 425 additions and 226 deletions
|
|
@ -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
|
||||
|
||||
|
|
|
|||
117
src/nimblepkg/nimscriptsupport.nim
Normal file
117
src/nimblepkg/nimscriptsupport.nim
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
# 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 = if n.strVal.isNil: "" else: 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 x.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) =
|
||||
setDefaultLibpath()
|
||||
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 backend.len == 0:
|
||||
result.backend = "c"
|
||||
elif cmpIgnoreStyle(backend, "javascript") == 0:
|
||||
result.backend = "js"
|
||||
else:
|
||||
result.backend = backend.toLower()
|
||||
|
||||
# ensure everything can be called again:
|
||||
resetAllModulesHard()
|
||||
vm.globalCtx = nil
|
||||
initDefines()
|
||||
|
|
@ -1,11 +1,14 @@
|
|||
# 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
|
||||
|
||||
when not declared(system.map):
|
||||
from sequtils import map
|
||||
|
||||
const
|
||||
NimsExt* = ".nims"
|
||||
|
||||
type
|
||||
Package* = object
|
||||
# Required fields in a package.
|
||||
|
|
@ -15,7 +18,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.
|
||||
|
|
@ -23,9 +26,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 = ""
|
||||
|
|
@ -67,23 +73,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.
|
||||
##
|
||||
|
|
@ -100,9 +89,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
|
||||
|
|
@ -164,7 +151,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.
|
||||
|
|
@ -241,21 +256,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):
|
||||
|
|
@ -266,13 +294,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,
|
||||
|
|
@ -284,8 +309,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
|
||||
|
|
@ -298,8 +323,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
|
||||
|
||||
|
|
@ -318,22 +343,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