-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathnawabs.nim
268 lines (242 loc) · 9.01 KB
/
nawabs.nim
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
#
# Nawabs -- The Anti package manager for Nim
# (c) Copyright 2021 Andreas Rumpf
#
# See the file "license.txt", included in this
# distribution, for details about the copyright.
import strutils, os, json, parseopt
from osproc import quoteShell
import osutils, recipes, packages, tinkerer, nimscriptsupport
const
Help = """
Usage: nawabs [options] COMMAND [args]
Commands:
init Initializes the current working directory as
the workspace.
refresh Refreshes the package list.
search [pkg/tag] Searches for a specified package. Search is
performed by tag and by name. If no argument
is given, lists all packages.
clone pkg Clones a package.
--deps:DIR_ Use DIR_ as the subdirectory
for cloning missing dependencies. (Use '_' to
denote the workspace, '.' for the current
directory.)
--nodeps Do not clone missing dependencies.
--noquestions Do not ask any questions.
build pkg [args] Build the package, save as recipe if
successful. You can pass optional args
like -d:release to the build.
--deps:DIR_ Use DIR_ as the subdirectory
for cloning missing dependencies. (Use '_' to
denote the workspace, '.' for the current
directory.)
--nodeps Do not clone missing dependencies.
--norecipes Do not use the recipes mechanism.
--noquestions Do not ask any questions.
pinned pkg Use the recipe to get a reproducible build.
path pkg-list Show absolute paths to the installed packages
specified.
deps pkg Show required ``--path:xyz`` command line to
build the given package.
update pkg Update a package and all of its dependencies.
--nodeps Do not update its dependencies.
--depsOnly Only update its dependencies.
--ask Ask about every dependency.
update Update every package in the workspace that
doesn't have uncommitted changes.
--ask Ask about every dependency.
task <taskname> [file.nimble] Run the task of the nimble file.
tests [file.nimble] Run the 'tests' task of the nimble file.
bench [file.nimble] Run the 'bench' task of the nimble file.
Options:
-h, --help Print this help message.
-v, --version Print version information.
--nimExe:nim.exe Which nim to use for building.
--cloneUsingHttps Use the https URL instead of git URLs for
cloning.
--workspace:DIR Use DIR as the current workspace.
"""
Version = "2.0"
proc execRecipe(c: Config; proj: Project;
attempt = false): bool {.discardable.} =
let recipe = toRecipe(c.workspace, proj)
if not fileExists recipe:
if not attempt:
error "no recipe found: " & recipe
else:
runScript(recipe, c.workspace)
proc getProject(c: Config; name: string): Project =
result = findProj(c.workspace, name)
if result.name.len == 0:
error "cannot find package " & name
proc build(c: Config; pkgList: seq[Package]; pkg, rest: string) =
var cmd = c.nimExe
if rest.len > 0:
cmd.add ' '
cmd.add rest
var deps: seq[string] = @[]
buildCmd c, getPackages(c), pkg, cmd, deps
exec cmd
if not c.norecipes:
writeRecipe(c.workspace, getProject(c, pkg), cmd, deps)
writeKeyValPair(c.workspace, "_", cmd)
proc listDeps(c: Config, pkg: string) =
var cmd = ""
var deps: seq[string] = @[]
buildCmd c, @[], pkg, cmd, deps
var result = ""
for d in deps:
result.add " --path:"
result.add quoteShell(d)
echo result
proc update(c: Config; pkg: string) =
let p = getProject(c, pkg)
var cmd = c.nimExe
var deps: seq[string] = @[]
buildCmd(c, getPackages(c), pkg, cmd, deps, onlyDeps=true)
if c.depsSetting != onlyDeps:
updateProject(c, p.toPath)
if c.depsSetting != noDeps:
for d in deps: updateProject(c, d)
proc echoPath(c: Config, a: string) =
let p = getProject(c, a)
echo c.workspace / p.subdir / p.name
proc findNimbleFile(): string =
for x in walkFiles("*.nimble"):
if result.len == 0: result = x
else: error "cannot determine which .nimble file to use; ambiguous"
if result.len == 0:
error "cannot find a .nimble file"
proc runtask(c: Config; taskname, file: string) =
runScript(file, c.workspace, taskname, allowSetCommand=true)
proc main(c: Config) =
var action = ""
var args: seq[string] = @[]
var rest = ""
template handleRest() =
if args.len == 1 and action in ["build", "run"]:
rest = cmdLineRest(p)
break
var p = initOptParser()
while true:
next(p)
case p.kind
of cmdArgument:
if action.len == 0: action = p.key.normalize
else: args.add p.key
handleRest()
of cmdLongOption, cmdShortOption:
case p.key.normalize
of "version", "v":
echo Version
quit 0
of "help", "h":
echo Help
quit 0
of "nimexe":
if p.val.len == 0: error "--nimExe takes a value"
else: c.nimExe = p.val
of "nodeps": c.depsSetting = noDeps
of "depsonly": c.depsSetting = onlyDeps
of "ask": c.depsSetting = askDeps
of "deps":
if p.val == recipesDirName:
error "cannot use " & recipesDirName & " for --deps"
elif p.val.len > 1 and p.val.endsWith"_":
c.deps = p.val
else:
error "deps directory must end in an underscore"
of "norecipes": c.norecipes = true
of "cloneusinghttps": c.cloneUsingHttps = true
of "noquestions": c.noquestions = true
of "workspace":
if p.val.len == 0: error "--" & p.key & " takes a value"
else: c.workspace = p.val
else:
error "unkown command line option: " & p.key
of cmdEnd: break
if c.workspace.len > 0:
if not dirExists(c.workspace / recipesDirName):
error c.workspace & "is not a workspace"
else:
c.workspace = getCurrentDir()
if action != "init":
while c.workspace.len > 0 and not dirExists(c.workspace / recipesDirName):
c.workspace = c.workspace.parentDir()
if c.workspace.len == 0:
error "Could not detect a workspace. " &
"Use 'nawabs init' to create a new workspace."
case c.deps
of "_": c.deps = c.workspace
of ".": c.deps = getCurrentDir()
else: discard
template singlePkg() =
if args.len != 1:
error action & " command takes a single package name"
template noPkg() =
if args.len != 0:
error action & " command takes no arguments"
case action
of "init":
noPkg()
if dirExists(c.workspace / recipesDirName):
error c.workspace & " is already a workspace"
recipes.init(c.workspace)
withDir c.workspace / recipesDirName:
createDir configDir
let roots = configDir / "roots.nims"
copyFile(getAppDir() / roots, roots)
copyFile(getAppDir() / configDir / nimscriptApi, nimscriptApi)
refresh(c)
of "refresh": refresh(c)
of "search", "list": search getPackages(c), args
of "clone":
singlePkg()
if cloneRec(c, getPackages(c), args[0]):
error "Already part of workspace: " & args[0]
of "help", "h":
echo Help
of "update":
if args.len == 0:
updateEverything(c, c.workspace)
else:
singlePkg()
update(c, args[0])
of "pinned":
singlePkg()
execRecipe c, getProject(c, args[0])
of "build":
singlePkg()
build c, getPackages(c), args[0], rest
of "deps":
singlePkg()
listDeps c, args[0]
of "path":
for a in args: echoPath(c, a)
of "task":
if args.len == 2:
runtask(c, args[0], args[1])
elif args.len == 1:
runtask(c, args[0], findNimbleFile())
else:
error "command 'task' takes 1 or 2 arguments"
of "tests", "bench":
if args.len == 1:
runtask(c, action, args[0])
elif args.len == 0:
runtask(c, action, findNimbleFile())
else:
error "command '" & action & "' takes 0 or 1 arguments"
else:
# typing in 'nawabs' with no command currently raises an error so we're
# free to later do something more convenient here
if action.len == 0: error "command missing"
else: error "unknown command: " & action
if c.foreignDeps.len > 0:
echo("Hint: This package has some external dependencies.\n",
"To install them you may be able to run:")
for fd in c.foreignDeps:
echo " ", fd
when isMainModule:
main(newConfig())