- Docopt for CLI parsing

- Download, extract and Git checkout support
- OS specific keys with -win, -lin and -osx
- Force re-generation with -f flag
This commit is contained in:
Ganesh Viswanathan 2017-11-16 02:39:48 -06:00
commit 9bcabd23e3
4 changed files with 173 additions and 50 deletions

View file

@ -38,11 +38,11 @@ __Config file__
_[n.global]_
output = name of the Nimble project once installed, also location to place generated .nim files
```output``` = name of the Nimble project once installed, also location to place generated .nim files
quotes = pick up any headers included using "" (and not <> which is typically used for standard headers) [default: true]
```quotes``` = pick up any headers included using "" (and not <> which is typically used for standard headers) [default: true]
filter = string to identify and recurse into library .h files in #include statements and exclude standard headers
```filter``` = string to identify and recurse into library .h files in #include statements and exclude standard headers
_[n.include]_
@ -56,9 +56,23 @@ _[n.exclude]_
List of all directories or files to exclude from all parsing. If an entry here matches any portion of a file, it is excluded from recursive processing.
_[n.prepare]_
The following keys can be used to prepare dependencies such as downloading ZIP files, cloning Git repositories, etc. Multiple entries are possible by appending any .string to the key. E.g. download.file1. -win, -lin and -osx can be used for OS specific tasks. E.g. download-win
```download``` = url to download to the output directory. ZIP files are automatically extracted. Files are not redownloaded if already present but re-extracted
```git``` = url of Git repository to clone. Full repo is pulled so gitremote + gitsparse is preferable. Resets to HEAD if already present
```gitremote``` = url of Git repository to partially checkout. Use with gitsparse to pull only files and dirs of interest
```gitsparse``` = list of files and/or dirs to include in partial checkout, one per line. Resets to HEAD if already present
```execute``` = command to run during preparation
_[sourcefile]_
The following keys apply to library source code and help with generating the .nim files.
The following keys apply to library source code and help with generating the .nim files. -win, -lin and -osx can be used for OS specific tasks. E.g. dynlib-win
```recurse``` = find #include files and process them [default: false]

View file

@ -1,3 +1,4 @@
import docopt
import nre
import os
import ospaths
@ -18,6 +19,18 @@ var OUTPUT = ""
var INCLUDES: seq[string] = @[]
var EXCLUDES: seq[string] = @[]
const DOC = """
Nimgen is a helper for c2nim to simpilfy and automate the wrapping of C libraries
Usage:
nimgen [options] <file.cfg>...
Options:
-f delete all artifacts and regenerate
"""
let ARGS = docopt(DOC)
# ###
# Helpers
@ -38,7 +51,88 @@ proc execProc(cmd: string): string =
echo "Command failed: " & $x
echo cmd
echo result
quit()
quit(1)
proc extractZip(zipfile: string) =
var cmd = "unzip $#"
if defined(Windows):
cmd = "powershell -nologo -noprofile -command \"& { Add-Type -A 'System.IO.Compression.FileSystem'; [IO.Compression.ZipFile]::ExtractToDirectory('$#', '.'); }\""
setCurrentDir(OUTPUT)
defer: setCurrentDir("..")
echo "Extracting " & zipfile
discard execProc(cmd % zipfile)
proc downloadUrl(url: string) =
let file = url.extractFilename()
let ext = file.splitFile().ext.toLowerAscii()
var cmd = "curl $# -o $#"
if defined(Windows):
cmd = "powershell wget $# -OutFile $#"
if not (ext == ".zip" and fileExists(OUTPUT/file)):
echo "Downloading " & file
createDir(OUTPUT)
discard execProc(cmd % [url, OUTPUT/file])
if ext == ".zip":
extractZip(file)
proc gitReset() =
echo "Resetting Git repo"
setCurrentDir(OUTPUT)
defer: setCurrentDir("..")
discard execProc("git reset --hard HEAD")
proc gitRemotePull(url: string, pull=true) =
if dirExists(OUTPUT):
if pull:
gitReset()
return
createDir(OUTPUT)
setCurrentDir(OUTPUT)
defer: setCurrentDir("..")
echo "Setting up Git repo"
discard execProc("git init .")
discard execProc("git remote add origin " & url)
if pull:
echo "Checking out artifacts"
discard execProc("git pull --depth=1 origin master")
proc gitSparseCheckout(plist: string) =
let sparsefile = ".git/info/sparse-checkout"
if fileExists(OUTPUT/sparsefile):
gitReset()
return
setCurrentDir(OUTPUT)
defer: setCurrentDir("..")
discard execProc("git config core.sparsecheckout true")
writeFile(sparsefile, plist)
echo "Checking out artifacts"
discard execProc("git pull --depth=1 origin master")
proc getKey(ukey: string): tuple[key: string, val: bool] =
var kv = ukey.replace(re"\..*", "").split("-", 1)
if kv.len() == 1:
kv.add("")
if (kv[1] == "") or
(kv[1] == "win" and defined(Windows)) or
(kv[1] == "lin" and defined(Linux)) or
(kv[1] == "osx" and defined(MacOSX)):
return (kv[0], true)
return (kv[0], false)
# ###
# File loction
@ -72,7 +166,7 @@ proc search(file: string): string =
break
if not found:
echo "File doesn't exist: " & file
quit()
quit(1)
return result.replace(re"[\\/]", $DirSep)
@ -275,18 +369,19 @@ proc c2nim(fl, outfile, flags, ppflags: string, recurse, preproc, ctag, define:
var winlib, linlib, osxlib: string = ""
for dl in dynlib:
let lib = " const dynlib$# = \"$#\"\n" % [fname, dl]
if dl.splitFile().ext == ".dll":
let ext = dl.splitFile().ext
if ext == ".dll":
winlib &= lib
if dl.splitFile().ext == ".so":
elif ext == ".so":
linlib &= lib
if dl.splitFile().ext == ".dylib":
elif ext == ".dylib":
osxlib &= lib
if winlib != "":
outlib &= win & winlib & "\n"
if linlib != "":
outlib &= lin & linlib & "\n"
if winlib != "":
if osxlib != "":
outlib &= osx & osxlib & "\n"
if outlib != "":
@ -336,13 +431,17 @@ proc c2nim(fl, outfile, flags, ppflags: string, recurse, preproc, ctag, define:
proc runcfg(cfg: string) =
if not fileExists(cfg):
echo "Config doesn't exist: " & cfg
quit()
quit(1)
CONFIG = loadConfig(cfg)
if CONFIG.hasKey("n.global"):
if CONFIG["n.global"].hasKey("output"):
OUTPUT = CONFIG["n.global"]["output"]
if ARGS["-f"]:
removeDir(OUTPUT)
if CONFIG["n.global"].hasKey("filter"):
FILTER = CONFIG["n.global"]["filter"]
if CONFIG["n.global"].hasKey("quotes"):
@ -357,42 +456,57 @@ proc runcfg(cfg: string) =
for excl in CONFIG["n.exclude"].keys():
EXCLUDES.add(excl)
if CONFIG.hasKey("n.prepare"):
for prep in CONFIG["n.prepare"].keys():
let (key, val) = getKey(prep)
if val == true:
if key == "download":
downloadUrl(CONFIG["n.prepare"][prep])
elif key == "git":
gitRemotePull(CONFIG["n.prepare"][prep])
elif key == "gitremote":
gitRemotePull(CONFIG["n.prepare"][prep], false)
elif key == "gitsparse":
gitSparseCheckout(CONFIG["n.prepare"][prep])
elif key == "execute":
discard execProc(CONFIG["n.prepare"][prep])
for file in CONFIG.keys():
if file in @["n.global", "n.include", "n.exclude"]:
if file in @["n.global", "n.include", "n.exclude", "n.prepare"]:
continue
var sfile = search(file)
var srch = ""
var action = ""
var compile: seq[string] = @[]
var dynlib: seq[string] = @[]
for act in CONFIG[file].keys():
action = act.replace(re"\..*", "")
if action == "create":
createDir(file.splitPath().head)
writeFile(file, CONFIG[file][act])
elif action in @["prepend", "append", "replace", "compile", "dynlib"] and sfile != "":
if action == "prepend":
if srch != "":
prepend(sfile, CONFIG[file][act], CONFIG[file][srch])
else:
prepend(sfile, CONFIG[file][act])
elif action == "append":
if srch != "":
append(sfile, CONFIG[file][act], CONFIG[file][srch])
else:
append(sfile, CONFIG[file][act])
elif action == "replace":
if srch != "":
freplace(sfile, CONFIG[file][srch], CONFIG[file][act])
elif action == "compile":
compile.add(CONFIG[file][act])
elif action == "dynlib":
dynlib.add(CONFIG[file][act])
srch = ""
elif action == "search":
srch = act
let (action, val) = getKey(act)
if val == true:
if action == "create":
createDir(file.splitPath().head)
writeFile(file, CONFIG[file][act])
elif action in @["prepend", "append", "replace", "compile", "dynlib"] and sfile != "":
if action == "prepend":
if srch != "":
prepend(sfile, CONFIG[file][act], CONFIG[file][srch])
else:
prepend(sfile, CONFIG[file][act])
elif action == "append":
if srch != "":
append(sfile, CONFIG[file][act], CONFIG[file][srch])
else:
append(sfile, CONFIG[file][act])
elif action == "replace":
if srch != "":
freplace(sfile, CONFIG[file][srch], CONFIG[file][act])
elif action == "compile":
compile.add(CONFIG[file][act])
elif action == "dynlib":
dynlib.add(CONFIG[file][act])
srch = ""
elif action == "search":
srch = act
if file.splitFile().ext != ".nim":
var recurse = false
@ -426,9 +540,5 @@ proc runcfg(cfg: string) =
# ###
# Main loop
if paramCount() == 0:
echo "nimgen file.cfg"
quit()
for i in 1..paramCount():
runcfg(paramStr(i))
for i in ARGS["<file.cfg>"]:
runcfg(i)

View file

@ -1,6 +1,6 @@
# Package
version = "0.1.0"
version = "0.1.1"
author = "genotrance"
description = "c2nim helper to simpilfy and automate the wrapping of C libraries"
license = "MIT"
@ -9,7 +9,7 @@ skipDirs = @["tests"]
# Dependencies
requires "nim >= 0.16.0", "c2nim >= 0.9.13"
requires "nim >= 0.16.0", "c2nim >= 0.9.13", "docopt >= 0.6.5"
bin = @["nimgen"]

View file

@ -2,7 +2,6 @@ import ospaths
import strutils
for comp in @["nimbass", "nimfuzz", "nimssl"]:
cd(".."/comp)
exec "nimble install -y"
exec "nimble test"
cd(".."/"nimgen")
withDir(".."/comp):
exec "nimble install -y"
exec "nimble test"