Initial CLI implementation.

This commit is contained in:
Jonathan Bernard
2025-06-15 00:09:37 -05:00
parent 131eb8df16
commit f5c641c1b0
2 changed files with 96 additions and 24 deletions
+95 -23
View File
@@ -11,6 +11,9 @@ const USAGE = """Usage:
Options:
-d, --dir <dir> Use the given directory as the project root (defaults
to the current working directory).
-l, --lang <language> Choose the language/ecosystem to consider. Valid
values are: 'nim' or 'node'. If not provided, this
is auto-detected by the presence of either a *.nimble
@@ -64,13 +67,14 @@ type
SemVerParts = enum major, minor, patch, prerelease, buildmetadata
type PackageVersion = object
packageFile: Path
file: Path
version: string
name: string
case lang: LangType
of lNim:
discard
lines: seq[string]
versionLine: int
of lNode:
nodePackage: JsonNode
@@ -85,27 +89,29 @@ let SemVerPattern =
re"^(?P<major>0|[1-9]\d*)\.(?P<minor>0|[1-9]\d*)\.(?P<patch>0|[1-9]\d*)(?:-(?P<prerelease>(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?P<buildmetadata>[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$"
proc parseNimblePackage(dir: Path): PackageVersion =
result = PackageVersion(lang: lNim)
for fe in walkDir(dir):
if fe.kind == pcFile and
fe.path.splitFile.ext == ".nimble":
let content = readFile($fe.path)
for v in content.splitLines:
if v.startsWith("version"):
return PackageVersion(
lang: lNim,
packageFile: fe.path,
version: v.split("=")[^1].strip(chars = {' ', '"'}),
name: $fe.path.splitFile.name)
result.lines = readFile($fe.path).splitLines
for idx, l in result.lines:
if l.startsWith("version"):
result.versionLine = idx
result.version = l.split("=")[^1].strip(chars = {' ', '"'})
result.name = $fe.path.splitFile.name
result.file = fe.path
return result
raise newException(IOError, "No valid .nimble file found in $#" % [$dir])
proc parseNodePackage(dir: Path): PackageVersion =
result.packageFile = dir / Path("package.json")
result.lang = lNode
result.nodePackage = parseFile($result.packageFile)
result = PackageVersion(
file: dir / Path("package.json"),
lang: lNode,
nodePackage: parseFile($result.file))
if not result.nodePackage.hasKey("name") or
not result.nodePackage.hasKey("version") or
@@ -118,6 +124,28 @@ proc parseNodePackage(dir: Path): PackageVersion =
result.version = result.nodePackage{"version"}.getStr
proc detectAndParsePackage(dir: Path): PackageVersion =
try: result = parseNimblePackage(dir)
except:
let nimEx = getCurrentException()
try: result = parseNodePackage(dir)
except:
let nodeEx = getCurrentException()
stderr.writeLine(
"Unable to find a package definitions file. Errors:\n\t$#\n\t$#" %
[nimEx.msg, nodeEx.msg])
proc writePackage(pkg: PackageVersion) =
if pkg.lang == lNim:
var lines = pkg.lines
lines[pkg.versionLine] = "version = \"$#\"" % pkg.version
writeFile($pkg.file, lines.join("\p"))
elif pkg.lang == lNode:
pkg.nodePackage["version"] = %pkg.version
writeFile($pkg.file, pkg.nodePackage.pretty)
proc incrementLastVersionPart(version: string): string =
let versionParts = toSeq(findIter(version, re"([^\d.]+)?\.?(\d+)"))
let lastVersionPartMatch = versionParts[^1]
@@ -178,15 +206,7 @@ proc incrementSemverPart(
when isMainModule:
let args = docopt(USAGE, version = UV_VERSION)
if args["bump"]:
discard
elif args["set"]:
discard
elif args["get"]:
discard
elif args["interactive"]:
discard
elif args["test"]:
if args["test"]:
# incrementLastVersionPart
assert incrementLastVersionPart("1.0.0") == "1.0.1"
@@ -206,3 +226,55 @@ when isMainModule:
assert incrementSemverPart("1.5.10", buildmetadata) == "1.5.10+build.0"
echo "All tests passed."
quit(QuitSuccess)
let dir =
if args["--dir"]: Path($args["--dir"])
else: Path(".")
var pkg =
if args["--lang"] and $args["--lang"] == "nim":
parseNimblePackage(dir)
elif args["--lang"] and $args["--lang"] == "node":
parseNodePackage(dir)
else:
detectAndParsePackage(dir)
if args["bump"]:
if $args["<part>"] == "last":
pkg.version = incrementLastVersionPart(pkg.version)
else:
let part = parseEnum[SemVerParts]($args["<part>"])
pkg.version = incrementSemverPart(pkg.version, part)
writePackage(pkg)
echo pkg.version
elif args["set"]:
pkg.version = $args["<new-version>"]
writePackage(pkg)
echo pkg.version
elif args["get"]: echo pkg.version
elif args["interactive"]:
var acceptNewVersion = false
var newVersion = pkg.version
while not acceptNewVersion:
stdout.writeLine "Current version is " & pkg.version
stdout.write "New version? "
newVersion = stdin.readLine
stdout.write "New version will be set to '" & pkg.version & "'. Is this correct (yes/no)? "
let isCorrect = stdin.readLine
let acceptNewVersion = "yes".startsWith(isCorrect.toLower)
pkg.version = newVersion
echo "Updating version definition in " & $pkg.file
writePackage(pkg)
# TODO:
# for f in filesToUpdate:
# echo "Updating version definition in " & $f
# updateVersionInFile(f)