• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2# Copyright 2020 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6"""Gets info about completed chromiumos-sdk runs.
7
8Moreover, this script exists to get versions of published sdk tarballs in
9gs://chromiumos-sdk/. The hope is that it'll help answer the question "when did
10the toolchain ebuild ${x} go live?"
11"""
12
13import argparse
14import json
15import logging
16import os
17import shutil
18import subprocess
19import sys
20import tempfile
21from typing import Dict, List
22from pathlib import Path
23
24
25def fetch_all_sdk_manifest_paths() -> List[str]:
26  """Fetches all paths of SDK manifests; newer = later in the return value."""
27  results = subprocess.run(
28      ['gsutil', 'ls', 'gs://chromiumos-sdk/cros-sdk-20??.*.Manifest'],
29      check=True,
30      stdout=subprocess.PIPE,
31      encoding='utf-8',
32  ).stdout
33  # These are named so that sorted order == newest last.
34  return sorted(x.strip() for x in results.splitlines())
35
36
37def fetch_manifests_into(into_dir: Path, manifests: List[str]):
38  # Wrap this in a `try` block because gsutil likes to print to stdout *and*
39  # stderr even on success, so we silence them & only print on failure.
40  try:
41    subprocess.run(
42        [
43            'gsutil',
44            '-m',
45            'cp',
46            '-I',
47            str(into_dir),
48        ],
49        check=True,
50        input='\n'.join(manifests),
51        stdout=subprocess.PIPE,
52        stderr=subprocess.STDOUT,
53        encoding='utf-8',
54    )
55  except subprocess.CalledProcessError as e:
56    logging.exception('gsutil failed; output:\n%s', e.stdout)
57
58
59def load_manifest_versions(manifest: Path) -> Dict[str, str]:
60  with manifest.open(encoding='utf-8') as f:
61    raw_versions = json.load(f)
62
63  # We get a dict of list of lists of versions and some other metadata, e.g.
64  # {"foo/bar": [["1.2.3", {}]]}
65  # Trim out the metadata.
66  return {k: v[0][0] for k, v in raw_versions['packages'].items()}
67
68
69def main():
70  parser = argparse.ArgumentParser(
71      description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
72  parser.add_argument(
73      '-d', '--debug', action='store_true', help='Emit debugging output')
74  parser.add_argument(
75      '-n',
76      '--number',
77      type=int,
78      default=20,
79      help='Number of recent manifests to fetch info about. 0 means unlimited.')
80  args = parser.parse_args()
81
82  is_debug = args.debug
83  logging.basicConfig(level=logging.DEBUG if is_debug else logging.INFO)
84
85  logging.debug('Fetching SDK manifests')
86  manifest_paths = fetch_all_sdk_manifest_paths()
87  logging.debug('%d SDK manifests fetched', len(manifest_paths))
88
89  number = args.number
90  if number:
91    manifest_paths = manifest_paths[-number:]
92
93  tempdir = Path(tempfile.mkdtemp(prefix='cros-sdk-rolls'))
94  try:
95    logging.debug('Working in tempdir %r', tempdir)
96    fetch_manifests_into(tempdir, manifest_paths)
97
98    for path in manifest_paths:
99      basename = os.path.basename(path)
100      versions = load_manifest_versions(tempdir.joinpath(basename))
101      print(f'{basename}: {versions["sys-devel/llvm"]}')
102  finally:
103    if is_debug:
104      logging.debug('Keeping around tempdir %r to aid debugging', tempdir)
105    else:
106      shutil.rmtree(tempdir)
107
108
109if __name__ == '__main__':
110  sys.exit(main())
111