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

Commit 90327bc

Browse files
committed
Add script to download fuchsia sdk from GCS
Adds a script to download the Fuchsia SDK from a given GCS bucket. This script can run as an optional gclient hook to allow for the Fuchsia architecture to run LSC checks on commits to fuchsia.git.
1 parent 0ff9e89 commit 90327bc

File tree

2 files changed

+196
-2
lines changed

2 files changed

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

0 commit comments

Comments
 (0)