blob: 64e4a06a7601e69e1fa6737b74fe7f5437ed5099 [file] [log] [blame]
#!/usr/bin/env python
# Copyright 2017 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import argparse
import errno
import json
import os
import subprocess
import sys
import tempfile
DEFAULT_DST_ROOT = '/system'
DEFAULT_OUT_DIR = 'out/debug-x86-64'
def netaddr_cmd(out_dir, device):
path = os.path.join(out_dir, '../build-magenta/tools/netaddr')
command = [
path,
'--fuchsia',
device,
]
return command
def mkdir_p(path):
try:
os.makedirs(path)
except OSError as exc: # Python >2.5
if exc.errno == errno.EEXIST and os.path.isdir(path):
pass
else:
raise
def parse_package_file(package_file_path):
with open(package_file_path) as package_file:
data = json.load(package_file)
return data
def update_device(device, batch_file, verbose, out_dir):
ssh_config_path = os.path.join(out_dir, 'ssh-keys', 'ssh_config')
try:
netaddr = netaddr_cmd(out_dir, device)
ipv6 = '[' + subprocess.check_output(netaddr).strip() + ']'
except subprocess.CalledProcessError:
# netaddr prints its own errors, no need to add another one here.
return 1
with open(os.devnull, 'w') as devnull:
status = subprocess.call(
['sftp', '-F', ssh_config_path, '-b', batch_file, ipv6],
stdout=sys.stdout if verbose else devnull)
if status != 0:
print >> sys.stderr, 'error: sftp failed'
return status
def scp_everything(devices, package_data, out_dir, dst_root, name_filter,
verbose):
# Temporary file for sftp
with tempfile.NamedTemporaryFile() as f:
# Create a directory tree that mirrors what we want on the device.
for binary in package_data['binaries']:
binary_name = binary['binary']
if name_filter is not None and name_filter not in binary_name:
continue
src_path = os.path.join(out_dir, binary_name)
device_path = os.path.join(dst_root, binary['bootfs_path'].lstrip('/'))
# must "rm" the file first because memfs requires it
print >> f, '-rm %s' % device_path
print >> f, 'put -P %s %s' % (src_path, device_path)
f.flush()
for device in devices:
if update_device(device, f.name, verbose, out_dir) == 0:
print 'Updated %d files on "%s".' % (len(package_data['binaries']), device)
else:
print 'Update FAILED on "%s"' % device
return 0
def main():
parser = argparse.ArgumentParser()
parser.add_argument('package_file', help='JSON file containing package data')
parser.add_argument(
'device', default=[':'], nargs='*', help='Device to update')
parser.add_argument(
'-o',
'--out-dir',
metavar='DIR',
default=DEFAULT_OUT_DIR,
help='Directory containing build products')
parser.add_argument(
'-d',
'--dst-root',
metavar='PATH',
default=DEFAULT_DST_ROOT,
help='Path on device to the directory to copy package products')
parser.add_argument(
'-f',
'--filter',
metavar='FILTER',
help='Push products with a name that contains FILTER')
parser.add_argument(
'-v', '--verbose', action='store_true', help='Display copy filenames')
args = parser.parse_args()
package_data = parse_package_file(args.package_file)
out_dir = args.out_dir or DEFAULT_OUT_DIR
dst_root = args.dst_root or DEFAULT_DST_ROOT
name_filter = args.filter
verbose = args.verbose
return scp_everything(args.device, package_data, out_dir, dst_root,
name_filter, verbose)
if __name__ == '__main__':
sys.exit(main())