From 9bcabd23e3c542937e12b25aae94f6eb43ff75c4 Mon Sep 17 00:00:00 2001 From: Ganesh Viswanathan Date: Thu, 16 Nov 2017 02:39:48 -0600 Subject: [PATCH] - Docopt for CLI parsing - Download, extract and Git checkout support - OS specific keys with -win, -lin and -osx - Force re-generation with -f flag --- README.md | 22 ++++- nimgen.nim | 190 +++++++++++++++++++++++++++++++++--------- nimgen.nimble | 4 +- tests/nimgentest.nims | 7 +- 4 files changed, 173 insertions(+), 50 deletions(-) diff --git a/README.md b/README.md index f1e9d1b..ea57fa4 100644 --- a/README.md +++ b/README.md @@ -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] diff --git a/nimgen.nim b/nimgen.nim index f085283..6f6998f 100644 --- a/nimgen.nim +++ b/nimgen.nim @@ -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] ... + +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[""]: + runcfg(i) diff --git a/nimgen.nimble b/nimgen.nimble index af6e501..6a10fdd 100644 --- a/nimgen.nimble +++ b/nimgen.nimble @@ -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"] diff --git a/tests/nimgentest.nims b/tests/nimgentest.nims index 693d133..c5644d0 100644 --- a/tests/nimgentest.nims +++ b/tests/nimgentest.nims @@ -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"