Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit bc51c29

Browse files
authored
Add script to download fuchsia sdk from GCS (#31026)
1 parent 46bea73 commit bc51c29

File tree

2 files changed

+202
-2
lines changed

2 files changed

+202
-2
lines changed

DEPS

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,11 @@ vars = {
7474
# Checkout Linux dependencies only when building on Linux.
7575
'download_linux_deps': 'host_os == "linux"',
7676

77+
# Downloads the fuchsia SDK as listed in .fuchsia_sdk_version. This variable
78+
# is currently only used for the Fuchsia LSC process and is not intended for
79+
# local development.
80+
'download_fuchsia_sdk': False,
81+
7782
# An LLVM backend needs LLVM binaries and headers. To avoid build time
7883
# increases we can use prebuilts. We don't want to download this on every
7984
# CQ/CI bot nor do we want the average Dart developer to incur that cost.
@@ -598,7 +603,7 @@ deps = {
598603
'version': 'OCj2VuVM1Sn0RL9v4BAB3HgWsqL-2gFJ0K_AqyoYc_gC'
599604
}
600605
],
601-
'condition': 'host_os == "mac"',
606+
'condition': 'host_os == "mac" and not download_fuchsia_sdk',
602607
'dep_type': 'cipd',
603608
},
604609
'src/fuchsia/sdk/linux': {
@@ -608,7 +613,7 @@ deps = {
608613
'version': 'uVt9IOhg0QAYFxhFt2f8NXSZ819CivnCR7-QX40796QC'
609614
}
610615
],
611-
'condition': 'host_os == "linux"',
616+
'condition': 'host_os == "linux" and not download_fuchsia_sdk',
612617
'dep_type': 'cipd',
613618
},
614619

@@ -712,6 +717,19 @@ hooks = [
712717
'--fail-loudly',
713718
]
714719
},
720+
{
721+
'name': 'Download Fuchsia SDK',
722+
'pattern': '.',
723+
'condition': 'download_fuchsia_sdk',
724+
'action': [
725+
'python3',
726+
'src/flutter/tools/download_fuchsia_sdk.py',
727+
'--fail-loudly',
728+
'--verbose',
729+
'--host-os',
730+
Var('host_os'),
731+
]
732+
},
715733
{
716734
'name': 'Setup githooks',
717735
'pattern': '.',

tools/download_fuchsia_sdk.py

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
#!/usr/bin/env python3
2+
# Copyright 2013 The Flutter 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+
# The return code of this script will always be 0, even if there is an error,
7+
# unless the --fail-loudly flag is passed.
8+
9+
10+
import argparse
11+
import tarfile
12+
import json
13+
import os
14+
import shutil
15+
import subprocess
16+
import sys
17+
18+
SRC_ROOT = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
19+
FUCHSIA_SDK_DIR = os.path.join(SRC_ROOT, 'fuchsia', 'sdk')
20+
FLUTTER_DIR = os.path.join(SRC_ROOT, 'flutter')
21+
SDK_VERSION_INFO_FILE = os.path.join(FLUTTER_DIR, '.fuchsia_sdk_version')
22+
23+
24+
# Prints to stderr.
25+
def eprint(*args, **kwargs):
26+
print(*args, file=sys.stderr, **kwargs)
27+
28+
29+
def FileNameForBucket(bucket):
30+
return bucket.split('/')[-1]
31+
32+
33+
def DownloadFuchsiaSDKFromGCS(bucket, verbose):
34+
file = FileNameForBucket(bucket)
35+
url = 'https://storage.googleapis.com/{}'.format(bucket)
36+
dest = os.path.join(FUCHSIA_SDK_DIR, file)
37+
38+
if verbose:
39+
print('Fuchsia SDK url: "%s"' % url)
40+
print('Fuchsia SDK destination path: "%s"' % dest)
41+
42+
if os.path.isfile(dest):
43+
os.unlink(dest)
44+
45+
curl_command = [
46+
'curl',
47+
'--retry', '3',
48+
'--continue-at', '-', '--location',
49+
'--output', dest,
50+
url,
51+
]
52+
if verbose:
53+
print('Running: "%s"' % (' '.join(curl_command)))
54+
curl_result = subprocess.run(
55+
curl_command,
56+
stdout=subprocess.PIPE,
57+
stderr=subprocess.PIPE,
58+
universal_newlines=True,
59+
)
60+
if curl_result.returncode == 0 and verbose:
61+
print('curl output:stdout:\n{}\nstderr:\n{}'.format(
62+
curl_result.stdout, curl_result.stderr,
63+
))
64+
elif curl_result.returncode != 0:
65+
eprint('Failed to download: stdout:\n{}\nstderr:\n{}'.format(
66+
curl_result.stdout, curl_result.stderr,
67+
))
68+
return None
69+
70+
return dest
71+
72+
73+
def OnErrorRmTree(func, path, exc_info):
74+
"""
75+
Error handler for ``shutil.rmtree``.
76+
77+
If the error is due to an access error (read only file)
78+
it attempts to add write permission and then retries.
79+
If the error is for another reason it re-raises the error.
80+
81+
Usage : ``shutil.rmtree(path, onerror=onerror)``
82+
"""
83+
import stat
84+
# Is the error an access error?
85+
if not os.access(path, os.W_OK):
86+
os.chmod(path, stat.S_IWUSR)
87+
func(path)
88+
else:
89+
raise
90+
91+
92+
def ExtractGzipArchive(archive, host_os, verbose):
93+
sdk_dest = os.path.join(FUCHSIA_SDK_DIR, host_os)
94+
if os.path.isdir(sdk_dest):
95+
shutil.rmtree(sdk_dest, onerror=OnErrorRmTree)
96+
97+
extract_dest = os.path.join(FUCHSIA_SDK_DIR, 'temp')
98+
if os.path.isdir(extract_dest):
99+
shutil.rmtree(extract_dest, onerror=OnErrorRmTree)
100+
os.makedirs(extract_dest, exist_ok=True)
101+
102+
if verbose:
103+
print('Extracting "%s" to "%s"' % (archive, extract_dest))
104+
105+
with tarfile.open(archive, 'r') as z:
106+
z.extractall(extract_dest)
107+
108+
shutil.move(extract_dest, sdk_dest)
109+
110+
111+
# Reads the version file and returns the bucket to download
112+
# The file is expected to live at the flutter directory and be named .fuchsia_sdk_version.
113+
#
114+
# The file is a JSON file which contains a single object with the following schema:
115+
# ```
116+
# {
117+
# "protocol": "gcs",
118+
# "identifiers": [
119+
# {
120+
# "host_os": "linux",
121+
# "bucket": "fuchsia-artifacts/development/8824687191341324145/sdk/linux-amd64/core.tar.gz"
122+
# }
123+
# ]
124+
# }
125+
# ```
126+
def ReadVersionFile(host_os):
127+
with open(SDK_VERSION_INFO_FILE) as f:
128+
try:
129+
version_obj = json.loads(f.read())
130+
if version_obj['protocol'] != 'gcs':
131+
eprint('The gcs protocol is the only suppoted protocl at this time')
132+
return None
133+
for id_obj in version_obj['identifiers']:
134+
if id_obj['host_os'] == host_os:
135+
return id_obj['bucket']
136+
except:
137+
eprint('Could not read JSON version file')
138+
return None
139+
140+
141+
def Main():
142+
parser = argparse.ArgumentParser()
143+
parser.add_argument(
144+
'--fail-loudly',
145+
action='store_true',
146+
default=False,
147+
help="Return an error code if a prebuilt couldn't be fetched and extracted")
148+
149+
parser.add_argument(
150+
'--verbose',
151+
action='store_true',
152+
default='LUCI_CONTEXT' in os.environ,
153+
help='Emit verbose output')
154+
155+
parser.add_argument(
156+
'--host-os',
157+
help='The host os')
158+
159+
args = parser.parse_args()
160+
fail_loudly = 1 if args.fail_loudly else 0
161+
verbose = args.verbose
162+
host_os = args.host_os
163+
164+
bucket = ReadVersionFile(host_os)
165+
166+
if bucket is None:
167+
eprint('Unable to find bucket in version file')
168+
return fail_loudly
169+
170+
archive = DownloadFuchsiaSDKFromGCS(bucket, verbose)
171+
if archive is None:
172+
eprint('Failed to download SDK from %s' % bucket)
173+
return fail_loudly
174+
175+
ExtractGzipArchive(archive, host_os, verbose)
176+
177+
success = True
178+
return 0 if success else fail_loudly
179+
180+
181+
if __name__ == '__main__':
182+
sys.exit(Main())

0 commit comments

Comments
 (0)