aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGanesh Viswanathan <dev@genotrance.com>2019-12-21 23:29:57 -0600
committerGanesh Viswanathan <dev@genotrance.com>2019-12-21 23:29:57 -0600
commit53cb044257bf8857caff3d5cbdfb06b6e43fd400 (patch)
tree76a2287b7eb0dd5409f77784c8c7db8e6cdf0aa7
parenta2847d77f080c9c429db6ea9b0e5d9f34e4ce15b (diff)
downloadnimterop-53cb044257bf8857caff3d5cbdfb06b6e43fd400.tar.gz
nimterop-53cb044257bf8857caff3d5cbdfb06b6e43fd400.zip
Fix #144 - nimcheck/nimsuggest support
-rw-r--r--nimterop/build.nim114
-rw-r--r--nimterop/cimport.nim18
-rw-r--r--nimterop/getters.nim2
3 files changed, 86 insertions, 48 deletions
diff --git a/nimterop/build.nim b/nimterop/build.nim
index d91472c..bd0a0b1 100644
--- a/nimterop/build.nim
+++ b/nimterop/build.nim
@@ -1,4 +1,4 @@
-import macros, osproc, sets, strformat, strutils, tables
+import hashes, macros, osproc, sets, strformat, strutils, tables
import os except findExe, sleep
@@ -18,17 +18,33 @@ proc sleep*(milsecs: int) =
else:
"sleep "
- (oup, ret) = gorgeEx(cmd & $(milsecs / 1000))
+ discard gorgeEx(cmd & $(milsecs / 1000))
-proc execAction*(cmd: string, retry = 0, nostderr = false): string =
+proc getOsCacheDir(): string =
+ when defined(posix):
+ result = getEnv("XDG_CACHE_HOME", getHomeDir() / ".cache") / "nim"
+ else:
+ result = getHomeDir() / "nimcache"
+
+proc getNimteropCacheDir(): string =
+ result = getOsCacheDir() / "nimterop"
+
+proc execAction*(cmd: string, retry = 0, die = true, cache = false,
+ cacheKey = ""): tuple[output: string, ret: int] =
## Execute an external command - supported at compile time
##
## Checks if command exits successfully before returning. If not, an
- ## error is raised.
+ ## error is raised. Always caches results to be used in nimsuggest or nimcheck
+ ## mode.
+ ##
+ ## `retry` - number of times command should be retried before error
+ ## `die = false` - return on errors
+ ## `cache = true` - cache results unless cleared with -f
+ ## `cacheKey` - key to create unique cache entry
var
ccmd = ""
- ret = 0
when defined(Windows):
+ # Replace 'cd d:\abc' with 'd: && cd d:\abc`
var filteredCmd = cmd
if cmd.toLower().startsWith("cd"):
var
@@ -45,16 +61,44 @@ proc execAction*(cmd: string, retry = 0, nostderr = false): string =
doAssert false
when nimvm:
- (result, ret) = gorgeEx(ccmd)
+ # Cache results for speedup if cache = true
+ # Else cache for preserving functionality in nimsuggest and nimcheck
+ let
+ hash = (ccmd & cacheKey).hash().abs()
+ cacheFile = getNimteropCacheDir() / "execCache" / "nimterop_" & $hash & ".txt"
+
+ when defined(nimsuggest) or defined(nimcheck):
+ # Load results from cache file if generated in previous run
+ if fileExists(cacheFile):
+ result.output = cacheFile.readFile()
+ elif die:
+ doAssert false, "Results not cached - run nim c/cpp at least once\n" & ccmd
+ else:
+ if cache and fileExists(cacheFile) and not compileOption("forceBuild"):
+ # Return from cache when requested
+ result.output = cacheFile.readFile()
+ else:
+ # Execute command and store results in cache
+ (result.output, result.ret) = gorgeEx(ccmd)
+ if result.ret == 0:
+ # mkdir for execCache dir (circular dependency)
+ let dir = cacheFile.parentDir()
+ if not dirExists(dir):
+ let flag = when not defined(Windows): "-p" else: ""
+ discard execAction(&"mkdir {flag} {dir.sanitizePath}")
+ cacheFile.writeFile(result.output)
else:
- let opt = if nostderr: {poUsePath} else: {poStdErrToStdOut, poUsePath}
- (result, ret) = execCmdEx(ccmd, opt)
- if ret != 0:
+ # Used by toast
+ (result.output, result.ret) = execCmdEx(ccmd)
+
+ # On failure, retry or die as requested
+ if result.ret != 0:
if retry > 0:
sleep(500)
- result = execAction(cmd, retry = retry - 1)
- else:
- doAssert false, "Command failed: " & $(ret, nostderr) & "\ncmd: " & ccmd & "\nresult:\n" & result
+ result = execAction(cmd, retry = retry - 1, die, cache, cacheKey)
+ elif die:
+ doAssert false, "Command failed: " & $result.ret & "\ncmd: " & ccmd &
+ "\nresult:\n" & result.output
proc findExe*(exe: string): string =
## Find the specified executable using the `which`/`where` command - supported
@@ -66,10 +110,10 @@ proc findExe*(exe: string): string =
else:
"which " & exe
- (oup, code) = gorgeEx(cmd)
+ (output, ret) = execAction(cmd, die = false)
- if code == 0:
- return oup.splitLines()[0].strip()
+ if ret == 0:
+ return output.splitLines()[0].strip()
proc mkDir*(dir: string) =
## Create a directory at compile time
@@ -129,15 +173,6 @@ proc rmDir*(dir: string) =
## Remove a directory or pattern at compile time
rmFile(dir, dir = true)
-proc getOsCacheDir(): string =
- when defined(posix):
- result = getEnv("XDG_CACHE_HOME", getHomeDir() / ".cache") / "nim"
- else:
- result = getHomeDir() / "nimcache"
-
-proc getNimteropCacheDir(): string =
- result = getOsCacheDir() / "nimterop"
-
proc getProjectCacheDir*(name: string, forceClean = true): string =
## Get a cache directory where all nimterop artifacts can be stored
##
@@ -248,7 +283,7 @@ proc gitReset*(outdir: string) =
echo "# Resetting " & outdir
let cmd = &"cd {outdir.sanitizePath} && git reset --hard"
- while execAction(cmd).contains("Permission denied"):
+ while execAction(cmd).output.contains("Permission denied"):
sleep(1000)
echo "# Retrying ..."
@@ -261,7 +296,7 @@ proc gitCheckout*(file, outdir: string) =
echo "# Resetting " & file
let file2 = file.relativePath outdir
let cmd = &"cd {outdir.sanitizePath} && git checkout {file2.sanitizePath}"
- while execAction(cmd).contains("Permission denied"):
+ while execAction(cmd).output.contains("Permission denied"):
sleep(500)
echo "# Retrying ..."
@@ -344,7 +379,7 @@ proc findFile*(file: string, dir: string, recurse = true, first = false, regex =
cmd = cmd % [recursive, (".*[\\\\/]" & file & "$").quoteShell, dir.sanitizePath]
let
- (files, ret) = gorgeEx(cmd)
+ (files, ret) = execAction(cmd, die = false)
if ret == 0:
for line in files.splitLines():
let f =
@@ -386,7 +421,7 @@ proc linkLibs*(names: openArray[string], staticLink = true): string =
for name in names:
let
cmd = &"pkg-config --libs --silence-errors {stat} lib{name}"
- libs = gorge(cmd)
+ (libs, _) = execAction(cmd, die = false)
for lib in libs.split(" "):
resSet.incl lib
@@ -421,7 +456,8 @@ proc configure*(path, check: string, flags = "") =
if fileExists(path / i):
echo "# Running autogen.sh"
- echo execAction(&"cd {(path / i).parentDir().sanitizePath} && bash autogen.sh")
+ echo execAction(
+ &"cd {(path / i).parentDir().sanitizePath} && bash autogen.sh").output
break
@@ -430,7 +466,7 @@ proc configure*(path, check: string, flags = "") =
if fileExists(path / i):
echo "# Running autoreconf"
- echo execAction(&"cd {path.sanitizePath} && autoreconf -fi")
+ echo execAction(&"cd {path.sanitizePath} && autoreconf -fi").output
break
@@ -442,7 +478,7 @@ proc configure*(path, check: string, flags = "") =
if flags.len != 0:
cmd &= &" {flags}"
- echo execAction(cmd)
+ echo execAction(cmd).output
doAssert (path / check).fileExists(), "# Configure failed"
@@ -539,7 +575,7 @@ proc cmake*(path, check, flags: string) =
var
cmd = &"cd {path.sanitizePath} && cmake {flags}"
- echo execAction(cmd)
+ echo execAction(cmd).output
doAssert (path / check).fileExists(), "# cmake failed"
@@ -575,7 +611,7 @@ proc make*(path, check: string, flags = "", regex = false) =
if flags.len != 0:
cmd &= &" {flags}"
- echo execAction(cmd)
+ echo execAction(cmd).output
doAssert findFile(check, path, regex = regex).len != 0, "# make failed"
@@ -597,7 +633,7 @@ proc getGccPaths*(mode = "c"): seq[string] =
mmode = if mode == "cpp": "c++" else: mode
inc = false
- (outp, _) = gorgeEx(&"""{getCompiler()} -Wp,-v -x{mmode} {nul}""")
+ (outp, _) = execAction(&"""{getCompiler()} -Wp,-v -x{mmode} {nul}""", die = false)
for line in outp.splitLines():
if "#include <...> search starts here" in line:
@@ -612,7 +648,7 @@ proc getGccPaths*(mode = "c"): seq[string] =
result.add path
when defined(osx):
- result.add execAction("xcrun --show-sdk-path").strip() & "/usr/include"
+ result.add(execAction("xcrun --show-sdk-path").output.strip() & "/usr/include")
proc getGccLibPaths*(mode = "c"): seq[string] =
var
@@ -620,7 +656,7 @@ proc getGccLibPaths*(mode = "c"): seq[string] =
mmode = if mode == "cpp": "c++" else: mode
linker = when defined(OSX): "-Xlinker" else: ""
- (outp, _) = gorgeEx(&"""{getCompiler()} {linker} -v -x{mmode} {nul}""")
+ (outp, _) = execAction(&"""{getCompiler()} {linker} -v -x{mmode} {nul}""", die = false)
for line in outp.splitLines():
if "LIBRARY_PATH=" in line:
@@ -699,9 +735,9 @@ proc getNumProcs(): string =
when defined(windows):
getEnv("NUMBER_OF_PROCESSORS").strip()
elif defined(linux):
- execAction("nproc").strip()
+ execAction("nproc").output.strip()
elif defined(macosx):
- execAction("sysctl -n hw.ncpu").strip()
+ execAction("sysctl -n hw.ncpu").output.strip()
else:
"1"
@@ -727,7 +763,7 @@ proc buildLibrary(lname, outdir, conFlags, cmakeFlags, makeFlags: string): strin
when defined(windows):
if findExe("sh").len != 0:
let
- uname = execAction("sh -c uname -a").toLowerAscii()
+ uname = execAction("sh -c uname -a").output.toLowerAscii()
if uname.contains("msys"):
gen = "MSYS Makefiles".quoteShell
elif uname.contains("mingw"):
diff --git a/nimterop/cimport.nim b/nimterop/cimport.nim
index c13ce1f..6b2d153 100644
--- a/nimterop/cimport.nim
+++ b/nimterop/cimport.nim
@@ -69,7 +69,7 @@ proc walkDirImpl(indir, inext: string, file=true): seq[string] =
else:
"find $1 -type d" % dir
- (output, ret) = gorgeEx(cmd)
+ (output, ret) = execAction(cmd, die = false)
if ret == 0:
result = output.splitLines()
@@ -85,9 +85,7 @@ proc getFileDate(fullpath: string): string =
elif defined(OSX):
&"stat -f %m {fullpath.sanitizePath}"
- (result, ret) = gorgeEx(cmd)
-
- doAssert ret == 0, "File date error: " & fullpath & "\n" & result
+ (result, ret) = execAction(cmd)
proc getCacheValue(fullpath: string): string =
if not gStateCT.nocache:
@@ -116,7 +114,10 @@ proc getNimCheckError(output: string): tuple[tmpFile, errors: string] =
doAssert fileExists(result.tmpFile), "Failed to write to cache dir: " & result.tmpFile
let
- (check, _) = gorgeEx(&"{getCurrentCompilerExe()} check {result.tmpFile.sanitizePath}")
+ (check, _) = execAction(
+ &"{getCurrentCompilerExe()} check {result.tmpFile.sanitizePath}",
+ die = false
+ )
result.errors = "\n\n" & check
@@ -160,7 +161,8 @@ proc getToast(fullpath: string, recurse: bool = false, dynlib: string = "",
cmd.add &" {fullpath.sanitizePath}"
# see https://github.com/nimterop/nimterop/issues/69
- (result, ret) = gorgeEx(cmd, cache=getCacheValue(fullpath))
+ (result, ret) = execAction(cmd, die = false, cache = (not gStateCT.nocache),
+ cacheKey = getCacheValue(fullpath))
doAssert ret == 0, getToastError(result)
macro cOverride*(body): untyped =
@@ -668,8 +670,8 @@ macro c2nImport*(filename: static string, recurse: static bool = false, dynlib:
cmd.add &" --assumedef:{i.quoteShell}"
let
- (c2nimout, ret) = gorgeEx(cmd, cache=getCacheValue(hpath))
- doAssert ret == 0, "Command failed:\n " & cmd & "\n\n" & c2nimout
+ (c2nimout, ret) = execAction(cmd, cache = not gStateCT.nocache,
+ cacheKey = getCacheValue(hpath))
var
nimout = &"const {header} = \"{fullpath}\"\n\n" & readFile(npath)
diff --git a/nimterop/getters.nim b/nimterop/getters.nim
index 4cf5653..ef647e6 100644
--- a/nimterop/getters.nim
+++ b/nimterop/getters.nim
@@ -261,7 +261,7 @@ proc getPreprocessor*(gState: State, fullpath: string, mode = "cpp"): string =
cmd &= &"{fullpath.sanitizePath}"
# Include content only from file
- for line in execAction(cmd).splitLines():
+ for line in execAction(cmd).output.splitLines():
if line.strip() != "":
if line.len > 1 and line[0 .. 1] == "# ":
start = false