Best Python code snippet using localstack_python
tools.py
Source:tools.py  
1# SPDX-License-Identifier: GPL-2.0+2#3# Copyright (c) 2016 Google, Inc4#5import glob6import os7import shlex8import shutil9import sys10import tempfile11import urllib.request12from patman import command13from patman import tout14# Output directly (generally this is temporary)15outdir = None16# True to keep the output directory around after exiting17preserve_outdir = False18# Path to the Chrome OS chroot, if we know it19chroot_path = None20# Search paths to use for filename(), used to find files21search_paths = []22tool_search_paths = []23# Tools and the packages that contain them, on debian24packages = {25    'lz4': 'liblz4-tool',26    }27# List of paths to use when looking for an input file28indir = []29def prepare_output_dir(dirname, preserve=False):30    """Select an output directory, ensuring it exists.31    This either creates a temporary directory or checks that the one supplied32    by the user is valid. For a temporary directory, it makes a note to33    remove it later if required.34    Args:35        dirname: a string, name of the output directory to use to store36                intermediate and output files. If is None - create a temporary37                directory.38        preserve: a Boolean. If outdir above is None and preserve is False, the39                created temporary directory will be destroyed on exit.40    Raises:41        OSError: If it cannot create the output directory.42    """43    global outdir, preserve_outdir44    preserve_outdir = dirname or preserve45    if dirname:46        outdir = dirname47        if not os.path.isdir(outdir):48            try:49                os.makedirs(outdir)50            except OSError as err:51                raise ValueError(52                    f"Cannot make output directory 'outdir': 'err.strerror'")53        tout.debug("Using output directory '%s'" % outdir)54    else:55        outdir = tempfile.mkdtemp(prefix='binman.')56        tout.debug("Using temporary directory '%s'" % outdir)57def _remove_output_dir():58    global outdir59    shutil.rmtree(outdir)60    tout.debug("Deleted temporary directory '%s'" % outdir)61    outdir = None62def finalise_output_dir():63    global outdir, preserve_outdir64    """Tidy up: delete output directory if temporary and not preserved."""65    if outdir and not preserve_outdir:66        _remove_output_dir()67        outdir = None68def get_output_filename(fname):69    """Return a filename within the output directory.70    Args:71        fname: Filename to use for new file72    Returns:73        The full path of the filename, within the output directory74    """75    return os.path.join(outdir, fname)76def get_output_dir():77    """Return the current output directory78    Returns:79        str: The output directory80    """81    return outdir82def _finalise_for_test():83    """Remove the output directory (for use by tests)"""84    global outdir85    if outdir:86        _remove_output_dir()87        outdir = None88def set_input_dirs(dirname):89    """Add a list of input directories, where input files are kept.90    Args:91        dirname: a list of paths to input directories to use for obtaining92                files needed by binman to place in the image.93    """94    global indir95    indir = dirname96    tout.debug("Using input directories %s" % indir)97def get_input_filename(fname, allow_missing=False):98    """Return a filename for use as input.99    Args:100        fname: Filename to use for new file101        allow_missing: True if the filename can be missing102    Returns:103        fname, if indir is None;104        full path of the filename, within the input directory;105        None, if file is missing and allow_missing is True106    Raises:107        ValueError if file is missing and allow_missing is False108    """109    if not indir or fname[:1] == '/':110        return fname111    for dirname in indir:112        pathname = os.path.join(dirname, fname)113        if os.path.exists(pathname):114            return pathname115    if allow_missing:116        return None117    raise ValueError("Filename '%s' not found in input path (%s) (cwd='%s')" %118                     (fname, ','.join(indir), os.getcwd()))119def get_input_filename_glob(pattern):120    """Return a list of filenames for use as input.121    Args:122        pattern: Filename pattern to search for123    Returns:124        A list of matching files in all input directories125    """126    if not indir:127        return glob.glob(pattern)128    files = []129    for dirname in indir:130        pathname = os.path.join(dirname, pattern)131        files += glob.glob(pathname)132    return sorted(files)133def align(pos, align):134    if align:135        mask = align - 1136        pos = (pos + mask) & ~mask137    return pos138def not_power_of_two(num):139    return num and (num & (num - 1))140def set_tool_paths(toolpaths):141    """Set the path to search for tools142    Args:143        toolpaths: List of paths to search for tools executed by run()144    """145    global tool_search_paths146    tool_search_paths = toolpaths147def path_has_file(path_spec, fname):148    """Check if a given filename is in the PATH149    Args:150        path_spec: Value of PATH variable to check151        fname: Filename to check152    Returns:153        True if found, False if not154    """155    for dir in path_spec.split(':'):156        if os.path.exists(os.path.join(dir, fname)):157            return True158    return False159def get_host_compile_tool(env, name):160    """Get the host-specific version for a compile tool161    This checks the environment variables that specify which version of162    the tool should be used (e.g. ${HOSTCC}).163    The following table lists the host-specific versions of the tools164    this function resolves to:165        Compile Tool  | Host version166        --------------+----------------167        as            |  ${HOSTAS}168        ld            |  ${HOSTLD}169        cc            |  ${HOSTCC}170        cpp           |  ${HOSTCPP}171        c++           |  ${HOSTCXX}172        ar            |  ${HOSTAR}173        nm            |  ${HOSTNM}174        ldr           |  ${HOSTLDR}175        strip         |  ${HOSTSTRIP}176        objcopy       |  ${HOSTOBJCOPY}177        objdump       |  ${HOSTOBJDUMP}178        dtc           |  ${HOSTDTC}179    Args:180        name: Command name to run181    Returns:182        host_name: Exact command name to run instead183        extra_args: List of extra arguments to pass184    """185    host_name = None186    extra_args = []187    if name in ('as', 'ld', 'cc', 'cpp', 'ar', 'nm', 'ldr', 'strip',188                'objcopy', 'objdump', 'dtc'):189        host_name, *host_args = env.get('HOST' + name.upper(), '').split(' ')190    elif name == 'c++':191        host_name, *host_args = env.get('HOSTCXX', '').split(' ')192    if host_name:193        return host_name, extra_args194    return name, []195def get_target_compile_tool(name, cross_compile=None):196    """Get the target-specific version for a compile tool197    This first checks the environment variables that specify which198    version of the tool should be used (e.g. ${CC}). If those aren't199    specified, it checks the CROSS_COMPILE variable as a prefix for the200    tool with some substitutions (e.g. "${CROSS_COMPILE}gcc" for cc).201    The following table lists the target-specific versions of the tools202    this function resolves to:203        Compile Tool  | First choice   | Second choice204        --------------+----------------+----------------------------205        as            |  ${AS}         | ${CROSS_COMPILE}as206        ld            |  ${LD}         | ${CROSS_COMPILE}ld.bfd207                      |                |   or ${CROSS_COMPILE}ld208        cc            |  ${CC}         | ${CROSS_COMPILE}gcc209        cpp           |  ${CPP}        | ${CROSS_COMPILE}gcc -E210        c++           |  ${CXX}        | ${CROSS_COMPILE}g++211        ar            |  ${AR}         | ${CROSS_COMPILE}ar212        nm            |  ${NM}         | ${CROSS_COMPILE}nm213        ldr           |  ${LDR}        | ${CROSS_COMPILE}ldr214        strip         |  ${STRIP}      | ${CROSS_COMPILE}strip215        objcopy       |  ${OBJCOPY}    | ${CROSS_COMPILE}objcopy216        objdump       |  ${OBJDUMP}    | ${CROSS_COMPILE}objdump217        dtc           |  ${DTC}        | (no CROSS_COMPILE version)218    Args:219        name: Command name to run220    Returns:221        target_name: Exact command name to run instead222        extra_args: List of extra arguments to pass223    """224    env = dict(os.environ)225    target_name = None226    extra_args = []227    if name in ('as', 'ld', 'cc', 'cpp', 'ar', 'nm', 'ldr', 'strip',228                'objcopy', 'objdump', 'dtc'):229        target_name, *extra_args = env.get(name.upper(), '').split(' ')230    elif name == 'c++':231        target_name, *extra_args = env.get('CXX', '').split(' ')232    if target_name:233        return target_name, extra_args234    if cross_compile is None:235        cross_compile = env.get('CROSS_COMPILE', '')236    if name in ('as', 'ar', 'nm', 'ldr', 'strip', 'objcopy', 'objdump'):237        target_name = cross_compile + name238    elif name == 'ld':239        try:240            if run(cross_compile + 'ld.bfd', '-v'):241                target_name = cross_compile + 'ld.bfd'242        except:243            target_name = cross_compile + 'ld'244    elif name == 'cc':245        target_name = cross_compile + 'gcc'246    elif name == 'cpp':247        target_name = cross_compile + 'gcc'248        extra_args = ['-E']249    elif name == 'c++':250        target_name = cross_compile + 'g++'251    else:252        target_name = name253    return target_name, extra_args254def get_env_with_path():255    """Get an updated environment with the PATH variable set correctly256    If there are any search paths set, these need to come first in the PATH so257    that these override any other version of the tools.258    Returns:259        dict: New environment with PATH updated, or None if there are not search260            paths261    """262    if tool_search_paths:263        env = dict(os.environ)264        env['PATH'] = ':'.join(tool_search_paths) + ':' + env['PATH']265        return env266def run_result(name, *args, **kwargs):267    """Run a tool with some arguments268    This runs a 'tool', which is a program used by binman to process files and269    perhaps produce some output. Tools can be located on the PATH or in a270    search path.271    Args:272        name: Command name to run273        args: Arguments to the tool274        for_host: True to resolve the command to the version for the host275        for_target: False to run the command as-is, without resolving it276                   to the version for the compile target277        raise_on_error: Raise an error if the command fails (True by default)278    Returns:279        CommandResult object280    """281    try:282        binary = kwargs.get('binary')283        for_host = kwargs.get('for_host', False)284        for_target = kwargs.get('for_target', not for_host)285        raise_on_error = kwargs.get('raise_on_error', True)286        env = get_env_with_path()287        if for_target:288            name, extra_args = get_target_compile_tool(name)289            args = tuple(extra_args) + args290        elif for_host:291            name, extra_args = get_host_compile_tool(env, name)292            args = tuple(extra_args) + args293        name = os.path.expanduser(name)  # Expand paths containing ~294        all_args = (name,) + args295        result = command.run_pipe([all_args], capture=True, capture_stderr=True,296                                 env=env, raise_on_error=False, binary=binary)297        if result.return_code:298            if raise_on_error:299                raise ValueError("Error %d running '%s': %s" %300                                 (result.return_code,' '.join(all_args),301                                  result.stderr or result.stdout))302        return result303    except ValueError:304        if env and not path_has_file(env['PATH'], name):305            msg = "Please install tool '%s'" % name306            package = packages.get(name)307            if package:308                 msg += " (e.g. from package '%s')" % package309            raise ValueError(msg)310        raise311def tool_find(name):312    """Search the current path for a tool313    This uses both PATH and any value from set_tool_paths() to search for a tool314    Args:315        name (str): Name of tool to locate316    Returns:317        str: Full path to tool if found, else None318    """319    name = os.path.expanduser(name)  # Expand paths containing ~320    paths = []321    pathvar = os.environ.get('PATH')322    if pathvar:323        paths = pathvar.split(':')324    if tool_search_paths:325        paths += tool_search_paths326    for path in paths:327        fname = os.path.join(path, name)328        if os.path.isfile(fname) and os.access(fname, os.X_OK):329            return fname330def run(name, *args, **kwargs):331    """Run a tool with some arguments332    This runs a 'tool', which is a program used by binman to process files and333    perhaps produce some output. Tools can be located on the PATH or in a334    search path.335    Args:336        name: Command name to run337        args: Arguments to the tool338        for_host: True to resolve the command to the version for the host339        for_target: False to run the command as-is, without resolving it340                   to the version for the compile target341    Returns:342        CommandResult object343    """344    result = run_result(name, *args, **kwargs)345    if result is not None:346        return result.stdout347def filename(fname):348    """Resolve a file path to an absolute path.349    If fname starts with ##/ and chroot is available, ##/ gets replaced with350    the chroot path. If chroot is not available, this file name can not be351    resolved, `None' is returned.352    If fname is not prepended with the above prefix, and is not an existing353    file, the actual file name is retrieved from the passed in string and the354    search_paths directories (if any) are searched to for the file. If found -355    the path to the found file is returned, `None' is returned otherwise.356    Args:357      fname: a string,  the path to resolve.358    Returns:359      Absolute path to the file or None if not found.360    """361    if fname.startswith('##/'):362      if chroot_path:363        fname = os.path.join(chroot_path, fname[3:])364      else:365        return None366    # Search for a pathname that exists, and return it if found367    if fname and not os.path.exists(fname):368        for path in search_paths:369            pathname = os.path.join(path, os.path.basename(fname))370            if os.path.exists(pathname):371                return pathname372    # If not found, just return the standard, unchanged path373    return fname374def read_file(fname, binary=True):375    """Read and return the contents of a file.376    Args:377      fname: path to filename to read, where ## signifiies the chroot.378    Returns:379      data read from file, as a string.380    """381    with open(filename(fname), binary and 'rb' or 'r') as fd:382        data = fd.read()383    #self._out.Info("Read file '%s' size %d (%#0x)" %384                   #(fname, len(data), len(data)))385    return data386def write_file(fname, data, binary=True):387    """Write data into a file.388    Args:389        fname: path to filename to write390        data: data to write to file, as a string391    """392    #self._out.Info("Write file '%s' size %d (%#0x)" %393                   #(fname, len(data), len(data)))394    with open(filename(fname), binary and 'wb' or 'w') as fd:395        fd.write(data)396def get_bytes(byte, size):397    """Get a string of bytes of a given size398    Args:399        byte: Numeric byte value to use400        size: Size of bytes/string to return401    Returns:402        A bytes type with 'byte' repeated 'size' times403    """404    return bytes([byte]) * size405def to_bytes(string):406    """Convert a str type into a bytes type407    Args:408        string: string to convert409    Returns:410        A bytes type411    """412    return string.encode('utf-8')413def to_string(bval):414    """Convert a bytes type into a str type415    Args:416        bval: bytes value to convert417    Returns:418        Python 3: A bytes type419        Python 2: A string type420    """421    return bval.decode('utf-8')422def to_hex(val):423    """Convert an integer value (or None) to a string424    Returns:425        hex value, or 'None' if the value is None426    """427    return 'None' if val is None else '%#x' % val428def to_hex_size(val):429    """Return the size of an object in hex430    Returns:431        hex value of size, or 'None' if the value is None432    """433    return 'None' if val is None else '%#x' % len(val)434def print_full_help(fname):435    """Print the full help message for a tool using an appropriate pager.436    Args:437        fname: Path to a file containing the full help message438    """439    pager = shlex.split(os.getenv('PAGER', ''))440    if not pager:441        lesspath = shutil.which('less')442        pager = [lesspath] if lesspath else None443    if not pager:444        pager = ['more']445    command.run(*pager, fname)446def download(url, tmpdir_pattern='.patman'):447    """Download a file to a temporary directory448    Args:449        url (str): URL to download450        tmpdir_pattern (str): pattern to use for the temporary directory451    Returns:452        Tuple:453            Full path to the downloaded archive file in that directory,454                or None if there was an error while downloading455            Temporary directory name456    """457    print('- downloading: %s' % url)458    leaf = url.split('/')[-1]459    tmpdir = tempfile.mkdtemp(tmpdir_pattern)460    response = urllib.request.urlopen(url)461    fname = os.path.join(tmpdir, leaf)462    fd = open(fname, 'wb')463    meta = response.info()464    size = int(meta.get('Content-Length'))465    done = 0466    block_size = 1 << 16467    status = ''468    # Read the file in chunks and show progress as we go469    while True:470        buffer = response.read(block_size)471        if not buffer:472            print(chr(8) * (len(status) + 1), '\r', end=' ')473            break474        done += len(buffer)475        fd.write(buffer)476        status = r'%10d MiB  [%3d%%]' % (done // 1024 // 1024,477                                            done * 100 // size)478        status = status + chr(8) * (len(status) + 1)479        print(status, end=' ')480        sys.stdout.flush()481    print('\r', end='')482    sys.stdout.flush()483    fd.close()484    if done != size:485        print('Error, failed to download')486        os.remove(fname)487        fname = None...Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!
