Dependencies can now be specified.
This commit is contained in:
parent
41da5f70ae
commit
2b28c91e38
3 changed files with 208 additions and 5 deletions
|
|
@ -1,4 +1,5 @@
|
||||||
import parsecfg, json, streams, strutils
|
import parsecfg, json, streams, strutils, parseutils
|
||||||
|
import version
|
||||||
type
|
type
|
||||||
TPackageInfo* = object
|
TPackageInfo* = object
|
||||||
name*: string
|
name*: string
|
||||||
|
|
@ -8,6 +9,7 @@ type
|
||||||
license*: string
|
license*: string
|
||||||
skipDirs*: seq[string]
|
skipDirs*: seq[string]
|
||||||
skipFiles*: seq[string]
|
skipFiles*: seq[string]
|
||||||
|
requires*: seq[tuple[name: string, ver: PVersionRange]]
|
||||||
|
|
||||||
TPackage* = object
|
TPackage* = object
|
||||||
name*: string
|
name*: string
|
||||||
|
|
@ -27,6 +29,7 @@ proc initPackageInfo(): TPackageInfo =
|
||||||
result.license = ""
|
result.license = ""
|
||||||
result.skipDirs = @[]
|
result.skipDirs = @[]
|
||||||
result.skipFiles = @[]
|
result.skipFiles = @[]
|
||||||
|
result.requires = @[]
|
||||||
|
|
||||||
proc validatePackageInfo(pkgInfo: TPackageInfo, path: string) =
|
proc validatePackageInfo(pkgInfo: TPackageInfo, path: string) =
|
||||||
if pkgInfo.name == "":
|
if pkgInfo.name == "":
|
||||||
|
|
@ -40,6 +43,14 @@ proc validatePackageInfo(pkgInfo: TPackageInfo, path: string) =
|
||||||
if pkgInfo.license == "":
|
if pkgInfo.license == "":
|
||||||
quit("Incorrect .babel file: " & path & " does not contain a license field.")
|
quit("Incorrect .babel file: " & path & " does not contain a license field.")
|
||||||
|
|
||||||
|
proc parseRequires(req: string): tuple[name: string, ver: PVersionRange] =
|
||||||
|
try:
|
||||||
|
var i = skipUntil(req, whitespace)
|
||||||
|
result.name = req[0 .. i]
|
||||||
|
result.ver = parseVersionRange(req[i .. -1])
|
||||||
|
except EParseVersion:
|
||||||
|
quit("Unable to parse dependency version range: " & getCurrentExceptionMsg())
|
||||||
|
|
||||||
proc readPackageInfo*(path: string): TPackageInfo =
|
proc readPackageInfo*(path: string): TPackageInfo =
|
||||||
result = initPackageInfo()
|
result = initPackageInfo()
|
||||||
var fs = newFileStream(path, fmRead)
|
var fs = newFileStream(path, fmRead)
|
||||||
|
|
@ -63,12 +74,18 @@ proc readPackageInfo*(path: string): TPackageInfo =
|
||||||
of "author": result.author = ev.value
|
of "author": result.author = ev.value
|
||||||
of "description": result.description = ev.value
|
of "description": result.description = ev.value
|
||||||
of "license": result.license = ev.value
|
of "license": result.license = ev.value
|
||||||
of "library":
|
|
||||||
case ev.key.normalize
|
|
||||||
of "skipdirs":
|
of "skipdirs":
|
||||||
result.skipDirs.add(ev.value.split(','))
|
result.skipDirs.add(ev.value.split(','))
|
||||||
of "skipfiles":
|
of "skipfiles":
|
||||||
result.skipFiles.add(ev.value.split(','))
|
result.skipFiles.add(ev.value.split(','))
|
||||||
|
else:
|
||||||
|
quit("Invalid field: " & ev.key, QuitFailure)
|
||||||
|
of "deps", "dependencies":
|
||||||
|
case ev.key.normalize
|
||||||
|
of "requires":
|
||||||
|
result.requires.add(parseRequires(ev.value))
|
||||||
|
else:
|
||||||
|
quit("Invalid field: " & ev.key, QuitFailure)
|
||||||
else: quit("Invalid section: " & currentSection, QuitFailure)
|
else: quit("Invalid section: " & currentSection, QuitFailure)
|
||||||
of cfgOption: quit("Invalid package info, should not contain --" & ev.value, QuitFailure)
|
of cfgOption: quit("Invalid package info, should not contain --" & ev.value, QuitFailure)
|
||||||
of cfgError:
|
of cfgError:
|
||||||
|
|
|
||||||
|
|
@ -40,12 +40,15 @@ author = "Dominik Picheta"
|
||||||
description = """Example .babel file."""
|
description = """Example .babel file."""
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
|
||||||
[Library]
|
|
||||||
SkipDirs = "SomeDir" ; ./ProjectName/SomeDir will be skipped.
|
SkipDirs = "SomeDir" ; ./ProjectName/SomeDir will be skipped.
|
||||||
SkipFiles = "file.txt,file2.txt" ; ./ProjectName/{file.txt, file2.txt} will be skipped.
|
SkipFiles = "file.txt,file2.txt" ; ./ProjectName/{file.txt, file2.txt} will be skipped.
|
||||||
|
|
||||||
|
[Deps]
|
||||||
|
Requires: "nimrod >= 0.8.0"
|
||||||
```
|
```
|
||||||
|
|
||||||
All the fields under ``[Package]`` are required.
|
All the fields (except ``SkipDirs`` and ``SkipFiles``) under ``[Package]`` are
|
||||||
|
required.
|
||||||
|
|
||||||
## Submitting your package to the package list.
|
## Submitting your package to the package list.
|
||||||
Babel's packages list is stored on github and everyone is encouraged to add
|
Babel's packages list is stored on github and everyone is encouraged to add
|
||||||
|
|
|
||||||
183
version.nim
Normal file
183
version.nim
Normal file
|
|
@ -0,0 +1,183 @@
|
||||||
|
## Module for handling versions and version ranges such as ``>= 1.0 & <= 1.5``
|
||||||
|
import strutils
|
||||||
|
type
|
||||||
|
TVersion* = distinct string
|
||||||
|
|
||||||
|
TVersionRangeEnum* = enum
|
||||||
|
verLater, # > V
|
||||||
|
verEarlier, # < V
|
||||||
|
verEqLater, # >= V -- Equal or later
|
||||||
|
verEqEarlier, # <= V -- Equal or earlier
|
||||||
|
verIntersect, # > V & < V
|
||||||
|
verEq, # V
|
||||||
|
verAny # *
|
||||||
|
|
||||||
|
PVersionRange* = ref TVersionRange
|
||||||
|
TVersionRange* = object
|
||||||
|
case kind*: TVersionRangeEnum
|
||||||
|
of verLater, verEarlier, verEqLater, verEqEarlier, verEq:
|
||||||
|
ver*: TVersion
|
||||||
|
of verIntersect:
|
||||||
|
verILeft, verIRight: PVersionRange
|
||||||
|
of verAny:
|
||||||
|
nil
|
||||||
|
|
||||||
|
EParseVersion* = object of EInvalidValue
|
||||||
|
|
||||||
|
proc newVersion*(ver: string): TVersion = return TVersion(ver)
|
||||||
|
|
||||||
|
proc `$`*(ver: TVersion): String {.borrow.}
|
||||||
|
|
||||||
|
proc `<`*(ver: TVersion, ver2: TVersion): Bool =
|
||||||
|
var sVer = string(ver).split('.')
|
||||||
|
var sVer2 = string(ver2).split('.')
|
||||||
|
for i in 0..max(sVer.len, sVer2.len)-1:
|
||||||
|
if i > sVer.len-1:
|
||||||
|
return True
|
||||||
|
elif i > sVer2.len-1:
|
||||||
|
return False
|
||||||
|
|
||||||
|
var sVerI = parseInt(sVer[i])
|
||||||
|
var sVerI2 = parseInt(sVer2[i])
|
||||||
|
if sVerI < sVerI2:
|
||||||
|
return True
|
||||||
|
elif sVerI == sVerI2:
|
||||||
|
nil
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
proc `==`*(ver: TVersion, ver2: TVersion): Bool {.borrow.}
|
||||||
|
|
||||||
|
proc `<=`*(ver: TVersion, ver2: TVersion): Bool =
|
||||||
|
return (ver == ver2) or (ver < ver2)
|
||||||
|
|
||||||
|
proc withinRange*(ver: TVersion, ran: PVersionRange): Bool =
|
||||||
|
case ran.kind
|
||||||
|
of verLater:
|
||||||
|
return ver > ran.ver
|
||||||
|
of verEarlier:
|
||||||
|
return ver < ran.ver
|
||||||
|
of verEqLater:
|
||||||
|
return ver >= ran.ver
|
||||||
|
of verEqEarlier:
|
||||||
|
return ver <= ran.ver
|
||||||
|
of verEq:
|
||||||
|
return ver == ran.ver
|
||||||
|
of verIntersect:
|
||||||
|
return withinRange(ver, ran.verILeft) and withinRange(ver, ran.verIRight)
|
||||||
|
of verAny:
|
||||||
|
return True
|
||||||
|
|
||||||
|
proc makeRange*(version: string, op: string): PVersionRange =
|
||||||
|
new(result)
|
||||||
|
if version == "":
|
||||||
|
raise newException(EParseVersion, "A version needs to accompany the operator.")
|
||||||
|
case op
|
||||||
|
of ">":
|
||||||
|
result.kind = verLater
|
||||||
|
of "<":
|
||||||
|
result.kind = verEarlier
|
||||||
|
of ">=":
|
||||||
|
result.kind = verEqLater
|
||||||
|
of "<=":
|
||||||
|
result.kind = verEqEarlier
|
||||||
|
of "":
|
||||||
|
result.kind = verEq
|
||||||
|
else:
|
||||||
|
raise newException(EParseVersion, "Invalid operator: " & op)
|
||||||
|
result.ver = TVersion(version)
|
||||||
|
|
||||||
|
proc parseVersionRange*(s: string): PVersionRange =
|
||||||
|
# >= 1.5 & <= 1.8
|
||||||
|
new(result)
|
||||||
|
|
||||||
|
var i = 0
|
||||||
|
var op = ""
|
||||||
|
var version = ""
|
||||||
|
while True:
|
||||||
|
case s[i]
|
||||||
|
of '>', '<', '=':
|
||||||
|
op.add(s[i])
|
||||||
|
of '&':
|
||||||
|
result.kind = verIntersect
|
||||||
|
result.verILeft = makeRange(version, op)
|
||||||
|
|
||||||
|
# Parse everything after &
|
||||||
|
# Recursion <3
|
||||||
|
result.verIRight = parseVersionRange(substr(s, i + 1))
|
||||||
|
|
||||||
|
# Disallow more than one verIntersect. It's pointless and could lead to
|
||||||
|
# major unknown mistakes.
|
||||||
|
if result.verIRight.kind == verIntersect:
|
||||||
|
raise newException(EParseVersion,
|
||||||
|
"Having more than one `&` in a version range is pointless")
|
||||||
|
|
||||||
|
break
|
||||||
|
|
||||||
|
of '0'..'9', '.':
|
||||||
|
version.add(s[i])
|
||||||
|
|
||||||
|
of '\0':
|
||||||
|
result = makeRange(version, op)
|
||||||
|
break
|
||||||
|
|
||||||
|
of ' ':
|
||||||
|
# Make sure '0.9 8.03' is not allowed.
|
||||||
|
if version != "" and i < s.len:
|
||||||
|
if s[i+1] in {'0'..'9', '.'}:
|
||||||
|
raise newException(EParseVersion, "Whitespace is not allowed in a version literal.")
|
||||||
|
|
||||||
|
else:
|
||||||
|
raise newException(EParseVersion, "Unexpected char in version range: " & s[i])
|
||||||
|
inc(i)
|
||||||
|
|
||||||
|
proc `$`*(verRange: PVersionRange): String =
|
||||||
|
echo(verRange.repr())
|
||||||
|
case verRange.kind
|
||||||
|
of verLater:
|
||||||
|
result = "> "
|
||||||
|
of verEarlier:
|
||||||
|
result = "< "
|
||||||
|
of verEqLater:
|
||||||
|
result = ">= "
|
||||||
|
of verEqEarlier:
|
||||||
|
result = "<= "
|
||||||
|
of verEq:
|
||||||
|
result = ""
|
||||||
|
of verIntersect:
|
||||||
|
return $verRange.verILeft & " & " & $verRange.verIRight
|
||||||
|
of verAny:
|
||||||
|
return "Any"
|
||||||
|
|
||||||
|
result.add(string(verRange.ver))
|
||||||
|
|
||||||
|
proc newVRAny*(): PVersionRange =
|
||||||
|
new(result)
|
||||||
|
result.kind = verAny
|
||||||
|
|
||||||
|
proc newVREarlier*(ver: String): PVersionRange =
|
||||||
|
new(result)
|
||||||
|
result.kind = verEarlier
|
||||||
|
result.ver = newVersion(ver)
|
||||||
|
|
||||||
|
proc newVREq*(ver: string): PVersionRange =
|
||||||
|
new(result)
|
||||||
|
result.kind = verEq
|
||||||
|
result.ver = newVersion(ver)
|
||||||
|
|
||||||
|
when isMainModule:
|
||||||
|
doAssert(newVersion("1.0") < newVersion("1.4"))
|
||||||
|
doAssert(newVersion("1.0.1") > newVersion("1.0"))
|
||||||
|
doAssert(newVersion("1.0.6") <= newVersion("1.0.6"))
|
||||||
|
|
||||||
|
var inter1 = parseVersionRange(">= 1.0 & <= 1.5")
|
||||||
|
var inter2 = parseVersionRange("1.0")
|
||||||
|
doAssert(inter2.kind == verEq)
|
||||||
|
#echo(parseVersionRange(">= 0.8 0.9"))
|
||||||
|
|
||||||
|
doAssert(not withinRange(newVersion("1.5.1"), inter1))
|
||||||
|
doAssert(withinRange(newVersion("1.0.2.3.4.5.6.7.8.9.10.11.12"), inter1))
|
||||||
|
|
||||||
|
doAssert(newVersion("1") == newVersion("1"))
|
||||||
|
|
||||||
|
echo("Everything works!")
|
||||||
Loading…
Add table
Add a link
Reference in a new issue