-
Notifications
You must be signed in to change notification settings - Fork 35
/
artifacts.bzl
176 lines (148 loc) · 5.8 KB
/
artifacts.bzl
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
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This source code is licensed under both the MIT license found in the
# LICENSE-MIT file in the root directory of this source tree and the Apache
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
# of this source tree.
load("@prelude//:paths.bzl", "paths")
load("@prelude//dist:dist_info.bzl", "DistInfo")
load("@prelude//utils:arglike.bzl", "ArgLike") # @unused Used as a type
load("@prelude//utils:expect.bzl", "expect")
# A group of artifacts.
ArtifactGroupInfo = provider(
fields = {
"artifacts": provider_field(typing.Any, default = None), # ["artifact"]
},
)
ArtifactOutputs = record(
# Single output. This is the artifact whose path would go into the resources
# JSON when this artifact is used as a resource.
default_output = field(Artifact),
# Other artifacts which need to be present in order to run the resource as
# an executable. This includes shared library dependencies and resources.
nondebug_runtime_files = field(list[ArgLike]),
# Other outputs that would be materialized if this artifact is the output of
# a build, or generally in any context where a user might run this artifact
# in a debugger.
#
# This is a superset of nondebug_runtime_files and also includes external
# debuginfo.
other_outputs = field(list[ArgLike]),
)
# Wrapper to support wrapping `Artifact`s referencing paths behind external
# symlinks.
ArtifactExt = record(
artifact = field(Artifact),
# If the `artifact` above is a symlink referencing an external path, this
# is an optional sub-path to append when accessing the path.
sub_path = field(str | None, None),
# Returns the resolved path as a `cmd_arg()`, with the optional sub-path
# appended.
as_arg = field(typing.Callable),
join = field(typing.Callable),
)
# A Provider that mirrors `DefaultInfo` for `Artifact` outputs, but allows
# specifying an `ArtifactExt` as it's default output.
DefaultOutputExt = provider(
fields = dict(
default_output = provider_field(ArtifactExt),
),
)
def single_artifact(dep: Artifact | Dependency) -> ArtifactOutputs:
if type(dep) == "artifact":
return ArtifactOutputs(
default_output = dep,
nondebug_runtime_files = [],
other_outputs = [],
)
if DefaultInfo in dep:
info = dep[DefaultInfo]
expect(
len(info.default_outputs) == 1,
"expected exactly one default output from {} ({})"
.format(dep, info.default_outputs),
)
default_output = info.default_outputs[0]
other_outputs = info.other_outputs
dist_info = dep.get(DistInfo)
nondebug_runtime_files = dist_info.nondebug_runtime_files if dist_info else other_outputs
return ArtifactOutputs(
default_output = default_output,
nondebug_runtime_files = nondebug_runtime_files,
other_outputs = other_outputs,
)
fail("unexpected dependency type: {}".format(type(dep)))
def unpack_artifacts(artifacts: list[Artifact | Dependency]) -> list[ArtifactOutputs]:
"""
Unpack a heterogeneous list of Artifact and ArtifactGroupInfo into a list
representing their outputs.
"""
out = []
for artifact in artifacts:
if type(artifact) == "artifact":
out.append(ArtifactOutputs(
default_output = artifact,
nondebug_runtime_files = [],
other_outputs = [],
))
continue
if ArtifactGroupInfo in artifact:
for artifact in artifact[ArtifactGroupInfo].artifacts:
out.append(ArtifactOutputs(
default_output = artifact,
nondebug_runtime_files = [],
other_outputs = [],
))
continue
out.append(single_artifact(artifact))
return out
def unpack_artifact_map(artifacts: dict[str, Artifact | Dependency]) -> dict[str, ArtifactOutputs]:
"""
Unpack a heterogeneous dict of Artifact and ArtifactGroupInfo into a dict
representing their outputs.
"""
out = {}
for name, artifact in artifacts.items():
if type(artifact) == "artifact":
out[name] = ArtifactOutputs(
default_output = artifact,
nondebug_runtime_files = [],
other_outputs = [],
)
continue
if ArtifactGroupInfo in artifact:
for artifact in artifact[ArtifactGroupInfo].artifacts:
out[paths.join(name, artifact.short_path)] = ArtifactOutputs(
default_output = artifact,
nondebug_runtime_files = [],
other_outputs = [],
)
continue
out[name] = single_artifact(artifact)
return out
def _as_arg(artifact: Artifact, sub_path: str | None) -> ArgLike:
if sub_path == None:
return artifact
return cmd_args(artifact, format = "{{}}/{}".format(sub_path))
def artifact_ext(
artifact: Artifact,
sub_path: str | None = None) -> ArtifactExt:
return ArtifactExt(
artifact = artifact,
sub_path = sub_path,
as_arg = lambda: _as_arg(artifact, sub_path),
join = lambda p: artifact_ext(
artifact = artifact,
sub_path = p if sub_path == None else paths.join(sub_path, p),
),
)
def to_artifact_ext(src: Artifact | Dependency) -> ArtifactExt:
if type(src) == "dependency":
ext = src.get(DefaultOutputExt)
if ext != None:
return ext.default_output
else:
(src,) = src[DefaultInfo].default_outputs
return artifact_ext(src)
def to_arglike(src: Artifact | Dependency) -> ArgLike:
return to_artifact_ext(src).as_arg()