Beispiel #1
0
def get_doc(command, indent='', format='text'):
    doc = inspect.getdoc(command) or ''

    cargs = getargspec(command)
    defaults = {
        i + '_default': j
        for i, j in zip(cargs.args[-len(cargs.defaults or ()):], cargs.defaults
                        or ())
    }

    executable = osp.basename(sys.argv[0])
    if format == 'rst':
        base_directory_default = ' ``$HOME/casa_distro``'
    else:
        base_directory_default = casa_distro_directory()
    help_vars = dict(executable=executable,
                     casa_version=__version__,
                     base_directory_default=base_directory_default,
                     publish_url=publish_url,
                     indent='    ')
    help_vars.update(defaults)
    help_vars['base_directory_default'] = base_directory_default
    r = re.compile('{([^}]+)}')
    keys = set()
    for text in param_help.values():
        keys.update(r.findall(text))
    help_vars.update({k: '' for k in keys if k not in help_vars})
    help_vars.update({k: v.format(**help_vars) for k, v in param_help.items()})

    doc = doc.format(**help_vars)
    if indent:
        doc = '\n'.join(indent + line for line in doc.split('\n'))
    return formatted_help(doc, format=format)
Beispiel #2
0
def clean_images(distro=None, branch=None, system=None,
                 image_version=None, version=None, name=None, type=None,
                 image=None, verbose=False,
                 base_directory=casa_distro_directory(), interactive=True):
    '''
    Delete singularity images which are no longer used in any build workflow,
    or those listed in the "image" parameter.
    There are two ways of selecting the image(s):

    1. filtered by environment, using the ``name`` selector, or a combination
       of ``distro``, ``branch``, and ``system``.

    2. directly specifying a full image name, e.g.::

           casa_distro clean_images image=casa-run-ubuntu-18.04.sif

    Parameters
    ----------
    {distro}
    {branch}
    {system}
    {image_version}
    {version}
    {name}
    {type}
    {image}
    {base_directory}
    interactive
        default={interactive_default}
        ask confirmation before deleting an image
    {verbose}

    '''

    images_to_update = list(iter_images(base_directory=base_directory,
                                        distro=distro, branch=branch,
                                        system=system,
                                        image_version=image_version,
                                        version=version,
                                        name=name, type=type,
                                        image=image))

    print('\n'.join(['%s\t: %s' % i for i in images_to_update]))

    for container_type, image_name \
            in iter_images(base_directory=base_directory,
                           distro=distro, branch=branch,
                           system=system, image_version=image_version,
                           name=name, type=type,
                           image=image):
        if interactive:
            confirm = interactive_input(
                'delete image %s : %s [y/N]: ' % (container_type, image_name))
            if confirm not in ('y', 'yes', 'Y', 'YES'):
                print('skip.')
                continue
        print('deleting image %s' % image_name)
        delete_image(container_type, image_name)
Beispiel #3
0
def delete(type=None, distro=None, branch=None, system=None,
           image_version=None, version=None, name=None,
           base_directory=casa_distro_directory(),
           interactive=True):
    """
    Delete an existing environment.

    The whole environment directory will be removed and forgotten.

    Use with care.

    Image files will be left untouched - use clean_images for this.

    Parameters
    ----------
    {type}
    {distro}
    {branch}
    {system}
    {image_version}
    {version}
    {name}
    {base_directory}
    interactive
        default={interactive_default}
        if true (or 1, or yes), ask confirmation interactively for each
        selected environment.
    """
    interactive = check_boolean('interactive', interactive)
    if not interactive and type is None and distro is None and system is None \
            and image_version is None and name is None:
        raise RuntimeError(
            'Refusing to delete all environments without confirmation. '
            'Either use interactive=True, or provide an explicit pattern for '
            'environment selection parameters')

    for config in iter_environments(base_directory,
                                    type=type,
                                    distro=distro,
                                    branch=branch,
                                    system=system,
                                    image_version=image_version,
                                    version=version,
                                    name=name):
        if interactive:
            confirm = interactive_input(
                'delete environment %s [y/N]: ' % config['name'])
            if confirm not in ('y', 'yes', 'Y', 'YES'):
                print('skip.')
                continue
        print('deleting environment %s' % config['name'])
        directory = config['directory']
        print('rm -rf "%s"' % directory)
        shutil.rmtree(directory)
Beispiel #4
0
def shell(type=None, distro=None, branch=None, system=None, image_version=None,
          name=None,
          version=None,
          base_directory=casa_distro_directory(),
          gui=True,
          opengl="auto",
          root=False,
          cwd=None,
          env=None, image=None,
          container_options=[],
          args_list=['-norc'],
          verbose=None):
    '''
    Start a bash shell in the configured container with the given pository
    configuration.

    Parameters
    ----------
    {type}
    {distro}
    {branch}
    {system}
    {image_version}
    {name}
    {version}
    {base_directory}
    {gui}
    {opengl}
    {root}
    {cwd}
    {env}
    {image}
    {container_options}
    {verbose}
    '''
    run(type=type, distro=distro, branch=branch, system=system,
        image_version=image_version,
        name=name,
        version=version,
        base_directory=base_directory,
        gui=gui,
        opengl=opengl,
        root=root,
        cwd=cwd,
        env=env,
        image=image,
        container_options=container_options,
        args_list=['/bin/bash'] + args_list,
        verbose=verbose)
Beispiel #5
0
def list_images(distro=None, branch=None, system=None, image_version=None,
                version=None, name=None, type=None,
                image='*', base_directory=casa_distro_directory(),
                verbose=None):
    '''List the locally installed container images.
    There are two ways of selecting the image(s):

    1. filtered by environment, using the ``name`` selector, or a combination
       of ``distro``, ``branch``, and ``system``.

    2. directly specifying a full image name, e.g.::

           casa_distro list_image image=casa-run-ubuntu-18.04.sif

    Parameters
    ----------
    {distro}
    {branch}
    {system}
    {image_version}
    {version}
    {name}
    {type}
    {image}
    {base_directory}
    {verbose}

    '''
    images_to_update = list(iter_images(base_directory=base_directory,
                                        distro=distro, branch=branch,
                                        system=system,
                                        image_version=image_version,
                                        version=version,
                                        name=name, type=type,
                                        image=image))

    print('\n'.join(['%s\t: %s' % i for i in images_to_update]))
Beispiel #6
0
def bv_maker(type='dev', distro=None, branch=None, system=None,
             image_version=None, name=None,
             base_directory=casa_distro_directory(),
             env=None, image=None, container_options=[], args_list=[],
             verbose=None):
    '''
    Start a bv_maker in the configured container with the given repository
    configuration.

    Parameters
    ----------
    {type}
    {distro}
    {branch}
    {system}
    {image_version}
    {name}
    {base_directory}
    {env}
    {image}
    {container_options}
    {verbose}

    '''
    args_list = ['bv_maker'] + args_list
    return run(type=type, distro=distro, branch=branch, system=system,
               image_version=image_version,
               name=name,
               base_directory=base_directory,
               gui=False,
               opengl="container",
               env=env,
               image=image,
               container_options=container_options,
               args_list=args_list,
               verbose=verbose)
Beispiel #7
0
def mrun(type=None, distro=None, branch=None, system=None,
         image_version=None, name=None,
         version=None,
         base_directory=casa_distro_directory(),
         gui=True,
         opengl="auto",
         root=False,
         cwd=None,
         env=None,
         image=None,
         container_options=[],
         args_list=[],
         verbose=None):
    '''
    Start any command in one or several container with the given
    repository configuration. By default, command is executed in
    all existing build workflows.

    example::

        # Launch bv_maker on all build workflows using any version of Ubuntu
        casa_distro mrun bv_maker system=ubuntu-*

    Parameters
    ----------
    {type}
    {distro}
    {branch}
    {system}
    {image_version}
    {name}
    {version}
    {base_directory}
    {gui}
    {opengl}
    {root}
    {cwd}
    {env}
    {image}
    {container_options}
    {verbose}

    '''

    verbose = verbose_file(verbose)
    gui = check_boolean('gui', gui)
    root = check_boolean('root', root)
    if container_options:
        container_options = parse_list(container_options)
    if env:
        env_list = parse_list(env)
        try:
            env = dict(e.split('=') for e in env_list)
        except ValueError:
            raise ValueError('env syntax error. Should be in the shape '
                             '"VAR1=value1,VAR2=value2" etc.')
    command = args_list
    res = []

    for config in iter_environments(base_directory,
                                    type=type,
                                    distro=distro,
                                    branch=branch,
                                    system=system,
                                    image_version=image_version,
                                    name=name,
                                    version=version):

        res.append(run_container(config,
                                 command=command,
                                 gui=gui,
                                 opengl=opengl,
                                 root=root,
                                 cwd=cwd,
                                 env=env,
                                 image=image,
                                 container_options=container_options,
                                 base_directory=base_directory,
                                 verbose=verbose))

    if all(r == 0 for r in res):
        return 0
    else:
        sys.stderr.write('Exit codes: {0}\n'.format(res))
        return max(res)
Beispiel #8
0
def pull_image(distro=None, branch=None, system=None, image_version=None,
               version=None, name=None, type=None,
               image='*', base_directory=casa_distro_directory(),
               url=default_download_url,
               force=False, verbose=None):
    '''Update the container images. By default all images that are used by at
    least one environment are updated. There are two ways of selecting the
    image(s) to be downloaded:

    1. filtered by environment, using the ``name`` selector, or a combination
       of ``distro``, ``branch``, and ``image_version``.

           casa_distro pull_image type=dev image_version=5.0

    2. directly specifying an image name (*not* including bulild_number),
       e.g.::

           casa_distro pull_image image=casa-run-5.0.sif

    Note that even though the build number does not appear in the local image
    name, this command will always pull the image with the highest
    build_number, e.g. the image that is named casa-dev-5.0-1.sif on the server
    will be downloaded to a file named casa-dev-5.0.sif.

    Parameters
    ----------
    {distro}
    {branch}
    {system}
    {type}
    {image_version}
    {version}
    {name}
    {base_directory}
    {image}
    url
        default={url_default}
        URL where to download image if it is not found.
    force
        default=False
        force re-download of images even if they are locally present and
        up-to-date.
    {verbose}

    '''
    verbose = verbose_file(verbose)
    images_to_update = list(iter_images(base_directory=base_directory,
                                        distro=distro, branch=branch,
                                        system=system,
                                        image_version=image_version,
                                        version=version,
                                        name=name, type=type,
                                        image=image))

    if not images_to_update and image not in (None, '') and '*' not in image:
        if image.endswith('.sif') or image.endswith('.simg'):
            container_type = 'singularity'
            images_to_update = [(container_type, image)]
        elif image.endswith('.ova') or image.endswith('.vdi'):
            container_type = 'vbox'
            images_to_update = [(container_type, image)]

    if verbose:
        print('images_to_update:\n%s'
              % '\n'.join(['%s\t: %s' % i for i in images_to_update]),
              file=verbose)

    for container_type, image in images_to_update:
        update_container_image(container_type, image,
                               base_directory=base_directory,
                               verbose=verbose, url=url, force=force)
    if not images_to_update:
        print('No build workflow match selection criteria',
              file=sys.stderr)
        return 1
Beispiel #9
0
def run(type=None, distro=None, branch=None, system=None, image_version=None,
        version=None, name=None,
        base_directory=casa_distro_directory(),
        gui=True,
        opengl="auto",
        root=False,
        cwd=None,
        env=None,
        image=None,
        container_options=None,
        args_list=[],
        verbose=None):
    """
    Start any command in a selected run or dev environment

    example::

        casa_distro branch=master ls -als /casa

    Parameters
    ----------
    {type}
    {distro}
    {branch}
    {system}
    {image_version}
    {name}
    {version}
    {base_directory}
    {gui}
    {opengl}
    {root}
    {cwd}
    {env}
    {image}
    {container_options}
    {verbose}

    """
    verbose = verbose_file(verbose)
    gui = check_boolean('gui', gui)
    root = check_boolean('root', root)
    config = select_environment(base_directory,
                                type=type,
                                distro=distro,
                                branch=branch,
                                system=system,
                                image_version=image_version,
                                name=name,
                                version=version)
    if container_options:
        container_options = parse_list(container_options)
    if env:
        env_list = parse_list(env)
        try:
            env = dict(e.split('=') for e in env_list)
        except ValueError:
            raise ValueError('env syntax error. Should be in the shape '
                             '"VAR1=value1,VAR2=value2" etc.')
    command = args_list

    return run_container(config,
                         command=command,
                         gui=gui,
                         opengl=opengl,
                         root=root,
                         cwd=cwd,
                         env=env,
                         image=image,
                         container_options=container_options,
                         base_directory=base_directory,
                         verbose=verbose)
Beispiel #10
0
def list_command(type=None, distro=None, branch=None, system=None,
                 image_version=None, name=None,
                 base_directory=casa_distro_directory(),
                 json='no',
                 verbose=None):
    '''List run or dev environments created by "setup"/"setup_dev" command.

    Parameters
    ----------
    {type}
    {distro}
    {branch}
    {system}
    {image_version}
    {name}
    {base_directory}
    json
        default = {json_default}
        The output is written as a list of configuration dictionaries in
        JSON format.
    {verbose}

    '''
    json_output = check_boolean('json', json)
    json = sys.modules['json']
    verbose = verbose_file(verbose)

    # json parameter is hiding json module.
    # it is not possible to get back to a global
    # variable for json. Therefore, the json module is
    # stored in the local variable
    import json

    json_result = []
    for config in iter_environments(base_directory,
                                    type=type,
                                    distro=distro,
                                    branch=branch,
                                    system=system,
                                    image_version=image_version,
                                    name=name):
        if json_output:
            json_result.append(config)
        else:
            print(config['name'])
            for i in ('type', 'distro', 'branch', 'version', 'system',
                      'image_version', 'container_type', 'image'):
                v = config.get(i)
                if v is not None:
                    print('  %s:' % i, config[i])
            overlay = config.get('overlay')
            if overlay:
                print('  writable file system:', overlay)
                print('  writable file system size:',
                      size_to_string(config['overlay_size']))
            print('  directory:', config['directory'])

            if verbose:
                print('  full environment:')
                for line in json.dumps(config, indent=2,
                                       separators=(',', ': ')).split('\n'):
                    print('   ', line)
    if json_output:
        json.dump(json_result, sys.stdout)
Beispiel #11
0
def help(command=None, format='text', full=False, file=None):
    """
    Print global help or help about a command.

    Parameters
    ----------
    format
        format help text in a given text format. Valid values are "text"
        (default) for raw text, or rst (RST/sphinx format).
    full
        if ``true`` or ``yes`` or ``1``, display each subcommand parameters
        documentation in the general help.
    """
    print('HELP, format:', format)
    full = check_boolean('full', full)
    if file is None:
        file = sys.stdout
    indent = ''
    if format == 'text':
        indent = ' ' * 4

    if format == 'rst':
        base_directory_default = ' ``$HOME/casa_distro``'
    else:
        base_directory_default = casa_distro_directory()

    if command:
        command_help = get_doc(commands[command], indent=indent, format=format)
        print('-' * len(command), file=file)
        print(command, file=file)
        print('-' * len(command), file=file)
        print(command_help, file=file)
    else:
        executable = osp.basename(sys.argv[0])

        help_vars = dict(executable=executable,
                         casa_version=__version__,
                         base_directory_default=base_directory_default,
                         indent='    ')
        r = re.compile('{([^}]+)}')
        keys = set()
        for text in param_help.values():
            keys.update(r.findall(text))
        help_vars.update({k: '' for k in keys if k not in help_vars})
        help_vars.update(
            {k: v.format(**help_vars)
             for k, v in param_help.items()})

        global_help = '''\
Casa_distro is the BrainVISA suite distribution swiss knife.
It allows to setup a virtual environment and launch BrainVISA software.
See http://brainivsa.info/casa-distro and
https://github.com/brainvisa/casa-distro for more information

Version : {casa_version}

usage::

    {executable} <general options> <command> [<command parameters>...]

general optional arguments:
    -v, --verbose   Display as much information as possible.
    --version       Display casa-distro version number and exit.
    -h, --help      Display help message and exit.
                    If used after command name, display only the help of this
                    command.

Common parameters:
==================
Most commands accept more or less the same parameters.

Many subcommands need :ref:`environment` selection specifications: :ref:`see the documentation on how to specify an environment <environment_options>`.

{base_directory}

Commands:
========='''.format(**help_vars)  # noqa: E501

        help_vars['indent'] = indent
        global_help = formatted_help(global_help, format=format)

        commands_summary = [global_help]
        for command in commands:
            command_doc = get_doc(commands[command],
                                  indent=indent * 2,
                                  format=format)
            if not full:
                # Split the docstring in two to remove parameters documentation
                # The docstring is supposed to follow the Numpy style docstring
                # see
                # https://numpydoc.readthedocs.io/en/latest/format.html#docstring-standard
                command_doc = re.split(r'\s*parameters\s*-+\s*',
                                       command_doc,
                                       flags=re.I)[0]
            commands_summary.append('\n')
            if format == 'rst':
                commands_summary.append('.. _' + command.replace('_', '-') +
                                        '-help:')
                commands_summary.append('')
            commands_summary.append(indent + '-' * len(command))
            commands_summary.append(indent + command)
            commands_summary.append(indent + '-' * len(command))
            commands_summary.append(command_doc)
        print('\n'.join(commands_summary), file=file)