summary refs log tree commit diff stats
path: root/tools/nimresolve.nim
diff options
context:
space:
mode:
authorAndreas Rumpf <rumpf_a@web.de>2017-10-02 08:31:38 +0200
committerAndreas Rumpf <rumpf_a@web.de>2017-10-02 08:31:38 +0200
commite9243a16167b24899d4fcf051f3252b3a5804811 (patch)
treedc4733a6f178d4f04ee4da33c50ca807eb7e9dd0 /tools/nimresolve.nim
parentfc7961d4ccd31ab6e7eabbeb7aa22b5488924b4f (diff)
parent02ff5f596c330b68927f843814ecb9b86c2eee67 (diff)
downloadNim-e9243a16167b24899d4fcf051f3252b3a5804811.tar.gz
Merge branch 'devel' into araq
Diffstat (limited to 'tools/nimresolve.nim')
-rw-r--r--tools/nimresolve.nim158
1 files changed, 158 insertions, 0 deletions
diff --git a/tools/nimresolve.nim b/tools/nimresolve.nim
new file mode 100644
index 000000000..9af24df5a
--- /dev/null
+++ b/tools/nimresolve.nim
@@ -0,0 +1,158 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2017 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## Standard tool that resolves import paths.
+
+import
+  os, strutils, parseopt
+
+import "../compiler/nimblecmd"
+
+# You can change these constants to build you own adapted resolver.
+const
+  considerParentDirs = not defined(noParentProjects)
+  considerNimbleDirs = not defined(noNimbleDirs)
+
+const
+  Version = "1.0"
+  Usage = "nimresolve - Nim Resolve Package Path Version " & Version & """
+
+  (c) 2017 Andreas Rumpf
+Usage:
+  nimresolve [options] package
+Options:
+  --source:FILE       the file that requests to resolve 'package'
+  --stdlib:PATH       the path to use for the standard library
+  --project:FILE      the main '.nim' file that was passed to the Nim compiler
+  --subdir:EXPR       the subdir part in: 'import $pkg / subdir'
+  --noNimblePath      do not search the Nimble path to resolve the package
+"""
+
+proc writeHelp() =
+  stdout.write(Usage)
+  stdout.flushFile()
+  quit(0)
+
+proc writeVersion() =
+  stdout.write(Version & "\n")
+  stdout.flushFile()
+  quit(0)
+
+type
+  Task = object
+    source, stdlib, subdir, project, pkg: string
+    noNimblePath: bool
+
+proc findInNimbleDir(t: Task; dir: string): bool =
+  var best = ""
+  var bestv = ""
+  for k, p in os.walkDir(dir, relative=true):
+    if k == pcDir and p.len > t.pkg.len+1 and
+        p[t.pkg.len] == '-' and p.startsWith(t.pkg):
+      let (_, a) = getPathVersion(p)
+      if bestv.len == 0 or bestv < a:
+        bestv = a
+        best = dir / p
+
+  if best.len > 0:
+    var f: File
+    if open(f, best / changeFileExt(t.pkg, ".nimble-link")):
+      # the second line contains what we're interested in, see:
+      # https://github.com/nim-lang/nimble#nimble-link
+      var override = ""
+      discard readLine(f, override)
+      discard readLine(f, override)
+      close(f)
+      if not override.isAbsolute():
+        best = best / override
+      else:
+        best = override
+  let f = if t.subdir.len == 0: t.pkg else: t.subdir
+  let res = addFileExt(best / f, "nim")
+  if best.len > 0 and fileExists(res):
+    echo res
+    result = true
+
+const stdlibDirs = [
+  "pure", "core", "arch",
+  "pure/collections",
+  "pure/concurrency", "impure",
+  "wrappers", "wrappers/linenoise",
+  "windows", "posix", "js"]
+
+proc resolve(t: Task) =
+  template attempt(a) =
+    let x = addFileExt(a, "nim")
+    if fileExists(x):
+      echo x
+      return
+
+  case t.pkg
+  of "stdlib":
+    if t.subdir.len == 0:
+      echo t.stdlib
+      return
+    else:
+      for candidate in stdlibDirs:
+        attempt(t.stdlib / candidate / t.subdir)
+  of "root":
+    let root = t.project.splitFile.dir
+    if t.subdir.len == 0:
+      echo root
+      return
+    else:
+      attempt(root / t.subdir)
+  else:
+    when considerParentDirs:
+      var p = parentDir(t.source.splitFile.dir)
+      # support 'import $karax':
+      let f = if t.subdir.len == 0: t.pkg else: t.subdir
+
+      while p.len > 0:
+        let dir = p / t.pkg
+        if dirExists(dir):
+          attempt(dir / f)
+          # 2nd attempt: try to use 'karax/karax'
+          attempt(dir / t.pkg / f)
+          # 3rd attempt: try to use 'karax/src/karax'
+          attempt(dir / "src" / f)
+          attempt(dir / "src" / t.pkg / f)
+        p = parentDir(p)
+
+    when considerNimbleDirs:
+      if not t.noNimblePath:
+        if findInNimbleDir(t, getHomeDir() / ".nimble" / "pkgs"): return
+        when not defined(windows):
+          if findInNimbleDir(t, "/opt/nimble/pkgs"): return
+
+  quit "cannot resolve: " & (t.pkg / t.subdir)
+
+proc main =
+  var t: Task
+  t.subdir = ""
+  for kind, key, val in getopt():
+    case kind
+    of cmdArgument:
+      t.pkg = key
+    of cmdLongoption, cmdShortOption:
+      case normalize(key)
+      of "source": t.source = val
+      of "stdlib": t.stdlib = val
+      of "project": t.project = val
+      of "subdir": t.subdir = val
+      of "nonimblepath": t.noNimblePath = true
+      of "help", "h": writeHelp()
+      of "version", "v": writeVersion()
+      else: writeHelp()
+    of cmdEnd: assert(false) # cannot happen
+  if t.pkg.len == 0:
+    quit "[Error] no package to resolve."
+  resolve(t)
+
+main()