Improved the init command. Fixes #96.
This commit is contained in:
parent
dbd478bc20
commit
7d5428be19
4 changed files with 130 additions and 42 deletions
105
src/nimble.nim
105
src/nimble.nim
|
|
@ -151,6 +151,18 @@ proc prompt(options: Options, question: string): bool =
|
||||||
else:
|
else:
|
||||||
return false
|
return false
|
||||||
|
|
||||||
|
proc promptCustom(question, default: string): string =
|
||||||
|
if default == "":
|
||||||
|
stdout.write(question, ": ")
|
||||||
|
let user = stdin.readLine()
|
||||||
|
if user.len == 0: return promptCustom(question, default)
|
||||||
|
else: return user
|
||||||
|
else:
|
||||||
|
stdout.write(question, " [", default, "]: ")
|
||||||
|
let user = stdin.readLine()
|
||||||
|
if user == "": return default
|
||||||
|
else: return user
|
||||||
|
|
||||||
proc renameBabelToNimble(options: Options) {.deprecated.} =
|
proc renameBabelToNimble(options: Options) {.deprecated.} =
|
||||||
let babelDir = getHomeDir() / ".babel"
|
let babelDir = getHomeDir() / ".babel"
|
||||||
let nimbleDir = getHomeDir() / ".nimble"
|
let nimbleDir = getHomeDir() / ".nimble"
|
||||||
|
|
@ -884,13 +896,6 @@ proc listPaths(options: Options) =
|
||||||
raise newException(NimbleError,
|
raise newException(NimbleError,
|
||||||
"At least one of the specified packages was not found")
|
"At least one of the specified packages was not found")
|
||||||
|
|
||||||
proc guessAuthor(): string =
|
|
||||||
if dirExists(os.getCurrentDir() / ".git"):
|
|
||||||
let (output, exitCode) = doCmdEx("git config user.name")
|
|
||||||
if exitCode == 0:
|
|
||||||
return output.string.strip
|
|
||||||
return "Anonymous"
|
|
||||||
|
|
||||||
proc join(x: seq[PkgTuple]; y: string): string =
|
proc join(x: seq[PkgTuple]; y: string): string =
|
||||||
if x.len == 0: return ""
|
if x.len == 0: return ""
|
||||||
result = x[0][0] & " " & $x[0][1]
|
result = x[0][0] & " " & $x[0][1]
|
||||||
|
|
@ -899,7 +904,7 @@ proc join(x: seq[PkgTuple]; y: string): string =
|
||||||
result.add x[i][0] & " " & $x[i][1]
|
result.add x[i][0] & " " & $x[i][1]
|
||||||
|
|
||||||
proc dump(options: Options) =
|
proc dump(options: Options) =
|
||||||
let proj = addFileExt(options.action.projName, NimsExt)
|
let proj = addFileExt(options.action.projName, "nimble")
|
||||||
let p = if fileExists(proj): readPackageInfo(proj)
|
let p = if fileExists(proj): readPackageInfo(proj)
|
||||||
else: getPkgInfo(os.getCurrentDir())
|
else: getPkgInfo(os.getCurrentDir())
|
||||||
echo "name: ", p.name.escape
|
echo "name: ", p.name.escape
|
||||||
|
|
@ -920,44 +925,76 @@ proc dump(options: Options) =
|
||||||
echo "backend: ", p.backend.escape
|
echo "backend: ", p.backend.escape
|
||||||
|
|
||||||
proc init(options: Options) =
|
proc init(options: Options) =
|
||||||
echo("Initializing new Nimble project!")
|
var nimbleFile: string = ""
|
||||||
var
|
|
||||||
pkgName, fName: string = ""
|
|
||||||
outFile: File
|
|
||||||
|
|
||||||
|
echo("In order to initialise a new Nimble package, I will need to ask you\n" &
|
||||||
|
"some questions. Default values are shown in square brackets, press\n" &
|
||||||
|
"enter to use them.")
|
||||||
|
|
||||||
|
# Ask for package name.
|
||||||
if options.action.projName != "":
|
if options.action.projName != "":
|
||||||
pkgName = options.action.projName
|
let pkgName = options.action.projName
|
||||||
fName = pkgName & NimsExt
|
nimbleFile = pkgName.changeFileExt("nimble")
|
||||||
if (existsFile(os.getCurrentDir() / fName)):
|
|
||||||
raise newException(NimbleError, "Already have a nimscript file.")
|
|
||||||
else:
|
else:
|
||||||
echo("Enter a project name for this (blank to use working directory), " &
|
var pkgName = os.getCurrentDir().splitPath.tail.toValidPackageName()
|
||||||
"Ctrl-C to abort:")
|
pkgName = promptCustom("Enter package name", pkgName)
|
||||||
pkgName = readline(stdin)
|
nimbleFile = pkgName.changeFileExt("nimble")
|
||||||
if pkgName == "":
|
|
||||||
pkgName = os.getCurrentDir().splitPath.tail
|
|
||||||
if pkgName == "":
|
|
||||||
raise newException(NimbleError, "Could not get default file path.")
|
|
||||||
fName = pkgName & NimsExt
|
|
||||||
|
|
||||||
# Now need to write out .nimble file with projName and other details
|
validatePackageName(nimbleFile.changeFileExt(""))
|
||||||
|
|
||||||
if (not existsFile(os.getCurrentDir() / fName) and
|
if existsFile(os.getCurrentDir() / nimbleFile):
|
||||||
open(f=outFile, filename = fName, mode = fmWrite)):
|
raise newException(NimbleError, "Nimble file already exists.")
|
||||||
|
|
||||||
|
# Ask for package version.
|
||||||
|
let pkgVersion = promptCustom("Enter intial version of package", "0.1.0")
|
||||||
|
validateVersion(pkgVersion)
|
||||||
|
|
||||||
|
# Ask for package author
|
||||||
|
var defaultAuthor = "Anonymous"
|
||||||
|
if findExe("git") != "":
|
||||||
|
let (name, exitCode) = doCmdEx("git config --global user.name")
|
||||||
|
if exitCode == QuitSuccess and name.len > 0:
|
||||||
|
defaultAuthor = name.strip()
|
||||||
|
elif defaultAuthor == "Anonymous" and findExe("hg") != "":
|
||||||
|
let (name, exitCode) = doCmdEx("hg config ui.username")
|
||||||
|
if exitCode == QuitSuccess and name.len > 0:
|
||||||
|
defaultAuthor = name.strip()
|
||||||
|
let pkgAuthor = promptCustom("Enter your name", defaultAuthor)
|
||||||
|
|
||||||
|
# Ask for description
|
||||||
|
let pkgDesc = promptCustom("Enter package description", "")
|
||||||
|
|
||||||
|
# Ask for license
|
||||||
|
# TODO: Provide selection of licenses, or select random default license.
|
||||||
|
let pkgLicense = promptCustom("Enter package license", "MIT")
|
||||||
|
|
||||||
|
# Ask for Nim dependency
|
||||||
|
let nimDepDef = getNimrodVersion()
|
||||||
|
let pkgNimDep = promptCustom("Enter lowest supported Nim version", $nimDepDef)
|
||||||
|
validateVersion(pkgNimDep)
|
||||||
|
|
||||||
|
# Now generate the .nimble file.
|
||||||
|
if existsFile(os.getCurrentDir() / nimbleFile):
|
||||||
|
raise newException(NimbleError,
|
||||||
|
"Looks like a Nimble file has already been created.")
|
||||||
|
|
||||||
|
var outFile: File
|
||||||
|
if open(f = outFile, filename = nimbleFile, mode = fmWrite):
|
||||||
outFile.writeLine """# Package
|
outFile.writeLine """# Package
|
||||||
|
|
||||||
version = "1.0.0"
|
version = $#
|
||||||
author = $1
|
author = $#
|
||||||
description = "New Nimble project for Nim"
|
description = $#
|
||||||
license = "MIT"
|
license = $#
|
||||||
|
|
||||||
# Dependencies
|
# Dependencies
|
||||||
|
|
||||||
requires "nim >= 0.11.2"
|
requires "nim >= $#"
|
||||||
""" % guessAuthor().escape()
|
""" % [pkgVersion.escape(), pkgAuthor.escape(), pkgDesc.escape(),
|
||||||
|
pkgLicense.escape(), pkgNimDep]
|
||||||
close(outFile)
|
close(outFile)
|
||||||
else:
|
else:
|
||||||
raise newException(NimbleError, "Unable to open file " & fName &
|
raise newException(NimbleError, "Unable to open file " & nimbleFile &
|
||||||
" for writing: " & osErrorMsg(osLastError()))
|
" for writing: " & osErrorMsg(osLastError()))
|
||||||
|
|
||||||
proc uninstall(options: Options) =
|
proc uninstall(options: Options) =
|
||||||
|
|
|
||||||
2
src/nimblepkg/nim.cfg
Normal file
2
src/nimblepkg/nim.cfg
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
--path:"$nim/"
|
||||||
|
--path:"$lib/packages/docutils"
|
||||||
|
|
@ -86,6 +86,8 @@ proc cleanup() =
|
||||||
# ensure everything can be called again:
|
# ensure everything can be called again:
|
||||||
resetAllModulesHard()
|
resetAllModulesHard()
|
||||||
clearPasses()
|
clearPasses()
|
||||||
|
msgs.gErrorMax = 1
|
||||||
|
msgs.writeLnHook = nil
|
||||||
vm.globalCtx = nil
|
vm.globalCtx = nil
|
||||||
initDefines()
|
initDefines()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,6 @@ import version, tools, nimbletypes, nimscriptsupport
|
||||||
when not declared(system.map):
|
when not declared(system.map):
|
||||||
from sequtils import map
|
from sequtils import map
|
||||||
|
|
||||||
const
|
|
||||||
NimsExt* = ".nims"
|
|
||||||
|
|
||||||
type
|
type
|
||||||
Package* = object
|
Package* = object
|
||||||
# Required fields in a package.
|
# Required fields in a package.
|
||||||
|
|
@ -48,6 +45,47 @@ proc initPackageInfo(path: string): PackageInfo =
|
||||||
result.binDir = ""
|
result.binDir = ""
|
||||||
result.backend = "c"
|
result.backend = "c"
|
||||||
|
|
||||||
|
proc validatePackageName*(name: string) =
|
||||||
|
## Raises an error if specified package name contains invalid characters.
|
||||||
|
##
|
||||||
|
## A valid package name is one which is a valid nim module name. So only
|
||||||
|
## underscores, letters and numbers allowed.
|
||||||
|
if name.len == 0: return
|
||||||
|
|
||||||
|
if name[0] in {'0'..'9'}:
|
||||||
|
raise newException(NimbleError,
|
||||||
|
"Invalid package name: cannot beging with " & name[0])
|
||||||
|
|
||||||
|
var prevWasUnderscore = false
|
||||||
|
for c in name:
|
||||||
|
case c
|
||||||
|
of '_':
|
||||||
|
if prevWasUnderscore:
|
||||||
|
raise newException(NimbleError,
|
||||||
|
"Invalid package name: cannot contain \"__\"")
|
||||||
|
prevWasUnderscore = true
|
||||||
|
of AllChars - IdentChars:
|
||||||
|
raise newException(NimbleError,
|
||||||
|
"Invalid package name: cannot contain '$1'" % $c)
|
||||||
|
else:
|
||||||
|
prevWasUnderscore = false
|
||||||
|
|
||||||
|
proc toValidPackageName*(name: string): string =
|
||||||
|
result = ""
|
||||||
|
for c in name:
|
||||||
|
case c
|
||||||
|
of '_', '-':
|
||||||
|
if result[^1] != '_': result.add('_')
|
||||||
|
of AllChars - IdentChars - {'-'}: discard
|
||||||
|
else: result.add(c)
|
||||||
|
|
||||||
|
proc validateVersion*(ver: string) =
|
||||||
|
for c in ver:
|
||||||
|
if c notin ({'.'} + Digits):
|
||||||
|
raise newException(NimbleError,
|
||||||
|
"Version may only consist of numbers and the '.' character " &
|
||||||
|
"but found '" & c & "'.")
|
||||||
|
|
||||||
proc validatePackageInfo(pkgInfo: PackageInfo, path: string) =
|
proc validatePackageInfo(pkgInfo: PackageInfo, path: string) =
|
||||||
if pkgInfo.name == "":
|
if pkgInfo.name == "":
|
||||||
raise newException(NimbleError, "Incorrect .nimble file: " & path &
|
raise newException(NimbleError, "Incorrect .nimble file: " & path &
|
||||||
|
|
@ -67,11 +105,7 @@ proc validatePackageInfo(pkgInfo: PackageInfo, path: string) =
|
||||||
if pkgInfo.backend notin ["c", "cc", "objc", "cpp", "js"]:
|
if pkgInfo.backend notin ["c", "cc", "objc", "cpp", "js"]:
|
||||||
raise newException(NimbleError, "'" & pkgInfo.backend &
|
raise newException(NimbleError, "'" & pkgInfo.backend &
|
||||||
"' is an invalid backend.")
|
"' is an invalid backend.")
|
||||||
for c in pkgInfo.version:
|
validateVersion(pkgInfo.version)
|
||||||
if c notin ({'.'} + Digits):
|
|
||||||
raise newException(NimbleError,
|
|
||||||
"Version may only consist of numbers and the '.' character " &
|
|
||||||
"but found '" & c & "'.")
|
|
||||||
|
|
||||||
if not pkgInfo.isNimScript:
|
if not pkgInfo.isNimScript:
|
||||||
# TODO: Turn this into a warning.
|
# TODO: Turn this into a warning.
|
||||||
|
|
@ -395,3 +429,16 @@ when isMainModule:
|
||||||
("packagea", "0.1")
|
("packagea", "0.1")
|
||||||
doAssert getNameVersion("/home/user/.nimble/libs/package-a-0.1") ==
|
doAssert getNameVersion("/home/user/.nimble/libs/package-a-0.1") ==
|
||||||
("package-a", "0.1")
|
("package-a", "0.1")
|
||||||
|
|
||||||
|
validatePackageName("foo_bar")
|
||||||
|
validatePackageName("f_oo_b_a_r")
|
||||||
|
try:
|
||||||
|
validatePackageName("foo__bar")
|
||||||
|
assert false
|
||||||
|
except NimbleError:
|
||||||
|
assert true
|
||||||
|
|
||||||
|
doAssert toValidPackageName("foo__bar") == "foo_bar"
|
||||||
|
doAssert toValidPackageName("jhbasdh!£$@%#^_&*_()qwe") == "jhbasdh_qwe"
|
||||||
|
|
||||||
|
echo("All tests passed!")
|
||||||
Loading…
Add table
Add a link
Reference in a new issue