blob: b14669ef31a7d187d051fede4692594e57501181 [file] [log] [blame] [view]
Haiyang Pan7760b292021-02-12 23:16:321# CIPD and 3pp for chromium dependencies
2
3[TOC]
4
5## What is CIPD?
6* CIPD stands for "Chrome Infrastructure Package Deployment".
7* Its code and docs [live within the luci-go project][CIPD].
8* Chromium uses CIPD to avoid checking large binary files into git, which git
9 does not handle well.
10* gclient supports CIPD packages in the same way as git repositories. They are
11 specified in [DEPS] and updated via `gclient sync`.
12* You can [browse Chromium's CIPD repository][browse] online.
13
John Palmer046f9872021-05-24 01:24:5614[CIPD]: https://chromium.googlesource.com/infra/luci/luci-go/+/main/cipd/README.md
Haiyang Pan7760b292021-02-12 23:16:3215[DEPS]: /DEPS
16[browse]: https://chrome-infra-packages.appspot.com/p/chromium
17
18## What is 3pp?
19* 3pp stands for "Third Party Packages" which allows uniform cross-compiliation,
20 version tracking and archival for third-party software packages for
21 distribution via CIPD.
22* The code and docs [live within the recipe module support_3pp][support_3pp].
23* By specifying a 3pp package, you can define how to build certain artifacts and
24 where to upload to CIPD. Then our packagers will do the rest for you.
25
John Palmer046f9872021-05-24 01:24:5626[support_3pp]: https://chromium.googlesource.com/infra/infra/+/main/recipes/README.recipes.md#recipe_modules-support_3pp
Haiyang Pan7760b292021-02-12 23:16:3227
28## Why use CIPD & 3pp?:
29
30* CIPD is our solution to storing large binary blobs directly in git, which git
31 is not good at.
32* Building these packages with 3pp is beneficial because:
33 * It makes how each binary file was created clear and verifiable.
34 * It avoids the need for maintaining a list of ACLs for uploading to CIPD.
35
36## Adding a new 3pp package
37
38### 1. Set up a new directory for your dependency
39
40You'll first want somewhere in the repository in which your dependency will
41live. For third-party dependencies, this should typically be a subdirectory
42of `//third_party`. You'll need to add the same set of things to that
43directory that you'd add for a non-CIPD dependency -- OWNERS, README.chromium,
44etc.
45
46For example, if you want to add a package named `sample_cipd_dep`, you might
47create the following:
48
49```
50 third_party/
51 sample_cipd_dep/
52 LICENSE
53 OWNERS
54 README.chromium
55```
56
57For more on third-party dependencies, see [adding_to_third_party.md].
58
59[adding_to_third_party.md]: /docs/adding_to_third_party.md
60
61### 2. Set up the 3pp subdirectory
62
63The 3pp subdirectory will store all the 3pp related files, including a 3pp spec
64(`3pp.pb`), as well as scripts, patches and/or tools to build the software
Joanna Wangf85e1bc2024-08-14 21:35:4665from source. It should be placed directly under the directory path that matches
66the desired name of the cipd package.
Haiyang Pan7760b292021-02-12 23:16:3267
68Staying with the example from above, the `sample_cipd_dep` directory may be
69like the following.
70
71> Note that among the files in 3pp subdirectory, the `3pp.pb` is always
72> required. The rest are optional, depending on how the `3pp.pb` is specified.
73
74```
75 third_party/
76 sample_cipd_dep/
77 LICENSE
78 OWNERS
79 README.chromium
80 3pp/
81 3pp.pb # REQUIRED
82 bootstrap.py
83 fetch.py
84 install.sh
85 install_win.sh
86 patches/
87 0001-foo.patch
88```
89
90#### 2.1 The file `3pp.pb` (Required)
91
92`3pp.pb` is a text proto specified by the **[`spec.proto`]** schema. It is broken up
93into two main sections:
94* `create`: allows you to specify how the package software gets created, and
95 allows specifying differences in how it's fetched/built/tested on a
96 per-target basis. See [here][doc_create] for more details.
97* `upload`: contains some details on how the final result gets uploaded to CIPD.
98 See [here][doc_upload] for more details.
99
John Palmer046f9872021-05-24 01:24:56100[`spec.proto`]: https://chromium.googlesource.com/infra/infra/+/main/recipes/recipe_modules/support_3pp/spec.proto
101[doc_create]: https://chromium.googlesource.com/infra/infra/+/main/recipes/README.recipes.md#creation-stages
102[doc_upload]: https://chromium.googlesource.com/infra/infra/+/main/recipes/README.recipes.md#upload
Haiyang Pan7760b292021-02-12 23:16:32103
104Staying with the example from above, the file `sample_cipd_dep/3pp/3pp.pb` may
105be like the following:
106
107```
108create {
109 source {
110 url {
111 download_url: "https://some_url_link/foo.zip"
112 version: "1.0.0"
113 extension: ".zip"
114 }
115 patch_version: "cr0"
116 unpack_archive: true
117 }
118}
119
120upload {
121 pkg_prefix: "tools"
122 universal: true
123}
124```
125
126While the above example could meet most of the use case, `3pp.pb` is capable of
127handling more complicated use case like the following:
128
129```
130# create section that is shared by linux-.* and mac-.* platforms
131create {
132 platform_re: "linux-.*|mac-.*"
133 source {
134 git {
135 repo: "<one_git_repo>"
136 tag_pattern: "v%s",
137
138 # Fixed to 3.8.x for now.
139 version_restriction: { op: LT val: "3.9a0"}
140 }
141 patch_dir: "patches"
142 }
143 build {
144 # Can also leave as blank since the script name defaults to "install.sh"
145 install: "install.sh"
146 }
147}
148
149# create section that is specific to linux-.* platforms
150create {
151 platform_re: "linux-.*"
152 build {
153 dep: "<dep_foo>"
154 dep: "<dep_bar>"
155
156 tool: "<tool_foo>"
157 }
158}
159
160# create section that is specific to linux-arm.* and linux-mips.* platforms
161create {
162 platform_re: "linux-arm.*|linux-mips.*"
163 build {
164 tool: "<tool_bar>"
165 }
166}
167
168# create section that is specific to windows-*
169create {
170 platform_re: "windows-.*"
171 source { script { name: "fetch.py" } }
172 build {
173 install: "install_win.sh"
174 }
175}
176
177upload { pkg_prefix: "tools" }
178```
179
180#### 2.2 The file `install.sh` (Optional)
181
182When the `build` message is specified in `3pp.pb`, the file specified in
183"build.install" (Default to "install.sh") will be run to transform the source
184into the built product.
185
186Staying with the example from above, the file `sample_cipd_dep/3pp/install.sh`
187may be like the following.
188
189> Note that during the build stage, the 3pp directory and all its dependent 3pp
190> directories (i.e. the `tool` and `dep` from the `build` message in `3pp.pb`)
191> will be [copied to a different directory]. So commands in `install.sh` should
192> not refer to files that are outside of these directories.
193
194[copied to a different directory]: https://chromium.googlesource.com/infra/infra/+/53fd7d1eda2010009ed00fdc1a7b59fe5034ae0c/recipes/recipe_modules/support_3pp/source.py#246
195
196```
197#!/bin/bash
Avi Drissman7b017a992022-09-07 15:50:38198# Copyright 2021 The Chromium Authors
Haiyang Pan7760b292021-02-12 23:16:32199# Use of this source code is governed by a BSD-style license that can be
200# found in the LICENSE file.
201
202set -e
203set -x
204set -o pipefail
205
206# An auto-created directory whose content will ultimately be uploaded to CIPD.
207# So the commands below should output the built product to this directory.
208PREFIX="$1"
209
210# Commands to transform the source into the built product and move it to $PREFIX
211./configure
212make install
213
214SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
215cp -a bin_foo "$SCRIPT_DIR/bootstrap.py" "$PREFIX"
216```
217
218#### 2.3 The file `fetch.py` (Optional)
219
220When specifying the `source` in 3pp.pb, it is possible to use a custom catch-all
221script to probe for the latest version and obtain the latest sources. A simple
222example can be like the following:
223
Haiyang Pan19302452023-03-03 22:50:49224> Note that this python script should be **python3-compatible**.
225
Haiyang Pan7760b292021-02-12 23:16:32226```
Haiyang Pan19302452023-03-03 22:50:49227#!/usr/bin/env python3
228# Copyright 2023 The Chromium Authors
Haiyang Pan7760b292021-02-12 23:16:32229# Use of this source code is governed by a BSD-style license that can be
230# found in the LICENSE file.
231
Haiyang Pan7760b292021-02-12 23:16:32232import argparse
233import json
234import os
235import urllib
236
237
238def do_latest():
239 print(urllib.urlopen('some_url/master/VERSION').read().strip())
240
241
242def get_download_url(version, platform):
243 target_os, target_arch = platform.split('-')
244 ext = '.zip' if target_os == 'windows' else '.tar.gz'
245 partial_manifest = {
246 'url': ['download_url1', 'download_url2'],
247 'ext': ext,
248 }
249 print(json.dumps(partial_manifest))
250
251
252def main():
253 ap = argparse.ArgumentParser()
254 sub = ap.add_subparsers()
255
256 latest = sub.add_parser("latest")
257 latest.set_defaults(func=lambda _opts: do_latest())
258
259 download = sub.add_parser("get_url")
260 download.set_defaults(
261 func=lambda _opts: get_download_url(
262 os.environ['_3PP_VERSION'], os.environ['_3PP_PLATFORM']
263 )
264 )
265
266 opts = ap.parse_args()
267 opts.func(opts)
268
269
270if __name__ == '__main__':
271 main()
272```
273
274### 3. Add "3pp" subdirectory to `chromium/src` repo
275
276#### 3pp CQ builders (Presubmit)
277
278The following are the optional CQ builders to run the presubmit check for CLs
279that have the directory "3pp" in the patchset.
280
281* [3pp-linux-amd64-packager](https://ci.chromium.org/p/chromium/builders/try/3pp-linux-amd64-packager):
282 For builds on the linux-amd64 platform or universal builds (e.g. to be used by
283 all platforms)
284
285#### 3pp CI builders (Postsubmit)
286
287Once the CLs pass the CQ and get landed, the following CI builders will
288periodically build all the 3pp packages that match the given platforms and
289upload any new results to CIPD.
290
291* [3pp-linux-amd64-packager](https://ci.chromium.org/p/chromium/builders/ci/3pp-linux-amd64-packager):
292 For builds on the linux-amd64 platform or universal builds (e.g. to be used by
293 all platforms)
294
295### 4. Add your CIPD package to DEPS
296
297Once your CIPD package is created by the 3pp CI builders, you can add it to
298`DEPS` by adding an entry of the following form to the `deps` dict:
299
300```
301deps = {
302 # ...
303
304 # This is the installation directory.
305 'src/third_party/sample_cipd_dep': {
306
307 # In this example, we're only installing one package in this location,
308 # but installing multiple package in a location is supported.
309 'packages': [
310 {
311 'package': 'chromium/third_party/sample_cipd_dep',
312 'version': 'TX7HeY1_1JLwFVx-xiETOpT8YK4W5CbyO26SpmaMA0IC',
313 },
314 ],
315
316 # As with git-based DEPS entries, 'condition' is optional.
317 'condition': 'checkout_android',
318 'dep_type': 'cipd',
319 },
320
321 # ...
322}
323```
324
325This will result in CIPD package `chromium/third_party/sample_cipd_dep` at
326`TX7HeY1_1JLwFVx-xiETOpT8YK4W5CbyO26SpmaMA0IC` being installed in
327`src/third_party/sample_cipd_dep` (relative to the gclient root directory).
328
329## Updating a CIPD dependency
330
331To modify a CIPD dependency, follow steps 2 and 3 above, then modify the
332version listed in DEPS.
333
334## Miscellaneous
335
336### Create a cipd.yaml file in the old way
337
338While it is strongly suggested to use 3pp infrastructure, there are existing flows
339that create a cipd.yaml file by a GN template or a script, and upload it to CIPD
340by builders with custom recipes.
341
342Examples are:
343* [android-androidx-packager](https://ci.chromium.org/p/chromium/builders/ci/android-androidx-packager)
344* [android-sdk-packager](https://ci.chromium.org/p/chromium/builders/ci/android-sdk-packager)
345
346#### Generating cipd.yaml via GN Template:
347The `cipd_package_definition` template in [build/cipd/cipd.gni] can be used to
348create the yaml definition as part of Chromium's normal build process. Declare
349a target like:
350```
351cipd_package_definition("my_cipd_package") {
352 package = "path/to/cipd/package"
353 description = "Prebuilt test binary."
354 install_mode = "copy"
355 deps = [ "//path/to:test_binary_target" ]
356 sources = [ "//path/to:test_binary_file" ]
357}
358```
John Palmer046f9872021-05-24 01:24:56359[build/cipd/cipd.gni]: https://source.chromium.org/chromium/chromium/src/+/main:build/cipd/cipd.gni
Haiyang Pan7760b292021-02-12 23:16:32360
361### Permissions in CIPD
362
363You can check a package's ACLs with `cipd acl-list`:
364
365```
366$ cipd acl-list chromium/third_party/sample_cipd_dep
367...
368```
369
370Permissions in CIPD are handled hierarchically. You can check entries higher
371in the package hierarchy with `cipd acl-list`, too:
372
373```
374$ cipd acl-list chromium
375...
376```
377
378By default, [cria/project-chromium-cipd-owners][cria] own all CIPD packages
379under `chromium/`. If you're adding a package, talk to one of them.
380
381To obtain write access to a new package, ask an owner to run:
382
383```
384$ cipd acl-edit chromium/third_party/sample_cipd_dep -owner user:[email protected]
385```
386
387[cria]: https://chrome-infra-auth.appspot.com/auth/groups/project-chromium-cipd-owners
388
389## Troubleshooting
390
391 - **A file maintained by CIPD is missing, and gclient sync doesn't recreate it.**
392
393CIPD currently caches installation state. Modifying packages managed by CIPD
394will invalidate this cache in a way that CIPD doesn't detect - i.e., CIPD will
395assume that anything it installed is still installed, even if you deleted it.
396To clear the cache and force a full reinstallation, delete your
397`$GCLIENT_ROOT/.cipd` directory.
398
399Note that there is a [bug](https://crbug.com/1176408) on file where
400`gclient sync` does not reset CIPD entries that are changed locally.