make config.nims behave like nim.cfg in terms of where these scripts are searched / run (#8682)

* run project config.nims if exists, then inputfile.nims if exists
* ~/.config/nim/config.nims can now be used
* also check in getSystemConfigPath for config.nims
* refactor handleCmdLine for nim and nimsuggest
This commit is contained in:
Timothee Cour 2018-08-30 04:52:32 -07:00 • committed by Andreas Rumpf
commit ed0cb7b85d
7 changed files with 152 additions and 114 deletions

View file

@ -0,0 +1,85 @@
## Helpers for binaries that use compiler passes, eg: nim, nimsuggest, nimfix
# TODO: nimfix should use this; currently out of sync
import
compiler/[options, idents, nimconf, scriptconfig, extccomp, commands, msgs, lineinfos, modulegraphs, condsyms],
std/os
type
NimProg* = ref object
suggestMode*: bool
supportsStdinFile*: bool
processCmdLine*: proc(pass: TCmdLinePass, cmd: string; config: ConfigRef)
mainCommand*: proc(graph: ModuleGraph)
proc initDefinesProg*(self: NimProg, conf: ConfigRef, name: string) =
condsyms.initDefines(conf.symbols)
defineSymbol conf.symbols, name
proc processCmdLineAndProjectPath*(self: NimProg, conf: ConfigRef) =
self.processCmdLine(passCmd1, "", conf)
if self.supportsStdinFile and conf.projectName == "-":
conf.projectName = "stdinfile"
conf.projectFull = "stdinfile"
conf.projectPath = canonicalizePath(conf, getCurrentDir())
conf.projectIsStdin = true
elif conf.projectName != "":
try:
conf.projectFull = canonicalizePath(conf, conf.projectName)
except OSError:
conf.projectFull = conf.projectName
let p = splitFile(conf.projectFull)
let dir = if p.dir.len > 0: p.dir else: getCurrentDir()
conf.projectPath = canonicalizePath(conf, dir)
conf.projectName = p.name
else:
conf.projectPath = canonicalizePath(conf, getCurrentDir())
proc loadConfigsAndRunMainCommand*(self: NimProg, cache: IdentCache; conf: ConfigRef): bool =
loadConfigs(DefaultConfig, cache, conf) # load all config files
if self.suggestMode:
conf.command = "nimsuggest"
proc runNimScriptIfExists(path: string)=
if fileExists(path):
runNimScript(cache, path, freshDefines = false, conf)
# Caution: make sure this stays in sync with `loadConfigs`
if optSkipSystemConfigFile notin conf.globalOptions:
runNimScriptIfExists(getSystemConfigPath(conf, DefaultConfigNims))
if optSkipUserConfigFile notin conf.globalOptions:
runNimScriptIfExists(getUserConfigPath(DefaultConfigNims))
if optSkipParentConfigFiles notin conf.globalOptions:
for dir in parentDirs(conf.projectPath, fromRoot = true, inclusive = false):
runNimScriptIfExists(dir / DefaultConfigNims)
if optSkipProjConfigFile notin conf.globalOptions:
runNimScriptIfExists(conf.projectPath / DefaultConfigNims)
block:
let scriptFile = conf.projectFull.changeFileExt("nims")
if not self.suggestMode:
runNimScriptIfExists(scriptFile)
# 'nim foo.nims' means to just run the NimScript file and do nothing more:
if fileExists(scriptFile) and scriptFile.cmpPaths(conf.projectFull) == 0:
return false
else:
if scriptFile.cmpPaths(conf.projectFull) != 0:
runNimScriptIfExists(scriptFile)
else:
# 'nimsuggest foo.nims' means to just auto-complete the NimScript file
discard
# now process command line arguments again, because some options in the
# command line can overwite the config file's settings
extccomp.initVars(conf)
self.processCmdLine(passCmd2, "", conf)
if conf.command == "":
rawMessage(conf, errGenerated, "command missing")
let graph = newModuleGraph(cache, conf)
graph.suggestMode = self.suggestMode
self.mainCommand(graph)
return true

View file

@ -651,7 +651,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
else: localError(conf, info, "invalid option for --symbolFiles: " & arg) else: localError(conf, info, "invalid option for --symbolFiles: " & arg)
of "skipcfg": of "skipcfg":
expectNoArg(conf, switch, arg, pass, info) expectNoArg(conf, switch, arg, pass, info)
incl(conf.globalOptions, optSkipConfigFile) incl(conf.globalOptions, optSkipSystemConfigFile)
of "skipprojcfg": of "skipprojcfg":
expectNoArg(conf, switch, arg, pass, info) expectNoArg(conf, switch, arg, pass, info)
incl(conf.globalOptions, optSkipProjConfigFile) incl(conf.globalOptions, optSkipProjConfigFile)

View file

@ -21,7 +21,7 @@ when defined(i386) and defined(windows) and defined(vcc):
import import
commands, lexer, condsyms, options, msgs, nversion, nimconf, ropes, commands, lexer, condsyms, options, msgs, nversion, nimconf, ropes,
extccomp, strutils, os, osproc, platform, main, parseopt, extccomp, strutils, os, osproc, platform, main, parseopt,
nodejs, scriptconfig, idents, modulegraphs, lineinfos nodejs, scriptconfig, idents, modulegraphs, lineinfos, cmdlinehelper
when hasTinyCBackend: when hasTinyCBackend:
import tccgen import tccgen
@ -57,69 +57,43 @@ proc processCmdLine(pass: TCmdLinePass, cmd: string; config: ConfigRef) =
rawMessage(config, errGenerated, errArgsNeedRunOption) rawMessage(config, errGenerated, errArgsNeedRunOption)
proc handleCmdLine(cache: IdentCache; conf: ConfigRef) = proc handleCmdLine(cache: IdentCache; conf: ConfigRef) =
condsyms.initDefines(conf.symbols) let self = NimProg(
supportsStdinFile: true,
processCmdLine: processCmdLine,
mainCommand: mainCommand
)
self.initDefinesProg(conf, "nim_compiler")
if paramCount() == 0: if paramCount() == 0:
writeCommandLineUsage(conf, conf.helpWritten) writeCommandLineUsage(conf, conf.helpWritten)
else: return
# Process command line arguments:
processCmdLine(passCmd1, "", conf) self.processCmdLineAndProjectPath(conf)
if conf.projectName == "-": if not self.loadConfigsAndRunMainCommand(cache, conf): return
conf.projectName = "stdinfile" if optHints in conf.options and hintGCStats in conf.notes: echo(GC_getStatistics())
conf.projectFull = "stdinfile" #echo(GC_getStatistics())
conf.projectPath = canonicalizePath(conf, getCurrentDir()) if conf.errorCounter != 0: return
conf.projectIsStdin = true when hasTinyCBackend:
elif conf.projectName != "": if conf.cmd == cmdRun:
try: tccgen.run(conf.arguments)
conf.projectFull = canonicalizePath(conf, conf.projectName) if optRun in conf.globalOptions:
except OSError: if conf.cmd == cmdCompileToJS:
conf.projectFull = conf.projectName var ex: string
let p = splitFile(conf.projectFull) if conf.outFile.len > 0:
let dir = if p.dir.len > 0: p.dir else: getCurrentDir() ex = conf.outFile.prependCurDir.quoteShell
conf.projectPath = canonicalizePath(conf, dir) else:
conf.projectName = p.name ex = quoteShell(
completeCFilePath(conf, changeFileExt(conf.projectFull, "js").prependCurDir))
execExternalProgram(conf, findNodeJs() & " " & ex & ' ' & conf.arguments)
else: else:
conf.projectPath = canonicalizePath(conf, getCurrentDir()) var binPath: string
loadConfigs(DefaultConfig, cache, conf) # load all config files if conf.outFile.len > 0:
let scriptFile = conf.projectFull.changeFileExt("nims") # If the user specified an outFile path, use that directly.
if fileExists(scriptFile): binPath = conf.outFile.prependCurDir
runNimScript(cache, scriptFile, freshDefines=false, conf) else:
# 'nim foo.nims' means to just run the NimScript file and do nothing more: # Figure out ourselves a valid binary name.
if scriptFile == conf.projectFull: return binPath = changeFileExt(conf.projectFull, ExeExt).prependCurDir
elif fileExists(conf.projectPath / "config.nims"): var ex = quoteShell(binPath)
# directory wide NimScript file execExternalProgram(conf, ex & ' ' & conf.arguments)
runNimScript(cache, conf.projectPath / "config.nims", freshDefines=false, conf)
# now process command line arguments again, because some options in the
# command line can overwite the config file's settings
extccomp.initVars(conf)
processCmdLine(passCmd2, "", conf)
if conf.command == "":
rawMessage(conf, errGenerated, "command missing")
mainCommand(newModuleGraph(cache, conf))
if optHints in conf.options and hintGCStats in conf.notes: echo(GC_getStatistics())
#echo(GC_getStatistics())
if conf.errorCounter == 0:
when hasTinyCBackend:
if conf.cmd == cmdRun:
tccgen.run(conf.arguments)
if optRun in conf.globalOptions:
if conf.cmd == cmdCompileToJS:
var ex: string
if conf.outFile.len > 0:
ex = conf.outFile.prependCurDir.quoteShell
else:
ex = quoteShell(
completeCFilePath(conf, changeFileExt(conf.projectFull, "js").prependCurDir))
execExternalProgram(conf, findNodeJs() & " " & ex & ' ' & conf.arguments)
else:
var binPath: string
if conf.outFile.len > 0:
# If the user specified an outFile path, use that directly.
binPath = conf.outFile.prependCurDir
else:
# Figure out ourselves a valid binary name.
binPath = changeFileExt(conf.projectFull, ExeExt).prependCurDir
var ex = quoteShell(binPath)
execExternalProgram(conf, ex & ' ' & conf.arguments)
when declared(GC_setMaxPause): when declared(GC_setMaxPause):
GC_setMaxPause 2_000 GC_setMaxPause 2_000

View file

@ -219,10 +219,10 @@ proc readConfigFile(
closeLexer(L) closeLexer(L)
return true return true
proc getUserConfigPath(filename: string): string = proc getUserConfigPath*(filename: string): string =
result = joinPath([getConfigDir(), "nim", filename]) result = joinPath([getConfigDir(), "nim", filename])
proc getSystemConfigPath(conf: ConfigRef; filename: string): string = proc getSystemConfigPath*(conf: ConfigRef; filename: string): string =
# try standard configuration file (installation did not distribute files # try standard configuration file (installation did not distribute files
# the UNIX way) # the UNIX way)
let p = getPrefixDir(conf) let p = getPrefixDir(conf)
@ -241,7 +241,7 @@ proc loadConfigs*(cfg: string; cache: IdentCache; conf: ConfigRef) =
if readConfigFile(configPath, cache, conf): if readConfigFile(configPath, cache, conf):
add(configFiles, configPath) add(configFiles, configPath)
if optSkipConfigFile notin conf.globalOptions: if optSkipSystemConfigFile notin conf.globalOptions:
readConfigFile(getSystemConfigPath(conf, cfg)) readConfigFile(getSystemConfigPath(conf, cfg))
if optSkipUserConfigFile notin conf.globalOptions: if optSkipUserConfigFile notin conf.globalOptions:
@ -263,4 +263,5 @@ proc loadConfigs*(cfg: string; cache: IdentCache; conf: ConfigRef) =
readConfigFile(projectConfig) readConfigFile(projectConfig)
for filename in configFiles: for filename in configFiles:
# delayed to here so that `hintConf` is honored
rawMessage(conf, hintConf, filename) rawMessage(conf, hintConf, filename)

View file

@ -54,10 +54,10 @@ type # please make sure we have under 32 options
optGenMapping, # generate a mapping file optGenMapping, # generate a mapping file
optRun, # run the compiled project optRun, # run the compiled project
optCheckNep1, # check that the names adhere to NEP-1 optCheckNep1, # check that the names adhere to NEP-1
optSkipConfigFile, # skip the general config file optSkipSystemConfigFile, # skip the system's cfg/nims config file
optSkipProjConfigFile, # skip the project's config file optSkipProjConfigFile, # skip the project's cfg/nims config file
optSkipUserConfigFile, # skip the users's config file optSkipUserConfigFile, # skip the users's cfg/nims config file
optSkipParentConfigFiles, # skip parent dir's config files optSkipParentConfigFiles, # skip parent dir's cfg/nims config files
optNoMain, # do not generate a "main" proc optNoMain, # do not generate a "main" proc
optUseColors, # use colors for hints, warnings, and errors optUseColors, # use colors for hints, warnings, and errors
optThreads, # support for multi-threading optThreads, # support for multi-threading
@ -391,6 +391,7 @@ const
TexExt* = "tex" TexExt* = "tex"
IniExt* = "ini" IniExt* = "ini"
DefaultConfig* = "nim.cfg" DefaultConfig* = "nim.cfg"
DefaultConfigNims* = "config.nims"
DocConfig* = "nimdoc.cfg" DocConfig* = "nimdoc.cfg"
DocTexConfig* = "nimdoc.tex.cfg" DocTexConfig* = "nimdoc.tex.cfg"

View file

@ -171,7 +171,7 @@ proc runNimScript*(cache: IdentCache; scriptName: string;
incl(m.flags, sfMainModule) incl(m.flags, sfMainModule)
graph.vm = setupVM(m, cache, scriptName, graph) graph.vm = setupVM(m, cache, scriptName, graph)
graph.compileSystemModule() graph.compileSystemModule() # TODO: see why this unsets hintConf in conf.notes
discard graph.processModule(m, llStreamOpen(scriptName, fmRead)) discard graph.processModule(m, llStreamOpen(scriptName, fmRead))
# ensure we load 'system.nim' again for the real non-config stuff! # ensure we load 'system.nim' again for the real non-config stuff!

View file

@ -20,7 +20,7 @@ import compiler / [options, commands, modules, sem,
passes, passaux, msgs, nimconf, passes, passaux, msgs, nimconf,
extccomp, condsyms, extccomp, condsyms,
sigmatch, ast, scriptconfig, sigmatch, ast, scriptconfig,
idents, modulegraphs, vm, prefixmatches, lineinfos] idents, modulegraphs, vm, prefixmatches, lineinfos, cmdlinehelper]
when defined(windows): when defined(windows):
import winlean import winlean
@ -582,55 +582,32 @@ proc processCmdLine*(pass: TCmdLinePass, cmd: string; conf: ConfigRef) =
# if processArgument(pass, p, argsCount): break # if processArgument(pass, p, argsCount): break
proc handleCmdLine(cache: IdentCache; conf: ConfigRef) = proc handleCmdLine(cache: IdentCache; conf: ConfigRef) =
condsyms.initDefines(conf.symbols) let self = NimProg(
defineSymbol conf.symbols, "nimsuggest" suggestMode: true,
processCmdLine: processCmdLine,
mainCommand: mainCommand
)
self.initDefinesProg(conf, "nimsuggest")
if paramCount() == 0: if paramCount() == 0:
stdout.writeline(Usage) stdout.writeline(Usage)
else: return
processCmdLine(passCmd1, "", conf)
if gMode != mstdin:
conf.writelnHook = proc (msg: string) = discard
if conf.projectName != "":
try:
conf.projectFull = canonicalizePath(conf, conf.projectName)
except OSError:
conf.projectFull = conf.projectName
var p = splitFile(conf.projectFull)
conf.projectPath = canonicalizePath(conf, p.dir)
conf.projectName = p.name
else:
conf.projectPath = canonicalizePath(conf, getCurrentDir())
# Find Nim's prefix dir. self.processCmdLineAndProjectPath(conf)
let binaryPath = findExe("nim")
if binaryPath == "":
raise newException(IOError,
"Cannot find Nim standard library: Nim compiler not in PATH")
conf.prefixDir = binaryPath.splitPath().head.parentDir()
if not dirExists(conf.prefixDir / "lib"): conf.prefixDir = ""
#msgs.writelnHook = proc (line: string) = log(line) if gMode != mstdin:
myLog("START " & conf.projectFull) conf.writelnHook = proc (msg: string) = discard
# Find Nim's prefix dir.
let binaryPath = findExe("nim")
if binaryPath == "":
raise newException(IOError,
"Cannot find Nim standard library: Nim compiler not in PATH")
conf.prefixDir = binaryPath.splitPath().head.parentDir()
if not dirExists(conf.prefixDir / "lib"): conf.prefixDir = ""
loadConfigs(DefaultConfig, cache, conf) # load all config files #msgs.writelnHook = proc (line: string) = log(line)
# now process command line arguments again, because some options in the myLog("START " & conf.projectFull)
# command line can overwite the config file's settings
conf.command = "nimsuggest"
let scriptFile = conf.projectFull.changeFileExt("nims")
if fileExists(scriptFile):
# 'nimsuggest foo.nims' means to just auto-complete the NimScript file:
if scriptFile != conf.projectFull:
runNimScript(cache, scriptFile, freshDefines=false, conf)
elif fileExists(conf.projectPath / "config.nims"):
# directory wide NimScript file
runNimScript(cache, conf.projectPath / "config.nims", freshDefines=false, conf)
extccomp.initVars(conf) discard self.loadConfigsAndRunMainCommand(cache, conf)
processCmdLine(passCmd2, "", conf)
let graph = newModuleGraph(cache, conf)
graph.suggestMode = true
mainCommand(graph)
handleCmdline(newIdentCache(), newConfigRef()) handleCmdline(newIdentCache(), newConfigRef())