1{
2 lib,
3 stdenv,
4 fetchurl,
5 system,
6 snapshotPath,
7 autoPatchelfHook,
8 python3,
9 libxcrypt-legacy,
10}:
11
12let
13 # Mapping from GCS component architecture names to Nix architecture names
14 arches = {
15 x86 = "i686";
16 x86_64 = "x86_64";
17 arm = "aarch64";
18 };
19
20 # Mapping from GCS component operating systems to Nix operating systems
21 oses = {
22 LINUX = "linux";
23 MACOSX = "darwin";
24 WINDOWS = "windows";
25 CYGWIN = "cygwin";
26 };
27
28 # Convert an archicecture + OS to a Nix platform
29 toNixPlatform =
30 arch: os:
31 let
32 arch' = arches.${arch} or (throw "unsupported architecture '${arch}'");
33 os' = oses.${os} or (throw "unsupported OS '${os}'");
34 in
35 "${arch'}-${os'}";
36
37 # All architectures that are supported by GCS
38 allArches = builtins.attrNames arches;
39
40 # A description of all available google-cloud-sdk components.
41 # It's a JSON file with a list of components, along with some metadata
42 snapshot = lib.importJSON snapshotPath;
43
44 # Generate a snapshot file for a single component. It has the same format as
45 # `snapshot`, but only contains a single component. These files are
46 # installed with google-cloud-sdk to let it know which components are
47 # available.
48 snapshotFromComponent =
49 {
50 component,
51 revision,
52 schema_version,
53 version,
54 }:
55 builtins.toJSON {
56 components = [ component ];
57 inherit revision schema_version version;
58 };
59
60 # Generate a set of components from a JSON file describing these components
61 componentsFromSnapshot =
62 {
63 components,
64 revision,
65 schema_version,
66 version,
67 ...
68 }:
69 lib.fix (
70 self:
71 builtins.listToAttrs (
72 builtins.map (component: {
73 name = component.id;
74 value = componentFromSnapshot self {
75 inherit
76 component
77 revision
78 schema_version
79 version
80 ;
81 };
82 }) components
83 )
84 );
85
86 # Generate a single component from its snapshot, along with a set of
87 # available dependencies to choose from.
88 componentFromSnapshot =
89 # Component derivations that can be used as dependencies
90 components:
91 # This component's snapshot
92 {
93 component,
94 revision,
95 schema_version,
96 version,
97 }@attrs:
98 let
99 baseUrl = builtins.dirOf schema_version.url;
100 # Architectures supported by this component. Defaults to all available
101 # architectures.
102 architectures = builtins.filter (arch: builtins.elem arch (builtins.attrNames arches)) (
103 lib.attrByPath [ "platform" "architectures" ] allArches component
104 );
105 # Operating systems supported by this component
106 operating_systems = builtins.filter (
107 os: builtins.elem os (builtins.attrNames oses)
108 ) component.platform.operating_systems;
109 in
110 mkComponent {
111 pname = component.id;
112 version = component.version.version_string;
113 src = lib.optionalString (lib.hasAttrByPath [
114 "data"
115 "source"
116 ] component) "${baseUrl}/${component.data.source}";
117 sha256 = lib.attrByPath [ "data" "checksum" ] "" component;
118 dependencies = builtins.map (dep: builtins.getAttr dep components) component.dependencies;
119 platforms =
120 if component.platform == { } then
121 lib.platforms.all
122 else
123 builtins.concatMap (arch: builtins.map (os: toNixPlatform arch os) operating_systems) architectures;
124 snapshot = snapshotFromComponent attrs;
125 };
126
127 # Filter out dependencies not supported by current system
128 filterForSystem = builtins.filter (drv: builtins.elem system drv.meta.platforms);
129
130 # Make a google-cloud-sdk component
131 mkComponent =
132 {
133 pname,
134 version,
135 # Source tarball, if any
136 src ? "",
137 # Checksum for the source tarball, if there is a source
138 sha256 ? "",
139 # Other components this one depends on
140 dependencies ? [ ],
141 # Short text describing the component
142 description ? "",
143 # Platforms supported
144 platforms ? lib.platforms.all,
145 # The snapshot corresponding to this component
146 snapshot,
147 }:
148 stdenv.mkDerivation {
149 inherit pname version snapshot;
150 src = lib.optionalString (src != "") (fetchurl {
151 url = src;
152 inherit sha256;
153 });
154 dontUnpack = true;
155 installPhase = ''
156 mkdir -p $out/google-cloud-sdk/.install
157
158 # If there is a source, unpack it
159 if [ ! -z "$src" ]; then
160 tar -xf $src -C $out/google-cloud-sdk/
161
162 # If the source has binaries, link them to `$out/bin`
163 if [ -d "$out/google-cloud-sdk/bin" ]; then
164 mkdir $out/bin
165 find $out/google-cloud-sdk/bin/ -type f -exec ln -s {} $out/bin/ \;
166 fi
167 fi
168
169 # Write the snapshot file to the `.install` folder
170 cp $snapshotPath $out/google-cloud-sdk/.install/${pname}.snapshot.json
171 '';
172 nativeBuildInputs = [
173 python3
174 stdenv.cc.cc
175 ]
176 ++ lib.optionals stdenv.hostPlatform.isLinux [
177 autoPatchelfHook
178 ];
179 buildInputs = [
180 libxcrypt-legacy
181 ];
182 passthru = {
183 dependencies = filterForSystem dependencies;
184 };
185 passAsFile = [ "snapshot" ];
186 meta = {
187 inherit description platforms;
188 };
189 };
190in
191componentsFromSnapshot snapshot