Merge branch 'master' of https://github.com/Araq/nimble into Araq-master

This commit is contained in:
Dominik Picheta 2015-11-07 16:01:19 +00:00
commit 6fcbffd1cc
7 changed files with 425 additions and 226 deletions

View file

@ -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

View 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()

View file

@ -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 & ")")

View file

@ -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: