scriptconfig.nim 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  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
  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. config: ConfigRef = nil): PEvalContext =
  25. # For Nimble we need to export 'setupVM'.
  26. result = newCtx(module, cache)
  27. result.mode = emRepl
  28. registerAdditionalOps(result)
  29. # captured vars:
  30. var errorMsg: string
  31. var vthisDir = scriptName.splitFile.dir
  32. template cbconf(name, body) {.dirty.} =
  33. result.registerCallback "stdlib.system." & astToStr(name),
  34. proc (a: VmArgs) =
  35. body
  36. template cbos(name, body) {.dirty.} =
  37. result.registerCallback "stdlib.system." & astToStr(name),
  38. proc (a: VmArgs) =
  39. errorMsg = nil
  40. try:
  41. body
  42. except OSError:
  43. errorMsg = getCurrentExceptionMsg()
  44. # Idea: Treat link to file as a file, but ignore link to directory to prevent
  45. # endless recursions out of the box.
  46. cbos listFiles:
  47. listDirs(a, {pcFile, pcLinkToFile})
  48. cbos listDirs:
  49. listDirs(a, {pcDir})
  50. cbos removeDir:
  51. os.removeDir getString(a, 0)
  52. cbos removeFile:
  53. os.removeFile getString(a, 0)
  54. cbos createDir:
  55. os.createDir getString(a, 0)
  56. cbos getOsError:
  57. setResult(a, errorMsg)
  58. cbos setCurrentDir:
  59. os.setCurrentDir getString(a, 0)
  60. cbos getCurrentDir:
  61. setResult(a, os.getCurrentDir())
  62. cbos moveFile:
  63. os.moveFile(getString(a, 0), getString(a, 1))
  64. cbos copyFile:
  65. os.copyFile(getString(a, 0), getString(a, 1))
  66. cbos getLastModificationTime:
  67. setResult(a, toSeconds(getLastModificationTime(getString(a, 0))))
  68. cbos rawExec:
  69. setResult(a, osproc.execCmd getString(a, 0))
  70. cbconf getEnv:
  71. setResult(a, os.getEnv(a.getString 0))
  72. cbconf existsEnv:
  73. setResult(a, os.existsEnv(a.getString 0))
  74. cbconf dirExists:
  75. setResult(a, os.dirExists(a.getString 0))
  76. cbconf fileExists:
  77. setResult(a, os.fileExists(a.getString 0))
  78. cbconf thisDir:
  79. setResult(a, vthisDir)
  80. cbconf put:
  81. options.setConfigVar(getString(a, 0), getString(a, 1))
  82. cbconf get:
  83. setResult(a, options.getConfigVar(a.getString 0))
  84. cbconf exists:
  85. setResult(a, options.existsConfigVar(a.getString 0))
  86. cbconf nimcacheDir:
  87. setResult(a, options.getNimcacheDir())
  88. cbconf paramStr:
  89. setResult(a, os.paramStr(int a.getInt 0))
  90. cbconf paramCount:
  91. setResult(a, os.paramCount())
  92. cbconf cmpIgnoreStyle:
  93. setResult(a, strutils.cmpIgnoreStyle(a.getString 0, a.getString 1))
  94. cbconf cmpIgnoreCase:
  95. setResult(a, strutils.cmpIgnoreCase(a.getString 0, a.getString 1))
  96. cbconf setCommand:
  97. options.command = a.getString 0
  98. let arg = a.getString 1
  99. if arg.len > 0:
  100. gProjectName = arg
  101. let path =
  102. if gProjectName.isAbsolute: gProjectName
  103. else: gProjectPath / gProjectName
  104. try:
  105. gProjectFull = canonicalizePath(path)
  106. except OSError:
  107. gProjectFull = path
  108. cbconf getCommand:
  109. setResult(a, options.command)
  110. cbconf switch:
  111. processSwitch(a.getString 0, a.getString 1, passPP, module.info)
  112. cbconf hintImpl:
  113. processSpecificNote(a.getString 0, wHint, passPP, module.info,
  114. a.getString 1)
  115. cbconf warningImpl:
  116. processSpecificNote(a.getString 0, wWarning, passPP, module.info,
  117. a.getString 1)
  118. cbconf patchFile:
  119. let key = a.getString(0) & "_" & a.getString(1)
  120. var val = a.getString(2).addFileExt(NimExt)
  121. if {'$', '~'} in val:
  122. val = pathSubs(val, vthisDir)
  123. elif not isAbsolute(val):
  124. val = vthisDir / val
  125. gModuleOverrides[key] = val
  126. cbconf selfExe:
  127. setResult(a, os.getAppFilename())
  128. cbconf cppDefine:
  129. if config != nil:
  130. options.cppDefine(config, a.getString(0))
  131. proc runNimScript*(cache: IdentCache; scriptName: string;
  132. freshDefines=true; config: ConfigRef=nil) =
  133. passes.gIncludeFile = includeModule
  134. passes.gImportModule = importModule
  135. let graph = newModuleGraph(config)
  136. if freshDefines: initDefines()
  137. defineSymbol("nimscript")
  138. defineSymbol("nimconfig")
  139. registerPass(semPass)
  140. registerPass(evalPass)
  141. searchPaths.add(options.libpath)
  142. var m = graph.makeModule(scriptName)
  143. incl(m.flags, sfMainModule)
  144. vm.globalCtx = setupVM(m, cache, scriptName, config)
  145. graph.compileSystemModule(cache)
  146. discard graph.processModule(m, llStreamOpen(scriptName, fmRead), nil, cache)
  147. # ensure we load 'system.nim' again for the real non-config stuff!
  148. resetSystemArtifacts()
  149. vm.globalCtx = nil
  150. # do not remove the defined symbols
  151. #initDefines()
  152. undefSymbol("nimscript")
  153. undefSymbol("nimconfig")