Ejemplo n.º 1
0
def register_target(name, target):
    """
    register a target type to a given target name

    :param str name: the target name (case sensitive)
    :param target: the target to register
    :type target: :class:`cleanmymac.target.Target`
    """
    global __TARGETS__
    if issubclass(target, Target):
        debug('registering : {0}'.format(name))
        __TARGETS__[name] = target
    else:
        error('target {0} is not of type Target, instead got: {1}'.format(name, target))
Ejemplo n.º 2
0
def get_target(name):
    """
    get a registered target

    :param str name: the target name
    :return: the target
    :rtype: :class:`cleanmymac.target.Target`
    """
    global __TARGETS__
    try:
        return __TARGETS__[name]
    except KeyError:
        error("no target found for: {0}".format(name))
        return None
Ejemplo n.º 3
0
def get_target(name):
    """
    get a registered target

    :param str name: the target name
    :return: the target
    :rtype: :class:`cleanmymac.target.Target`
    """
    global __TARGETS__
    try:
        return __TARGETS__[name]
    except KeyError:
        error("no target found for: {0}".format(name))
        return None
Ejemplo n.º 4
0
def register_target(name, target):
    """
    register a target type to a given target name

    :param str name: the target name (case sensitive)
    :param target: the target to register
    :type target: :class:`cleanmymac.target.Target`
    """
    global __TARGETS__
    if issubclass(target, Target):
        debug('registering : {0}'.format(name))
        __TARGETS__[name] = target
    else:
        error('target {0} is not of type Target, instead got: {1}'.format(
            name, target))
Ejemplo n.º 5
0
def delete_dir_content(folder):
    """
    delete all the files and directories in path

    :param Dir folder: a valid directory path
    """
    assert isinstance(folder, Dir)
    if not os.path.isdir(folder.path):
        error('{0} not a directory'.format(folder.path))
        return

    for root, dirs, files in os.walk(folder.path):
        for f in files:
            os.unlink(os.path.join(root, f))
        for d in dirs:
            shutil.rmtree(os.path.join(root, d))
Ejemplo n.º 6
0
def delete_dir_content(folder):
    """
    delete all the files and directories in path

    :param Dir folder: a valid directory path
    """
    assert isinstance(folder, Dir)
    if not os.path.isdir(folder.path):
        error('{0} not a directory'.format(folder.path))
        return

    for root, dirs, files in os.walk(folder.path):
        for f in files:
            os.unlink(os.path.join(root, f))
        for d in dirs:
            shutil.rmtree(os.path.join(root, d))
Ejemplo n.º 7
0
    def _run(self, commands):
        for cmd in commands:
            self._debug('run command "{0}"'.format(cmd))
            try:
                with Capture() as err:
                    with Capture() as out:
                        if self._verbose:
                            echo_success('running: {0}'.format(cmd))

                        command_done = Event()

                        def redirect():
                            while not command_done.is_set():
                                try:
                                    for line in out:
                                        echo_info(line.strip())
                                except TypeError:
                                    pass

                                try:
                                    for line in err:
                                        warn(line.strip())
                                except TypeError:
                                    pass

                                sleep(0.05)

                        p = run(cmd,
                                stdout=out,
                                stderr=err,
                                env=self._env,
                                async=True)

                        if self._verbose:
                            Thread(target=redirect).start()

                        try:
                            p.wait()
                        finally:
                            # make sure the console redirect thread is properly shutting down
                            command_done.set()

            except OSError:
                error(
                    'command: "{0}" could not be executed (not found?)'.format(
                        cmd))
Ejemplo n.º 8
0
def load_target(yaml_file, config, update=False, verbose=False, strict=True):
    """
    load a target given its description from a **YAML** file.
    The file is validated according to its type before loading.

    :param str yaml_file: a valid path to a **YAML** file
    :param dict config: the global configuration dictionary
    :param bool update: specify whether to perform update before cleanup
    :param bool verbose: toggle verbosity
    :return: the target
    :rtype: :class:`cleanmymac.target.Target`
    """
    with open(yaml_file, 'r+') as DESC:
        try:
            description = load(DESC)
            description = validate_yaml_target(description, strict=strict)
            _type = description['type']
            if _type not in VALID_TARGET_TYPES:
                error(
                    'unknown yaml target type: "{0}", valid options are: {1}'.
                    format(_type, VALID_TARGET_TYPES))
                return None

            target_class = __YAML_TYPES__[_type]
            if not issubclass(target_class, Target):
                error(
                    'expected a subclass of Target for "{0}", instead got: "{1}"'
                    .format(os.path.basename(yaml_file), target_class))
                return None

            if not config:
                config = {}
            config['spec'] = description['spec']
            return target_class(config, update=update, verbose=verbose)
        except Exception as e:
            error('Error loading configuration: "{0}". Reason: {1}'.format(
                yaml_file, e))
            if strict:
                raise e
            return None
Ejemplo n.º 9
0
def load_target(yaml_file, config, update=False, verbose=False, strict=True):
    """
    load a target given its description from a **YAML** file.
    The file is validated according to its type before loading.

    :param str yaml_file: a valid path to a **YAML** file
    :param dict config: the global configuration dictionary
    :param bool update: specify whether to perform update before cleanup
    :param bool verbose: toggle verbosity
    :return: the target
    :rtype: :class:`cleanmymac.target.Target`
    """
    with open(yaml_file, 'r+') as DESC:
        try:
            description = load(DESC)
            description = validate_yaml_target(description, strict=strict)
            _type = description['type']
            if _type not in VALID_TARGET_TYPES:
                error('unknown yaml target type: "{0}", valid options are: {1}'.format(
                        _type, VALID_TARGET_TYPES
                ))
                return None

            target_class = __YAML_TYPES__[_type]
            if not issubclass(target_class, Target):
                error('expected a subclass of Target for "{0}", instead got: "{1}"'.format(
                        os.path.basename(yaml_file), target_class
                ))
                return None

            if not config:
                config = {}
            config['spec'] = description['spec']
            return target_class(config, update=update, verbose=verbose)
        except Exception as e:
            error('Error loading configuration: "{0}". Reason: {1}'.format(yaml_file, e))
            if strict:
                raise e
            return None
Ejemplo n.º 10
0
def validate_yaml_target(description, strict=True):
    """
    performs the validation of the **YAML** definition of a :class:`cleanmymac.target.Target`.
    Currently two kinds of schemas are supported.

    * Shell command based Targets

    .. code-block:: yaml

        type: 'cmd'
        spec: {
          update_commands: [
            'conda update conda',
            'conda update anaconda'
          ],
          clean_commands: [
            'conda clean -p -s -t -y'
          ]
        }


    * Directory based Targets

    .. code-block:: yaml

        type: 'dir'
        spec: {
            update_message: 'Get the latest Java version from http://www.oracle.com/technetwork/java/javase/downloads/index.html',
            entries: [
                {
                    dir: '/Library/Java/JavaVirtualMachines',
                    pattern: 'jdk1\.6\.\d_\d+\.jdk'
                },
                {
                    dir: '/Library/Java/JavaVirtualMachines',
                    pattern: 'jdk1\.7\.\d_\d+\.jdk'
                },
                {
                    dir: '/Library/Java/JavaVirtualMachines',
                    pattern: 'jdk1\.8\.\d_\d+\.jdk'
                },
            ]
        }

    :param dict description: the loaded description
    :param bool strict: perform strict validation (fail on invalid specification if True)
    :return: the validate description
    :rtype: dict
    """
    global __TYPE_SCHEMA__
    schema = _target_schema()
    description = schema(description)
    _type = description['type']
    _spec = description['spec']
    try:
        schema = __TYPE_SCHEMA__[_type](strict=strict)
        description['spec'] = schema(_spec)
    except Exception as e:
        error(e)
        if strict:
            raise e
    return description
Ejemplo n.º 11
0
def cli(update, dry_run, quiet, pretty_print, strict, list_targets,
        stop_on_error, config, targets_path, targets, **kwargs):
    """
    the main **run** method, responsible for creating the parser and executing the main logic in
    **cleanmymac**

    :param bool update: perform update of targets (if applicable)
    :param bool dry_run: do not execute the actions, but log the result
    :param bool quiet: quiet mode (no output), show a progressbar instead
    :param bool pretty_print: enable pretty printing with colors
    :param bool strict: if set enforce strict(er) rules when validating targets
    :param bool list_targets: list the installed targets
    :param bool stop_on_error: abort the execution on first error
    :param str config: the configuration path
    :param str targets_path: extra targets paths
    :param list targets: the targets
    """
    disable_logger('sarge')
    targets = tuple([target.lower() for target in targets])

    set_pretty_print(pretty_print)

    debug_param('update', update)
    debug_param('dry run', dry_run)
    debug_param('quiet mode', quiet)
    debug_param('pretty print', pretty_print)
    debug_param('strict mode', strict)
    debug_param('list available targets', list_targets)
    debug_param('stop on error', stop_on_error)
    debug_param('global config path', config)
    debug_param('extra targets path', targets_path)
    debug_param('targets', targets)
    debug('')

    all_targets = dict(iter_targets())
    if is_debug():
        debug("Detailed information about registered targets")
        debug(get_targets_as_table(simple=False, fancy=False))

    if dry_run:
        verbose = True
    else:
        verbose = not quiet
    debug_param('verbose', verbose)

    if targets:
        target_names = set(targets)
    else:
        target_names = set(all_targets.keys())

    if update:
        echo_warn(
            'updating may result in an increase of the total space taken by the cleanup targets',
            verbose=verbose)

    echo_info('found {0} registered cleanup targets'.format(len(all_targets)),
              verbose=verbose)

    config = get_options(path=config)
    # register extra targets if any
    for pth in _config_targets_path(config):
        register_yaml_targets(pth)
    if targets_path and os.path.isdir(targets_path):
        register_yaml_targets(targets_path)

    if list_targets:
        echo_warn(get_targets_as_table(simple=True, fancy=True))
    else:
        with progressbar(verbose,
                         all_targets.items(),
                         label='Processing cleanup targets:',
                         width=40) as all_targets_bar:
            free_space_before = get_disk_usage('/', unit=UNIT_MB).free

            for name, target_initializer in all_targets_bar:
                echo_info(_HORIZONTAL_RULE, verbose=verbose)
                if name not in target_names:
                    debug('skipping target "{0}"'.format(name))
                    continue
                echo_target('\ncleaning: {0}'.format(name.upper()),
                            verbose=verbose)
                target_cfg = config[name] if name in config else None
                debug("got target configuration: {0}".format(
                    pformat(target_cfg)))

                try:
                    target = target_initializer(target_cfg,
                                                update=update,
                                                verbose=verbose,
                                                strict=strict)

                    if not isinstance(target, Target):
                        error(
                            'expected an instance of Target, instead got: {0}'.
                            format(target))
                        continue

                    if dry_run:
                        echo_warn(target.describe())
                    else:
                        target()
                except Exception, ex:
                    error(
                        'could not cleanup target "{0}". Reason:\n{1}'.format(
                            name, ex))
                    if stop_on_error:
                        break

                if not verbose:
                    sleep(
                        PROGRESSBAR_ADVANCE_DELAY
                    )  # nicer progress bar display for fast executing targets

            free_space_after = get_disk_usage('/', unit=UNIT_MB).free
            if not dry_run:
                echo_info('\ncleanup complete', verbose=verbose)
                echo_success('\nfreed {0:.3f} MB of disk space'.format(
                    free_space_after - free_space_before),
                             verbose=True,
                             nl=verbose)
Ejemplo n.º 12
0
def cli(update, dry_run, quiet, pretty_print, strict, list_targets, stop_on_error, config, targets_path, targets, **kwargs):
    """
    the main **run** method, responsible for creating the parser and executing the main logic in
    **cleanmymac**

    :param bool update: perform update of targets (if applicable)
    :param bool dry_run: do not execute the actions, but log the result
    :param bool quiet: quiet mode (no output), show a progressbar instead
    :param bool pretty_print: enable pretty printing with colors
    :param bool strict: if set enforce strict(er) rules when validating targets
    :param bool list_targets: list the installed targets
    :param bool stop_on_error: abort the execution on first error
    :param str config: the configuration path
    :param str targets_path: extra targets paths
    :param list targets: the targets
    """
    disable_logger('sarge')
    targets = tuple([target.lower() for target in targets])

    set_pretty_print(pretty_print)

    debug_param('update', update)
    debug_param('dry run', dry_run)
    debug_param('quiet mode', quiet)
    debug_param('pretty print', pretty_print)
    debug_param('strict mode', strict)
    debug_param('list available targets', list_targets)
    debug_param('stop on error', stop_on_error)
    debug_param('global config path', config)
    debug_param('extra targets path', targets_path)
    debug_param('targets', targets)
    debug('')

    all_targets = dict(iter_targets())
    if is_debug():
        debug("Detailed information about registered targets")
        debug(get_targets_as_table(simple=False, fancy=False))

    if dry_run:
        verbose = True
    else:
        verbose = not quiet
    debug_param('verbose', verbose)

    if targets:
        target_names = set(targets)
    else:
        target_names = set(all_targets.keys())

    if update:
        echo_warn('updating may result in an increase of the total space taken by the cleanup targets', verbose=verbose)

    echo_info('found {0} registered cleanup targets'.format(len(all_targets)), verbose=verbose)

    config = get_options(path=config)
    # register extra targets if any
    for pth in _config_targets_path(config):
        register_yaml_targets(pth)
    if targets_path and os.path.isdir(targets_path):
        register_yaml_targets(targets_path)

    if list_targets:
        echo_warn(get_targets_as_table(simple=True, fancy=True))
    else:
        with progressbar(verbose, all_targets.items(), label='Processing cleanup targets:',
                         width=40) as all_targets_bar:
            free_space_before = get_disk_usage('/', unit=UNIT_MB).free

            for name, target_initializer in all_targets_bar:
                echo_info(_HORIZONTAL_RULE, verbose=verbose)
                if name not in target_names:
                    debug('skipping target "{0}"'.format(name))
                    continue
                echo_target('\ncleaning: {0}'.format(name.upper()), verbose=verbose)
                target_cfg = config[name] if name in config else None
                debug("got target configuration: {0}".format(pformat(target_cfg)))

                try:
                    target = target_initializer(target_cfg, update=update, verbose=verbose, strict=strict)

                    if not isinstance(target, Target):
                        error('expected an instance of Target, instead got: {0}'.format(target))
                        continue

                    if dry_run:
                        echo_warn(target.describe())
                    else:
                        target()
                except Exception, ex:
                    error('could not cleanup target "{0}". Reason:\n{1}'.format(name, ex))
                    if stop_on_error:
                        break

                if not verbose:
                    sleep(PROGRESSBAR_ADVANCE_DELAY)  # nicer progress bar display for fast executing targets

            free_space_after = get_disk_usage('/', unit=UNIT_MB).free
            if not dry_run:
                echo_info('\ncleanup complete', verbose=verbose)
                echo_success('\nfreed {0:.3f} MB of disk space'.format(free_space_after - free_space_before),
                             verbose=True, nl=verbose)
Ejemplo n.º 13
0
def validate_yaml_target(description, strict=True):
    """
    performs the validation of the **YAML** definition of a :class:`cleanmymac.target.Target`.
    Currently two kinds of schemas are supported.

    * Shell command based Targets

    .. code-block:: yaml

        type: 'cmd'
        spec: {
          update_commands: [
            'conda update conda',
            'conda update anaconda'
          ],
          clean_commands: [
            'conda clean -p -s -t -y'
          ]
        }


    * Directory based Targets

    .. code-block:: yaml

        type: 'dir'
        spec: {
            update_message: 'Get the latest Java version from http://www.oracle.com/technetwork/java/javase/downloads/index.html',
            entries: [
                {
                    dir: '/Library/Java/JavaVirtualMachines',
                    pattern: 'jdk1\.6\.\d_\d+\.jdk'
                },
                {
                    dir: '/Library/Java/JavaVirtualMachines',
                    pattern: 'jdk1\.7\.\d_\d+\.jdk'
                },
                {
                    dir: '/Library/Java/JavaVirtualMachines',
                    pattern: 'jdk1\.8\.\d_\d+\.jdk'
                },
            ]
        }

    :param dict description: the loaded description
    :param bool strict: perform strict validation (fail on invalid specification if True)
    :return: the validate description
    :rtype: dict
    """
    global __TYPE_SCHEMA__
    schema = _target_schema()
    description = schema(description)
    _type = description['type']
    _spec = description['spec']
    try:
        schema = __TYPE_SCHEMA__[_type](strict=strict)
        description['spec'] = schema(_spec)
    except Exception as e:
        error(e)
        if strict:
            raise e
    return description