scriptconfig.nim 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. #
  2. #
  3. # The Nim Compiler
  4. # (c) Copyright 2015 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. ## Implements the new configuration system for Nim. Uses Nim as a scripting
  10. ## language.
  11. import
  12. ast, modules, idents, passes, passaux, condsyms,
  13. options, nimconf, sem, semdata, llstream, vm, vmdef, commands, msgs,
  14. os, times, osproc, wordrecg, strtabs, modulegraphs, lineinfos, pathutils
  15. # we support 'cmpIgnoreStyle' natively for efficiency:
  16. from strutils import cmpIgnoreStyle, contains
  17. proc listDirs(a: VmArgs, filter: set[PathComponent]) =
  18. let dir = getString(a, 0)
  19. var result: seq[string] = @[]
  20. for kind, path in walkDir(dir):
  21. if kind in filter: result.add path
  22. setResult(a, result)
  23. proc setupVM*(module: PSym; cache: IdentCache; scriptName: string;
  24. graph: ModuleGraph): PEvalContext =
  25. # For Nimble we need to export 'setupVM'.
  26. result = newCtx(module, cache, graph)
  27. result.mode = emRepl
  28. registerAdditionalOps(result)
  29. let conf = graph.config
  30. # captured vars:
  31. var errorMsg: string
  32. var vthisDir = scriptName.splitFile.dir
  33. template cbconf(name, body) {.dirty.} =
  34. result.registerCallback "stdlib.system." & astToStr(name),
  35. proc (a: VmArgs) =
  36. body
  37. template cbos(name, body) {.dirty.} =
  38. result.registerCallback "stdlib.system." & astToStr(name),
  39. proc (a: VmArgs) =
  40. errorMsg = ""
  41. try:
  42. body
  43. except OSError:
  44. errorMsg = getCurrentExceptionMsg()
  45. # Idea: Treat link to file as a file, but ignore link to directory to prevent
  46. # endless recursions out of the box.
  47. cbos listFiles:
  48. listDirs(a, {pcFile, pcLinkToFile})
  49. cbos listDirs:
  50. listDirs(a, {pcDir})
  51. cbos removeDir:
  52. os.removeDir getString(a, 0)
  53. cbos removeFile:
  54. os.removeFile getString(a, 0)
  55. cbos createDir:
  56. os.createDir getString(a, 0)
  57. cbos getOsError:
  58. setResult(a, errorMsg)
  59. cbos setCurrentDir:
  60. os.setCurrentDir getString(a, 0)
  61. cbos getCurrentDir:
  62. setResult(a, os.getCurrentDir())
  63. cbos moveFile:
  64. os.moveFile(getString(a, 0), getString(a, 1))
  65. cbos moveDir:
  66. os.moveDir(getString(a, 0), getString(a, 1))
  67. cbos copyFile:
  68. os.copyFile(getString(a, 0), getString(a, 1))
  69. cbos copyDir:
  70. os.copyDir(getString(a, 0), getString(a, 1))
  71. cbos getLastModificationTime:
  72. setResult(a, getLastModificationTime(getString(a, 0)).toUnix)
  73. cbos findExe:
  74. setResult(a, os.findExe(getString(a, 0)))
  75. cbos rawExec:
  76. setResult(a, osproc.execCmd getString(a, 0))
  77. cbconf getEnv:
  78. setResult(a, os.getEnv(a.getString 0, a.getString 1))
  79. cbconf existsEnv:
  80. setResult(a, os.existsEnv(a.getString 0))
  81. cbconf putEnv:
  82. os.putEnv(a.getString 0, a.getString 1)
  83. cbconf dirExists:
  84. setResult(a, os.dirExists(a.getString 0))
  85. cbconf fileExists:
  86. setResult(a, os.fileExists(a.getString 0))
  87. cbconf projectName:
  88. setResult(a, conf.projectName)
  89. cbconf projectDir:
  90. setResult(a, conf.projectPath.string)
  91. cbconf projectPath:
  92. setResult(a, conf.projectFull.string)
  93. cbconf thisDir:
  94. setResult(a, vthisDir)
  95. cbconf put:
  96. options.setConfigVar(conf, getString(a, 0), getString(a, 1))
  97. cbconf get:
  98. setResult(a, options.getConfigVar(conf, a.getString 0))
  99. cbconf exists:
  100. setResult(a, options.existsConfigVar(conf, a.getString 0))
  101. cbconf nimcacheDir:
  102. setResult(a, options.getNimcacheDir(conf).string)
  103. cbconf paramStr:
  104. setResult(a, os.paramStr(int a.getInt 0))
  105. cbconf paramCount:
  106. setResult(a, os.paramCount())
  107. cbconf cmpIgnoreStyle:
  108. setResult(a, strutils.cmpIgnoreStyle(a.getString 0, a.getString 1))
  109. cbconf cmpIgnoreCase:
  110. setResult(a, strutils.cmpIgnoreCase(a.getString 0, a.getString 1))
  111. cbconf setCommand:
  112. conf.command = a.getString 0
  113. let arg = a.getString 1
  114. if arg.len > 0:
  115. conf.projectName = arg
  116. let path =
  117. if conf.projectName.isAbsolute: AbsoluteFile(conf.projectName)
  118. else: conf.projectPath / RelativeFile(conf.projectName)
  119. try:
  120. conf.projectFull = canonicalizePath(conf, path)
  121. except OSError:
  122. conf.projectFull = path
  123. cbconf getCommand:
  124. setResult(a, conf.command)
  125. cbconf switch:
  126. processSwitch(a.getString 0, a.getString 1, passPP, module.info, conf)
  127. cbconf hintImpl:
  128. processSpecificNote(a.getString 0, wHint, passPP, module.info,
  129. a.getString 1, conf)
  130. cbconf warningImpl:
  131. processSpecificNote(a.getString 0, wWarning, passPP, module.info,
  132. a.getString 1, conf)
  133. cbconf patchFile:
  134. let key = a.getString(0) & "_" & a.getString(1)
  135. var val = a.getString(2).addFileExt(NimExt)
  136. if {'$', '~'} in val:
  137. val = pathSubs(conf, val, vthisDir)
  138. elif not isAbsolute(val):
  139. val = vthisDir / val
  140. conf.moduleOverrides[key] = val
  141. cbconf selfExe:
  142. setResult(a, os.getAppFilename())
  143. cbconf cppDefine:
  144. options.cppDefine(conf, a.getString(0))
  145. proc runNimScript*(cache: IdentCache; scriptName: AbsoluteFile;
  146. freshDefines=true; conf: ConfigRef) =
  147. rawMessage(conf, hintConf, scriptName.string)
  148. let graph = newModuleGraph(cache, conf)
  149. connectCallbacks(graph)
  150. if freshDefines: initDefines(conf.symbols)
  151. defineSymbol(conf.symbols, "nimscript")
  152. defineSymbol(conf.symbols, "nimconfig")
  153. registerPass(graph, semPass)
  154. registerPass(graph, evalPass)
  155. conf.searchPaths.add(conf.libpath)
  156. var m = graph.makeModule(scriptName)
  157. incl(m.flags, sfMainModule)
  158. graph.vm = setupVM(m, cache, scriptName.string, graph)
  159. graph.compileSystemModule() # TODO: see why this unsets hintConf in conf.notes
  160. discard graph.processModule(m, llStreamOpen(scriptName, fmRead))
  161. # ensure we load 'system.nim' again for the real non-config stuff!
  162. resetSystemArtifacts(graph)
  163. # do not remove the defined symbols
  164. #initDefines()
  165. undefSymbol(conf.symbols, "nimscript")
  166. undefSymbol(conf.symbols, "nimconfig")