blob: 67fe3c772fcf2bf049049b497205affbb2841add [file] [log] [blame] [edit]
#!/usr/bin/env python3
# Copyright 2013 The Flutter Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
# The return code of this script will always be 0, even if there is an error,
# unless the --fail-loudly flag is passed.
import argparse
import tarfile
import json
import os
import shutil
import subprocess
import sys
SRC_ROOT = os.path.dirname(
os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
)
FUCHSIA_SDK_DIR = os.path.join(SRC_ROOT, 'fuchsia', 'sdk')
FLUTTER_DIR = os.path.join(SRC_ROOT, 'flutter')
# Prints to stderr.
def eprint(*args, **kwargs):
print(*args, file=sys.stderr, **kwargs)
def FileNameForSdkPath(sdk_path):
return sdk_path.split('/')[-1]
def DownloadFuchsiaSDKFromGCS(sdk_path, verbose):
file = FileNameForSdkPath(sdk_path)
url = 'https://storage.googleapis.com/fuchsia-artifacts/{}'.format(sdk_path)
dest = os.path.join(FUCHSIA_SDK_DIR, file)
if verbose:
print('Fuchsia SDK url: "%s"' % url)
print('Fuchsia SDK destination path: "%s"' % dest)
if os.path.isfile(dest):
os.unlink(dest)
# Ensure destination folder exists.
os.makedirs(FUCHSIA_SDK_DIR, exist_ok=True)
curl_command = [
'curl',
'--retry',
'3',
'--continue-at',
'-',
'--location',
'--output',
dest,
url,
]
if verbose:
print('Running: "%s"' % (' '.join(curl_command)))
curl_result = subprocess.run(
curl_command,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
universal_newlines=True,
)
if curl_result.returncode == 0 and verbose:
print(
'curl output:stdout:\n{}\nstderr:\n{}'.format(
curl_result.stdout,
curl_result.stderr,
)
)
elif curl_result.returncode != 0:
eprint(
'Failed to download: stdout:\n{}\nstderr:\n{}'.format(
curl_result.stdout,
curl_result.stderr,
)
)
return None
return dest
def OnErrorRmTree(func, path, exc_info):
"""
Error handler for ``shutil.rmtree``.
If the error is due to an access error (read only file)
it attempts to add write permission and then retries.
If the error is for another reason it re-raises the error.
Usage : ``shutil.rmtree(path, onerror=onerror)``
"""
import stat
# Is the error an access error?
if not os.access(path, os.W_OK):
os.chmod(path, stat.S_IWUSR)
func(path)
else:
raise
def ExtractGzipArchive(archive, host_os, verbose):
sdk_dest = os.path.join(FUCHSIA_SDK_DIR, host_os)
if os.path.isdir(sdk_dest):
shutil.rmtree(sdk_dest, onerror=OnErrorRmTree)
extract_dest = os.path.join(FUCHSIA_SDK_DIR, 'temp')
if os.path.isdir(extract_dest):
shutil.rmtree(extract_dest, onerror=OnErrorRmTree)
os.makedirs(extract_dest, exist_ok=True)
if verbose:
print('Extracting "%s" to "%s"' % (archive, extract_dest))
with tarfile.open(archive, 'r') as z:
z.extractall(extract_dest)
shutil.move(extract_dest, sdk_dest)
def Main():
parser = argparse.ArgumentParser()
parser.add_argument(
'--fail-loudly',
action='store_true',
default=False,
help="Return an error code if a prebuilt couldn't be fetched and extracted"
)
parser.add_argument(
'--verbose',
action='store_true',
default='LUCI_CONTEXT' in os.environ,
help='Emit verbose output'
)
parser.add_argument('--host-os', help='The host os')
parser.add_argument(
'--fuchsia-sdk-path',
help='The path in gcs to the fuchsia sdk to download'
)
args = parser.parse_args()
fail_loudly = 1 if args.fail_loudly else 0
verbose = args.verbose
host_os = args.host_os
fuchsia_sdk_path = args.fuchsia_sdk_path
if fuchsia_sdk_path is None:
eprint('sdk_path can not be empty')
return fail_loudly
archive = DownloadFuchsiaSDKFromGCS(fuchsia_sdk_path, verbose)
if archive is None:
eprint('Failed to download SDK from %s' % fuchsia_sdk_path)
return fail_loudly
ExtractGzipArchive(archive, host_os, verbose)
success = True
return 0 if success else fail_loudly
if __name__ == '__main__':
sys.exit(Main())