1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
|
#
#
# Nim's Runtime Library
# (c) Copyright 2015 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
# Nim's configuration system now uses Nim for scripting. This module provides
# a few things that are required for this to work.
const
buildOS* {.magic: "BuildOS".}: string = ""
## The OS this build is running on. Can be different from ``system.hostOS``
## for cross compilations.
buildCPU* {.magic: "BuildCPU".}: string = ""
## The CPU this build is running on. Can be different from ``system.hostCPU``
## for cross compilations.
template builtin = discard
# We know the effects better than the compiler:
{.push hint[XDeclaredButNotUsed]: off.}
proc listDirs*(dir: string): seq[string] =
## Lists all the subdirectories (non-recursively) in the directory `dir`.
builtin
proc listFiles*(dir: string): seq[string] =
## Lists all the files (non-recursively) in the directory `dir`.
builtin
proc removeDir(dir: string){.
tags: [ReadIOEffect, WriteIOEffect], raises: [OSError].} = builtin
proc removeFile(dir: string) {.
tags: [ReadIOEffect, WriteIOEffect], raises: [OSError].} = builtin
proc moveFile(src, dest: string) {.
tags: [ReadIOEffect, WriteIOEffect], raises: [OSError].} = builtin
proc copyFile(src, dest: string) {.
tags: [ReadIOEffect, WriteIOEffect], raises: [OSError].} = builtin
proc createDir(dir: string) {.tags: [WriteIOEffect], raises: [OSError].} =
builtin
proc getOsError: string = builtin
proc setCurrentDir(dir: string) = builtin
proc getCurrentDir(): string = builtin
proc rawExec(cmd: string): int {.tags: [ExecIOEffect], raises: [OSError].} =
builtin
proc warningImpl(arg, orig: string) = discard
proc hintImpl(arg, orig: string) = discard
proc paramStr*(i: int): string =
## Retrieves the ``i``'th command line parameter.
builtin
proc paramCount*(): int =
## Retrieves the number of command line parameters.
builtin
proc switch*(key: string, val="") =
## Sets a Nim compiler command line switch, for
## example ``switch("checks", "on")``.
builtin
proc warning*(name: string; val: bool) =
## Disables or enables a specific warning.
let v = if val: "on" else: "off"
warningImpl(name & "]:" & v, "warning[" & name & "]:" & v)
proc hint*(name: string; val: bool) =
## Disables or enables a specific hint.
let v = if val: "on" else: "off"
hintImpl(name & "]:" & v, "hint[" & name & "]:" & v)
proc patchFile*(package, filename, replacement: string) =
## Overrides the location of a given file belonging to the
## passed package.
## If the ``replacement`` is not an absolute path, the path
## is interpreted to be local to the Nimscript file that contains
## the call to ``patchFile``, Nim's ``--path`` is not used at all
## to resolve the filename!
##
## Example:
##
## .. code-block:: nim
##
## patchFile("stdlib", "asyncdispatch", "patches/replacement")
discard
proc getCommand*(): string =
## Gets the Nim command that the compiler has been invoked with, for example
## "c", "js", "build", "help".
builtin
proc setCommand*(cmd: string; project="") =
## Sets the Nim command that should be continued with after this Nimscript
## has finished.
builtin
proc cmpIgnoreStyle(a, b: string): int = builtin
proc cmpIgnoreCase(a, b: string): int = builtin
proc cmpic*(a, b: string): int =
## Compares `a` and `b` ignoring case.
cmpIgnoreCase(a, b)
proc getEnv*(key: string; default = ""): string {.tags: [ReadIOEffect].} =
## Retrieves the environment variable of name `key`.
builtin
proc existsEnv*(key: string): bool {.tags: [ReadIOEffect].} =
## Checks for the existence of an environment variable named `key`.
builtin
proc putEnv*(key, val: string) {.tags: [WriteIOEffect].} =
## Sets the value of the environment variable named key to val.
builtin
proc fileExists*(filename: string): bool {.tags: [ReadIOEffect].} =
## Checks if the file exists.
builtin
proc dirExists*(dir: string): bool {.
tags: [ReadIOEffect].} =
## Checks if the directory `dir` exists.
builtin
proc existsFile*(filename: string): bool =
## An alias for ``fileExists``.
fileExists(filename)
proc existsDir*(dir: string): bool =
## An alias for ``dirExists``.
dirExists(dir)
proc selfExe*(): string =
## Returns the currently running nim or nimble executable.
builtin
proc toExe*(filename: string): string =
## On Windows adds ".exe" to `filename`, else returns `filename` unmodified.
(when defined(windows): filename & ".exe" else: filename)
proc toDll*(filename: string): string =
## On Windows adds ".dll" to `filename`, on Posix produces "lib$filename.so".
(when defined(windows): filename & ".dll" else: "lib" & filename & ".so")
proc strip(s: string): string =
var i = 0
while s[i] in {' ', '\c', '\L'}: inc i
result = s.substr(i)
template `--`*(key, val: untyped) =
## A shortcut for ``switch(astToStr(key), astToStr(val))``.
switch(astToStr(key), strip astToStr(val))
template `--`*(key: untyped) =
## A shortcut for ``switch(astToStr(key)``.
switch(astToStr(key), "")
type
ScriptMode* {.pure.} = enum ## Controls the behaviour of the script.
Silent, ## Be silent.
Verbose, ## Be verbose.
Whatif ## Do not run commands, instead just echo what
## would have been done.
var
mode*: ScriptMode ## Set this to influence how mkDir, rmDir, rmFile etc.
## behave
template checkOsError =
let err = getOsError()
if err.len > 0: raise newException(OSError, err)
template log(msg: string, body: untyped) =
if mode == ScriptMode.Verbose or mode == ScriptMode.Whatif:
echo "[NimScript] ", msg
if mode != ScriptMode.WhatIf:
body
proc rmDir*(dir: string) {.raises: [OSError].} =
## Removes the directory `dir`.
log "rmDir: " & dir:
removeDir dir
checkOsError()
proc rmFile*(file: string) {.raises: [OSError].} =
## Removes the `file`.
log "rmFile: " & file:
removeFile file
checkOsError()
proc mkDir*(dir: string) {.raises: [OSError].} =
## Creates the directory `dir` including all necessary subdirectories. If
## the directory already exists, no error is raised.
log "mkDir: " & dir:
createDir dir
checkOsError()
proc mvFile*(`from`, to: string) {.raises: [OSError].} =
## Moves the file `from` to `to`.
log "mvFile: " & `from` & ", " & to:
moveFile `from`, to
checkOsError()
proc cpFile*(`from`, to: string) {.raises: [OSError].} =
## Copies the file `from` to `to`.
log "cpFile: " & `from` & ", " & to:
copyFile `from`, to
checkOsError()
proc exec*(command: string) =
## Executes an external process.
log "exec: " & command:
if rawExec(command) != 0:
raise newException(OSError, "FAILED: " & command)
checkOsError()
proc exec*(command: string, input: string, cache = "") {.
raises: [OSError], tags: [ExecIOEffect].} =
## Executes an external process.
log "exec: " & command:
echo staticExec(command, input, cache)
proc selfExec*(command: string) =
## Executes an external command with the current nim/nimble executable.
## ``Command`` must not contain the "nim " part.
let c = selfExe() & " " & command
log "exec: " & c:
if rawExec(c) != 0:
raise newException(OSError, "FAILED: " & c)
checkOsError()
proc put*(key, value: string) =
## Sets a configuration 'key' like 'gcc.options.always' to its value.
builtin
proc get*(key: string): string =
## Retrieves a configuration 'key' like 'gcc.options.always'.
builtin
proc exists*(key: string): bool =
## Checks for the existence of a configuration 'key'
## like 'gcc.options.always'.
builtin
proc nimcacheDir*(): string =
## Retrieves the location of 'nimcache'.
builtin
proc thisDir*(): string =
## Retrieves the location of the current ``nims`` script file.
builtin
proc cd*(dir: string) {.raises: [OSError].} =
## Changes the current directory.
##
## The change is permanent for the rest of the execution, since this is just
## a shortcut for `os.setCurrentDir()
## <http://nim-lang.org/docs/os.html#setCurrentDir,string>`_ . Use the `withDir()
## <#withDir>`_ template if you want to perform a temporary change only.
setCurrentDir(dir)
checkOsError()
template withDir*(dir: string; body: untyped): untyped =
## Changes the current directory temporarily.
##
## If you need a permanent change, use the `cd() <#cd>`_ proc. Usage example:
##
## .. code-block:: nim
## withDir "foo":
## # inside foo
## #back to last dir
var curDir = getCurrentDir()
try:
cd(dir)
body
finally:
cd(curDir)
template `==?`(a, b: string): bool = cmpIgnoreStyle(a, b) == 0
proc writeTask(name, desc: string) =
if desc.len > 0:
var spaces = " "
for i in 0 ..< 20 - name.len: spaces.add ' '
echo name, spaces, desc
template task*(name: untyped; description: string; body: untyped): untyped =
## Defines a task. Hidden tasks are supported via an empty description.
## Example:
##
## .. code-block:: nim
## task build, "default build is via the C backend":
## setCommand "c"
proc `name Task`*() = body
let cmd = getCommand()
if cmd.len == 0 or cmd ==? "help":
setCommand "help"
writeTask(astToStr(name), description)
elif cmd ==? astToStr(name):
setCommand "nop"
`name Task`()
proc cppDefine*(define: string) =
## tell Nim that ``define`` is a C preprocessor ``#define`` and so always
## needs to be mangled.
builtin
when not defined(nimble):
# nimble has its own implementation for these things.
var
packageName* = "" ## Nimble support: Set this to the package name. It
## is usually not required to do that, nims' filename is
## the default.
version*: string ## Nimble support: The package's version.
author*: string ## Nimble support: The package's author.
description*: string ## Nimble support: The package's description.
license*: string ## Nimble support: The package's license.
srcDir*: string ## Nimble support: The package's source directory.
binDir*: string ## Nimble support: The package's binary directory.
backend*: string ## Nimble support: The package's backend.
skipDirs*, skipFiles*, skipExt*, installDirs*, installFiles*,
installExt*, bin*: seq[string] = @[] ## Nimble metadata.
requiresData*: seq[string] = @[] ## Exposes the list of requirements for read
## and write accesses.
proc requires*(deps: varargs[string]) =
## Nimble support: Call this to set the list of requirements of your Nimble
## package.
for d in deps: requiresData.add(d)
{.pop.}
|