15f9996aaSopenharmony_ci#!/usr/bin/env python 25f9996aaSopenharmony_ci# -*- coding: utf-8 -*- 35f9996aaSopenharmony_ci# Copyright 2014 The Chromium Authors. All rights reserved. 45f9996aaSopenharmony_ci# Use of this source code is governed by a BSD-style license that can be 55f9996aaSopenharmony_ci# found in the LICENSE file. 65f9996aaSopenharmony_ci"""Copies files to a directory.""" 75f9996aaSopenharmony_ci 85f9996aaSopenharmony_ciimport filecmp 95f9996aaSopenharmony_ciimport itertools 105f9996aaSopenharmony_ciimport optparse 115f9996aaSopenharmony_ciimport os 125f9996aaSopenharmony_ciimport shutil 135f9996aaSopenharmony_ciimport sys 145f9996aaSopenharmony_ci 155f9996aaSopenharmony_cifrom util import build_utils 165f9996aaSopenharmony_ci 175f9996aaSopenharmony_ci 185f9996aaSopenharmony_cidef copy_tree(src: str, 195f9996aaSopenharmony_ci dest: str, 205f9996aaSopenharmony_ci follow_all_symlinks=False, 215f9996aaSopenharmony_ci follow_outside_symlinks=False): 225f9996aaSopenharmony_ci """copy src/* to dest/ 235f9996aaSopenharmony_ci I. If follow_outside_symlinks is true, 245f9996aaSopenharmony_ci 1. If src item is a symlink, and points to some item inside src, 255f9996aaSopenharmony_ci then copy the symlink to dest. 265f9996aaSopenharmony_ci 2. If src item points to items outside src, then follow links to copy 275f9996aaSopenharmony_ci the original file to dest. 285f9996aaSopenharmony_ci 3. Else copy src item to dest. 295f9996aaSopenharmony_ci II. If follow_all_symlinks is true, 305f9996aaSopenharmony_ci 1. If src item is a symlink, then follow links to copy the original file 315f9996aaSopenharmony_ci to dest. 325f9996aaSopenharmony_ci 2. Else copy src item to dest. 335f9996aaSopenharmony_ci follow_outside_symlinks is true when follow_all_symlinks is true. 345f9996aaSopenharmony_ci """ 355f9996aaSopenharmony_ci with os.scandir(src) as itr: 365f9996aaSopenharmony_ci items = list(itr) 375f9996aaSopenharmony_ci return _do_copy_tree(items, 385f9996aaSopenharmony_ci src, 395f9996aaSopenharmony_ci dest, 405f9996aaSopenharmony_ci follow_all_symlinks=follow_all_symlinks, 415f9996aaSopenharmony_ci follow_outside_symlinks=follow_outside_symlinks) 425f9996aaSopenharmony_ci 435f9996aaSopenharmony_ci 445f9996aaSopenharmony_cidef _do_copy_tree(items: list, 455f9996aaSopenharmony_ci src: str, 465f9996aaSopenharmony_ci dest: str, 475f9996aaSopenharmony_ci follow_all_symlinks: bool = False, 485f9996aaSopenharmony_ci follow_outside_symlinks: bool = False) -> str: 495f9996aaSopenharmony_ci os.makedirs(dest, exist_ok=True) 505f9996aaSopenharmony_ci for item in items: 515f9996aaSopenharmony_ci srcname = os.path.join(src, item.name) 525f9996aaSopenharmony_ci destname = os.path.join(dest, item.name) 535f9996aaSopenharmony_ci is_symlink = item.is_symlink() 545f9996aaSopenharmony_ci if is_symlink: 555f9996aaSopenharmony_ci org_linkto = os.readlink(srcname) 565f9996aaSopenharmony_ci linkto = org_linkto 575f9996aaSopenharmony_ci if not os.path.isabs(org_linkto): 585f9996aaSopenharmony_ci linkto = os.path.join(os.path.dirname(item), org_linkto) 595f9996aaSopenharmony_ci 605f9996aaSopenharmony_ci if not os.path.exists(linkto): 615f9996aaSopenharmony_ci os.symlink(org_linkto, destname) 625f9996aaSopenharmony_ci shutil.copymode(srcname, destname, follow_symlinks=False) 635f9996aaSopenharmony_ci continue 645f9996aaSopenharmony_ci 655f9996aaSopenharmony_ci if follow_all_symlinks: 665f9996aaSopenharmony_ci if item.is_dir(): 675f9996aaSopenharmony_ci copy_tree(item, 685f9996aaSopenharmony_ci destname, 695f9996aaSopenharmony_ci follow_all_symlinks=follow_all_symlinks, 705f9996aaSopenharmony_ci follow_outside_symlinks=follow_outside_symlinks) 715f9996aaSopenharmony_ci else: 725f9996aaSopenharmony_ci shutil.copy(item, destname) 735f9996aaSopenharmony_ci shutil.copymode(item, destname) 745f9996aaSopenharmony_ci 755f9996aaSopenharmony_ci elif follow_outside_symlinks: 765f9996aaSopenharmony_ci if os.path.abspath(src) in os.path.abspath( 775f9996aaSopenharmony_ci linkto) and not os.path.isabs(org_linkto): 785f9996aaSopenharmony_ci os.symlink(org_linkto, destname) 795f9996aaSopenharmony_ci shutil.copymode(srcname, destname, follow_symlinks=False) 805f9996aaSopenharmony_ci else: 815f9996aaSopenharmony_ci if item.is_dir(): 825f9996aaSopenharmony_ci copy_tree( 835f9996aaSopenharmony_ci item, 845f9996aaSopenharmony_ci destname, 855f9996aaSopenharmony_ci follow_all_symlinks=follow_all_symlinks, 865f9996aaSopenharmony_ci follow_outside_symlinks=follow_outside_symlinks) 875f9996aaSopenharmony_ci else: 885f9996aaSopenharmony_ci shutil.copy(item, destname) 895f9996aaSopenharmony_ci shutil.copymode(item, destname) 905f9996aaSopenharmony_ci else: 915f9996aaSopenharmony_ci os.symlink(org_linkto, destname) 925f9996aaSopenharmony_ci shutil.copymode(srcname, destname, follow_symlinks=False) 935f9996aaSopenharmony_ci elif item.is_dir(): 945f9996aaSopenharmony_ci copy_tree(item, 955f9996aaSopenharmony_ci destname, 965f9996aaSopenharmony_ci follow_all_symlinks=follow_all_symlinks, 975f9996aaSopenharmony_ci follow_outside_symlinks=follow_outside_symlinks) 985f9996aaSopenharmony_ci else: 995f9996aaSopenharmony_ci shutil.copy(item, destname) 1005f9996aaSopenharmony_ci shutil.copymode(item, destname) 1015f9996aaSopenharmony_ci shutil.copystat(src, dest) 1025f9996aaSopenharmony_ci return dest 1035f9996aaSopenharmony_ci 1045f9996aaSopenharmony_ci 1055f9996aaSopenharmony_cidef copy_file(f: str, 1065f9996aaSopenharmony_ci dest: str, 1075f9996aaSopenharmony_ci deps: list, 1085f9996aaSopenharmony_ci follow_all_symlinks: bool = False, 1095f9996aaSopenharmony_ci follow_outside_symlinks: bool = False): 1105f9996aaSopenharmony_ci """Copy file or directory and update deps.""" 1115f9996aaSopenharmony_ci if os.path.isdir(f): 1125f9996aaSopenharmony_ci copy_tree(f, 1135f9996aaSopenharmony_ci os.path.join(dest, os.path.basename(f)), 1145f9996aaSopenharmony_ci follow_all_symlinks=follow_all_symlinks, 1155f9996aaSopenharmony_ci follow_outside_symlinks=follow_outside_symlinks) 1165f9996aaSopenharmony_ci deps.extend(build_utils.get_all_files(f)) 1175f9996aaSopenharmony_ci else: 1185f9996aaSopenharmony_ci if os.path.isfile(os.path.join(dest, os.path.basename(f))): 1195f9996aaSopenharmony_ci dest = os.path.join(dest, os.path.basename(f)) 1205f9996aaSopenharmony_ci 1215f9996aaSopenharmony_ci deps.append(f) 1225f9996aaSopenharmony_ci 1235f9996aaSopenharmony_ci if os.path.isfile(dest): 1245f9996aaSopenharmony_ci if filecmp.cmp(dest, f, shallow=False): 1255f9996aaSopenharmony_ci return 1265f9996aaSopenharmony_ci # The shutil.copy() below would fail if the file does not 1275f9996aaSopenharmony_ci # have write permissions. Deleting the file 1285f9996aaSopenharmony_ci # has similar costs to modifying the permissions. 1295f9996aaSopenharmony_ci os.unlink(dest) 1305f9996aaSopenharmony_ci 1315f9996aaSopenharmony_ci shutil.copy(f, dest) 1325f9996aaSopenharmony_ci 1335f9996aaSopenharmony_ci 1345f9996aaSopenharmony_cidef do_copy(options, deps: list): 1355f9996aaSopenharmony_ci """Copy files or directories given in options.files and update deps.""" 1365f9996aaSopenharmony_ci files = list( 1375f9996aaSopenharmony_ci itertools.chain.from_iterable( 1385f9996aaSopenharmony_ci build_utils.parse_gn_list(f) for f in options.files)) 1395f9996aaSopenharmony_ci 1405f9996aaSopenharmony_ci for f in files: 1415f9996aaSopenharmony_ci if not options.ignore_stale: 1425f9996aaSopenharmony_ci if os.path.isdir(f) and not options.clear: 1435f9996aaSopenharmony_ci print('To avoid stale files you must use --clear when copying ' 1445f9996aaSopenharmony_ci 'directories') 1455f9996aaSopenharmony_ci sys.exit(-1) 1465f9996aaSopenharmony_ci copy_file(f, 1475f9996aaSopenharmony_ci options.dest, 1485f9996aaSopenharmony_ci deps, 1495f9996aaSopenharmony_ci follow_all_symlinks=options.follow_all_symlinks, 1505f9996aaSopenharmony_ci follow_outside_symlinks=options.follow_outside_symlinks) 1515f9996aaSopenharmony_ci 1525f9996aaSopenharmony_ci 1535f9996aaSopenharmony_cidef do_renaming(options, deps: list): 1545f9996aaSopenharmony_ci """Copy and rename files given in options.renaming_sources 1555f9996aaSopenharmony_ci and update deps. 1565f9996aaSopenharmony_ci """ 1575f9996aaSopenharmony_ci src_files = list( 1585f9996aaSopenharmony_ci itertools.chain.from_iterable( 1595f9996aaSopenharmony_ci build_utils.parse_gn_list(f) for f in options.renaming_sources)) 1605f9996aaSopenharmony_ci 1615f9996aaSopenharmony_ci dest_files = list( 1625f9996aaSopenharmony_ci itertools.chain.from_iterable( 1635f9996aaSopenharmony_ci build_utils.parse_gn_list(f) 1645f9996aaSopenharmony_ci for f in options.renaming_destinations)) 1655f9996aaSopenharmony_ci 1665f9996aaSopenharmony_ci if (len(src_files) != len(dest_files)): 1675f9996aaSopenharmony_ci print('Renaming source and destination files not match.') 1685f9996aaSopenharmony_ci sys.exit(-1) 1695f9996aaSopenharmony_ci 1705f9996aaSopenharmony_ci for src, dest in zip(src_files, dest_files): 1715f9996aaSopenharmony_ci if os.path.isdir(src): 1725f9996aaSopenharmony_ci print('renaming directory is not supported.') 1735f9996aaSopenharmony_ci sys.exit(-1) 1745f9996aaSopenharmony_ci else: 1755f9996aaSopenharmony_ci copy_file(src, os.path.join(options.dest, dest), deps) 1765f9996aaSopenharmony_ci 1775f9996aaSopenharmony_ci 1785f9996aaSopenharmony_cidef main(args): 1795f9996aaSopenharmony_ci args = build_utils.expand_file_args(args) 1805f9996aaSopenharmony_ci 1815f9996aaSopenharmony_ci parser = optparse.OptionParser() 1825f9996aaSopenharmony_ci build_utils.add_depfile_option(parser) 1835f9996aaSopenharmony_ci 1845f9996aaSopenharmony_ci parser.add_option('--dest', help='Directory to copy files to.') 1855f9996aaSopenharmony_ci parser.add_option('--files', 1865f9996aaSopenharmony_ci action='append', 1875f9996aaSopenharmony_ci help='List of files to copy.') 1885f9996aaSopenharmony_ci parser.add_option( 1895f9996aaSopenharmony_ci '--clear', 1905f9996aaSopenharmony_ci action='store_true', 1915f9996aaSopenharmony_ci help='If set, the destination directory will be deleted ' 1925f9996aaSopenharmony_ci 'before copying files to it. This is highly recommended to ' 1935f9996aaSopenharmony_ci 'ensure that no stale files are left in the directory.') 1945f9996aaSopenharmony_ci parser.add_option('--ignore-stale', 1955f9996aaSopenharmony_ci action='store_true', 1965f9996aaSopenharmony_ci help='Do copy even there may be stale files. ' 1975f9996aaSopenharmony_ci 'If set, overrule options.clear') 1985f9996aaSopenharmony_ci parser.add_option('--stamp', help='Path to touch on success.') 1995f9996aaSopenharmony_ci parser.add_option('--follow-all-symlinks', 2005f9996aaSopenharmony_ci action='store_true', 2015f9996aaSopenharmony_ci help='whether to follow symlinks') 2025f9996aaSopenharmony_ci parser.add_option( 2035f9996aaSopenharmony_ci '--follow-outside-symlinks', 2045f9996aaSopenharmony_ci action='store_true', 2055f9996aaSopenharmony_ci help='whether to follow symlinks which points to targets outside of' 2065f9996aaSopenharmony_ci 'source directory') 2075f9996aaSopenharmony_ci parser.add_option('--renaming-sources', 2085f9996aaSopenharmony_ci action='append', 2095f9996aaSopenharmony_ci help='List of files need to be renamed while being ' 2105f9996aaSopenharmony_ci 'copied to dest directory') 2115f9996aaSopenharmony_ci parser.add_option('--renaming-destinations', 2125f9996aaSopenharmony_ci action='append', 2135f9996aaSopenharmony_ci help='List of destination file name without path, the ' 2145f9996aaSopenharmony_ci 'number of elements must match rename-sources.') 2155f9996aaSopenharmony_ci 2165f9996aaSopenharmony_ci options, _ = parser.parse_args(args) 2175f9996aaSopenharmony_ci if options.follow_all_symlinks: 2185f9996aaSopenharmony_ci options.follow_outside_symlinks = True 2195f9996aaSopenharmony_ci 2205f9996aaSopenharmony_ci if options.clear and not options.ignore_stale: 2215f9996aaSopenharmony_ci build_utils.delete_directory(options.dest) 2225f9996aaSopenharmony_ci build_utils.make_directory(options.dest) 2235f9996aaSopenharmony_ci 2245f9996aaSopenharmony_ci deps = [] 2255f9996aaSopenharmony_ci 2265f9996aaSopenharmony_ci if options.files: 2275f9996aaSopenharmony_ci do_copy(options, deps) 2285f9996aaSopenharmony_ci 2295f9996aaSopenharmony_ci if options.renaming_sources: 2305f9996aaSopenharmony_ci do_renaming(options, deps) 2315f9996aaSopenharmony_ci 2325f9996aaSopenharmony_ci if options.depfile: 2335f9996aaSopenharmony_ci build_utils.write_depfile(options.depfile, 2345f9996aaSopenharmony_ci options.stamp, 2355f9996aaSopenharmony_ci deps, 2365f9996aaSopenharmony_ci add_pydeps=False) 2375f9996aaSopenharmony_ci 2385f9996aaSopenharmony_ci if options.stamp: 2395f9996aaSopenharmony_ci build_utils.touch(options.stamp) 2405f9996aaSopenharmony_ci 2415f9996aaSopenharmony_ci 2425f9996aaSopenharmony_ciif __name__ == '__main__': 2435f9996aaSopenharmony_ci sys.exit(main(sys.argv[1:])) 244