-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathmod-deps.dang
More file actions
199 lines (183 loc) · 6.29 KB
/
Copy pathmod-deps.dang
File metadata and controls
199 lines (183 loc) · 6.29 KB
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
"""
Dagger dependencies for a Dang SDK module.
"""
type ModDeps {
"""
Workspace-relative path of the module root.
"""
let path: String!
"""
Workspace containing this module.
"""
let ws: Workspace!
"""
Return dependency names when present, otherwise dependency sources.
"""
list: [String!]! {
dependencyEntries
.map { dep => dependencyName(dep) }
.filter { dep => dep != "" }
}
"""
Add a Dagger dependency to dagger.json.
"""
add(source: String!, name: String! = ""): Changeset! {
# Write the declared entry verbatim, like dagger.json holds it: dependency
# sources are module-root-relative strings, and resolving them from module
# code needs a host session local paths don't have here.
let entry = if (name == "") {
toString(JSON.encode(source))
} else {
toString(JSON.encode({{name, source}}))
}
writeDependencyEntries(dependencyEntries + [entry])
}
"""
Remove a Dagger dependency from dagger.json by name or source.
"""
remove(name: String!): Changeset! {
writeDependencyEntries(
dependencyEntries.filter { dependency =>
dependencyName(dependency) != name and dependencySource(dependency) != name
},
)
}
"""
Update one dependency by name or source, or update all remote dependencies in
dagger.json.
A dependency answers to the same identifiers the engine matches on: its
module name, its source, or its source at a version. Naming a version
re-pins the dependency to it.
"""
update(name: String! = ""): Changeset! {
let src = ws.moduleSource("/" + path)
# A target is "<source-or-name>[@<version>]": the part before the version
# identifies the dependency, the version says what to re-pin it to.
let requestedVersion = name.split("@").dropFirst(1).join("@")
let target = sourceRef(name, requestedVersion)
let matched = src.dependencies
.{{moduleName, pin, asString, version}}
.filter { dep =>
name == ""
or dep.moduleName == target
or sourceRef(dep.asString, dep.version) == target
or sourceRef(dep.asString, dep.version) + "@" + dep.pin == target
}
# Only a pinned dependency carries a ref that can be resolved again; the
# engine's own update refuses local ones for the same reason.
let updatable = matched.filter { dep => dep.pin != "" }
if (updatable.length > 0) {
configChanges(
src.withDependencies(
updatable.map { dep =>
moduleSource(
refString: if (requestedVersion == "") {
dep.asString
} else {
sourceRef(dep.asString, dep.version) + "@" + requestedVersion
},
)
},
),
)
} else if (name == "") {
# Nothing to update — return an empty change instead of a config
# rewrite, so updating only local dependencies leaves dagger.json alone.
ws.changes(ws)
} else if (matched.length > 0 or isDeclared(target)) {
raise "updating a local dependency is not supported: " + name
} else {
raise "dependency requested for update is not in the dependency list: " + name
}
}
"""
Whether the config declares a dependency under this name or source.
A local dependency reaches module code without a resolvable ref, so the
declared config is the only place left to recognize the caller's target.
"""
let isDeclared(name: String!): Boolean! {
dependencyEntries.filter { dependency =>
dependencyName(dependency) == name or dependencySource(dependency) == name
}.length > 0
}
"""
Return a dependency ref stripped of its version:
"github.com/o/m@v1" -> "github.com/o/m".
"""
let sourceRef(asString: String!, version: String!): String! {
if (version == "") { asString } else { asString.trimSuffix("@" + version) }
}
"""
Stage a module source's edited config and return the change.
"""
let configChanges(src: ModuleSource!): Changeset! {
# updatedConfigDirectory carries only the config file, never the rest of the
# module, so this has to merge rather than replace.
ws.withDirectory("/" + path, src.updatedConfigDirectory.directory(path)).changes(ws)
}
"""
Return this module's dagger.json path from the workspace root.
"""
let configPath: String! {
if (path == ".") { "dagger.json" } else { path + "/dagger.json" }
}
"""
Return each dependency entry of dagger.json as raw JSON text, straight from
the declared config — a plain string entry stays a string.
"""
let dependencyEntries: [String!]! {
let config = json.withContents(ws.file("/" + configPath).contents :: Dagger.JSON!)
if (config.fields.contains("dependencies") == true) {
let dependencies = config.field(["dependencies"])
if (toString(dependencies.contents) == "null") {
[]
} else {
dependencies
.asArray.{{contents}}
.map { dependency => toString(dependency.contents) }
}
} else {
[]
}
}
"""
Return the dependency's configured name, or its source if no name is set.
"""
let dependencyName(dependency: String!): String! {
let value = json.withContents(dependency :: Dagger.JSON!)
if (dependency.hasPrefix("\"")) {
value.asString
} else if (value.fields.contains("name") == true) {
value.field(["name"]).asString
} else if (value.fields.contains("source") == true) {
value.field(["source"]).asString
} else {
""
}
}
"""
Return the dependency source of a config entry.
"""
let dependencySource(dependency: String!): String! {
let value = json.withContents(dependency :: Dagger.JSON!)
if (dependency.hasPrefix("\"")) {
value.asString
} else if (value.fields.contains("source") == true) {
value.field(["source"]).asString
} else {
""
}
}
"""
Stage dagger.json with the given dependency entries as its dependencies.
"""
let writeDependencyEntries(dependencies: [String!]!): Changeset! {
let config = json.withContents(ws.file("/" + configPath).contents :: Dagger.JSON!)
let updated = config.withField(
["dependencies"],
json.withContents(("[" + dependencies.join(",") + "]") :: Dagger.JSON!),
)
let contents = toString(updated.contents(pretty: true)) + "\n"
ws.withNewFile("/" + configPath, contents).changes(ws)
}
}