Beispiel #1
0
 def _get_path_to_storage(self) -> str:
     cmd = F'{self.builder} storage-path'
     basep = utils.chomp(host.capture(cmd))
     # Now build up the entire image path. The convention appears to be:
     # basep/img/tag
     specn = self.config['tag']
     return os.path.join(basep, 'img', specn)
Beispiel #2
0
 def _emit_build_spec(self) -> None:
     dockerf = self.config['spec']
     # Add spec file to the metadata assets.
     metadata.add_asset(metadata.FileAsset(dockerf))
     # Emit the contents of the spec file.
     logger.log('# Begin Spec Output')
     logger.log(utils.chomp(str().join(utils.cat(dockerf))))
     logger.log('# End Spec Output')
Beispiel #3
0
def run(  # pylint: disable=too-many-arguments
        cmd: str,
        verbatim: bool = False,
        echo: bool = False,
        capture_output: bool = False,
        verbose: bool = True,
        check_exit_code: bool = True) -> List[str]:
    '''
    Executes the provided command.

    Returns newline-delimited list of output if capture_output if True.

    Throws ChildProcessError on error if check_exit_code is True.
    '''
    def getrealcmd(cmd: str, verbatim: bool) -> str:
        # The user wants us to run the string exactly as provided.
        if verbatim:
            return cmd
        return F'{constants.BASH_MAGIC} {shlex.quote(cmd)}'

    realcmd = getrealcmd(cmd, verbatim)

    if echo:
        logger.log(F'# $ {realcmd}')

    # Output list of strings used to (optionally) capture command output.
    olst: List[str] = list()
    with subprocess.Popen(
            realcmd,
            shell=True,  # nosec
            bufsize=1,
            # Enables text mode, making write() et al. happy.
            universal_newlines=True,
            stdout=subprocess.PIPE,
            stderr=subprocess.STDOUT) as spo:
        # Show progress and store output to a string (if requested).
        while True:
            stdout = spo.stdout.readline()

            if not stdout:
                break
            if capture_output:
                olst.append(stdout)
            if verbose:
                logger.log(utils.chomp(stdout))

        wrc = spo.wait()
        if wrc != os.EX_OK and check_exit_code:
            cpe = ChildProcessError()
            cpe.errno = wrc
            estr = F"Command '{realcmd}' returned non-zero exit status."
            cpe.strerror = estr
            raise cpe

    return olst
Beispiel #4
0
def capture(cmd: str, check_exit_code: bool = True) -> str:
    '''
    Executes the provided command and returns a string with the command's
    output.

    See run() for exceptions.
    '''
    res = run(cmd,
              capture_output=True,
              verbose=False,
              check_exit_code=check_exit_code)
    return utils.chomp(str().join(res))
Beispiel #5
0
def os_pretty_name() -> str:
    '''
    Returns the host's pretty name as reported by /etc/os-release.
    '''
    name = 'Unknown'
    try:
        with open('/etc/os-release') as osrel:
            for line in osrel:
                if not line.startswith('PRETTY_NAME='):
                    continue
                name = utils.chomp(line.split('=')[1]).strip('"')
                break
    except (OSError, IOError):
        pass

    return name
Beispiel #6
0
def readgs(
        gspath: str,
        config: Optional[CLIConfiguration] = None
) -> Iterable[str]:
    '''
    A convenience routine for reading generate specification files.

    TODO(skg) Add description of formatting rules, semantics, etc. Don't forget
    about yield!

    We accept the following forms:
    # -a/--aarg [ARG_PARAMS] -b/--bargs [ARG PARAMS]
    # -c/--carg [ARG PARAMS] [positional arguments]
    '''
    logger.emlog(F'# Reading Generate Specification File: {gspath}')
    # Emit contents of gs file.
    logger.log('# Begin Generate Specification')
    logger.log(utils.chomp(str().join(utils.cat(gspath))))
    logger.log('# End Generate Specification\n')

    with open(gspath) as file:
        argv = list()
        lines = [x.strip() for x in utils.read_logical_lines(file)]
        for line in lines:
            # Interpret as special comment used to specify run-time arguments.
            if line.startswith('# -'):
                # Add to argument list.
                if config is not None:
                    argv.extend(shlex.split(line.lstrip('# ')))
                continue
            # Skip comments and empty lines.
            if line.startswith('#') or utils.emptystr(line):
                continue
            # Parse arguments if provided an argument parser.
            gsargs = None
            if config is not None:
                if not isinstance(config, CLIConfiguration):
                    estr = F'{__name__} expects an instance of CLIConfiguration'
                    raise ValueError(estr)
                gsargs = parsedargs(config.argparser, argv)
                config.update(gsargs)
            # Not a comment; yield generate specification string.
            yield line
            # Clear out argument list for next round.
            argv = list()
Beispiel #7
0
def capture(
        cmd: str,
        check_exit_code: bool = True
) -> str:
    '''
    Executes the provided command and returns a string with the command's
    output.

    See run() for exceptions.
    '''
    runo = cntrimg.activator().run(
        [cmd],
        echo=False,
        verbose=False,
        capture=True,
        check_exit_code=check_exit_code
    )
    return utils.chomp(str().join(runo))
Beispiel #8
0
    def _check_env(self) -> None:
        '''
        Build environment verification function.

        Raises OSError if the environment is unsatisfactory.
        '''
        logger.emlog('# Checking your build environment...')

        inyp = 'Is it in your PATH?\n'
        notf = "'{}' not found. " + inyp
        errs = str()

        if not host.which(self.buildc):
            errs += notf.format(self.buildc)

        if not host.which(self.tarcmd):
            errs += notf.format(self.tarcmd)

        if errs:
            raise OSError(utils.chomp(errs))
Beispiel #9
0
 def _get_path_to_storage(self) -> str:
     cmd = '{} -b {} -t {} --print-storage {}'.format(
         self.buildc,
         self.builder,
         self.config['tag'],
         self.config['spec']
     )
     cmdo = utils.chomp(host.capture(cmd))
     # Now do some filtering because the output emits more than just the
     # storage path.
     lst = list(filter(lambda x: 'building with' not in x, cmdo.split('\n')))
     if len(lst) < 1:
         msg = 'Could not determine storage ' \
               'path from the following output:\n{}'
         raise RuntimeError(msg.format(cmdo))
     # Hope for the best because of the rudimentary filtering used (i.e.,
     # hope lst[0] is a valid path). If this ever becomes problematic,
     # implement something nicer. Also, not a huge deal because the returned
     # value will be used in later file operations (let them fail).
     basep = lst[0]
     # Now build up the entire image path. The convention appears to be:
     # basep/img/tag
     specn = '{}'.format(self.config['tag'])
     return os.path.join(basep, 'img', specn)