コード例 #1
0
def longest_path(parameters, exclusions):
    """
        Traces all subdirectories of provided commandline paths
        using MaxWidth object

    Args:
        :parameters (list): list of all sys.argv parameters supplied with --sum
        :exclusions (ExcludedTypes object): types to exclude

    Returns:
        width (integer), number of characters in longest path
    """
    mp = MaxWidth()  # max path object
    abspath = absolute_paths(parameters)
    container = []
    max_width = 0

    for i in parameters:
        try:
            paths = sp_linecount(i, abspath, exclusions.types)
            width = mp.calc_maxpath(paths)
            max_width = width if (width > max_width) else max_width
            container.extend(paths)
        except TypeError:
            stdout_message(message='Provided path appears to be invalid',
                           prefix='WARN')
            sys.exit(exit_codes['EX_OSFILE']['Code'])
    return max_width, container
コード例 #2
0
def display_exclusions(expath, exdirpath, offset_spaces=default_width):
    """
    Show list of all file type extensions which are excluded
    from line total calculations
    """
    tab = '\t'.expandtabs(15)
    offset = '\t'.expandtabs(offset_spaces)

    # numbering
    div = cm.bpl + ')' + rst
    adj = 10

    try:

        ex = ProcessExclusions(expath)
        exclusions = ex.exclusions

        stdout_message(message='File types excluded from line counts:', indent=offset_spaces + adj)

        for index, ext in enumerate(exclusions):
            print('{}{}{:>3}{}'.format(offset, tab, index + 1, div + '  ' + ext))

        sys.stdout.write('\n')
        return True

    except OSError as e:
        fx = inspect.stack()[0][3]
        stdout_message(message=f'{fx}: Error: {e}. ', prefix='WARN')
        return False
コード例 #3
0
def multiprocessing_main(valid_paths, max_width, _threshold, wspace,
                         exclusions, debug):
    """
        Execute Operations using concurrency (multi-process) model

    Args:
        :valid_paths (list): list of filesystem paths (str) filtered for binary,
            other uncountable objects
        :max_width (int): width of output pattern, sans line count total column
        :_threshold (int): high line count threshold value (highlighted objects)
        :wspace (bool): when True, omit whitespace lines from count (DEFAULT:  False)
        :exclusions (ex object): instance of ExcludedTypes
        :debug (boot): debug flag

    """
    def debug_messages(flag, paths):
        if flag:
            stdout_message('Objects contained in container directories:',
                           prefix='DEBUG')
            for i in paths:
                print(i)

    def queue_generator(q, p):
        """Generator which offloads a queue before full"""
        while p.is_alive():
            p.join(timeout=1)
            while not q.empty():
                yield q.get(block=False)

    global q
    q = multiprocessing.Queue()
    processes, results = [], []
    debug_messages(debug, valid_paths)

    # maximum cores is 4 due to i/o contention single drive systems
    cores = 4 if cpu_cores() >= 4 else cpu_cores()
    equal_lists = [sorted(x) for x in split_list(valid_paths, cores)]

    for i in equal_lists:
        t = multiprocessing.Process(target=mp_linecount,
                                    args=(i, exclusions.types, wspace))
        processes.append(t)
        t.start()

        results.extend([x for x in queue_generator(q, t)])

        if debug:
            print('Completed: list {}'.format(get_varname(i)))  # show progress

    print_results(results, _threshold, max_width)

    if debug:
        export_json_object(results, logging=False)
        stdout_message(message='Num of objects: {}'.format(len(results)))
    return 0
コード例 #4
0
ファイル: configure.py プロジェクト: fstab50/xlines
def _configure_add(expath, exdirpath, startpt):
    """
        Add exclusions and update runtime constants

    Returns:
        Success | Failure, TYPE: bool
    """
    tab4 = '\t'.expandtabs(4)
    loop = True
    adj = 4
    vert_adj = 2

    try:

        with open(expath) as f1:
            exclusions = [x.strip() for x in f1.readlines()]

        while loop:
            width = _init_screen(starting_row=startpt + vert_adj)
            pattern_width = section_header('add', width, tabspaces=16)
            offset_chars = int((width / 2) - (pattern_width / 2)) + adj
            offset = '\t'.expandtabs(offset_chars)
            display_exclusions(expath, exdirpath, offset_chars)

            # query user input for new exclusions
            msg = 'Enter file extension types separated by commas [done]: '
            offset_msg = '\t'.expandtabs(
                int((width / 2) - (pattern_width / 2) + adj * 2))
            response = input(f'{offset_msg}{msg}')

            if not response:
                loop = False
                sys.stdout.write('\n')
                return True
            else:
                add_list = response.split(',')

                # add new extensions to existing
                exclusions.extend(
                    [x if x.startswith('.') else '.' + x for x in add_list])

                # write out new exclusions config file
                with open(expath, 'w') as f2:
                    f2.writelines([x + '\n' for x in exclusions])

    except OSError:
        stdout_message(
            message='Unable to modify local config file located at {}'.format(
                expath),
            prefix='WARN')
        return False
コード例 #5
0
ファイル: configure.py プロジェクト: fstab50/xlines
def main_menupage(expath, exdirpath):
    """
    Displays main configuration menu jump page and options
    """
    def menu():
        border = bbl
        icolor = bbl
        bar = border + '''
        ________________________________________________________________________________
        '''
        #bar = '\n' + ('_' * 80) + '\n'
        pattern_width = len(bar)
        width, srow = _init_screen()
        offset = '\t'.expandtabs(int((width / 2) - (pattern_width / 2)))
        _menu = (border + bar + rst + '''\n\n
            ''' + bdwt + PACKAGE + rst + ''' configuration main menu:\n\n
                  ''' + icolor + 'a' + rst +
                 ''')  Add file type to exclusion list\n\n
                  ''' + icolor + 'b' + rst +
                 ''')  Remove file type from exclusion list\n\n
                  ''' + icolor + 'c' + rst +
                 ''')  Set high line count threshold (''' + acct +
                 'highlight' + rst + ''' file objects)\n\n
                  ''' + icolor + 'd' + rst + ''')  quit\n
        ''' + border + bar + rst)
        for line in _menu.split('\n'):
            print('{}{}'.format(offset, line))
        return offset, srow

    loop = True
    tab8 = '\t'.expandtabs(8)

    while loop:
        offset, verticalstart = menu()
        answer = input('\n{}{}Choose operation [quit]: '.format(offset,
                                                                tab8)).lower()
        sys.stdout.write('\n')

        if not answer or answer == 'd':
            return True

        elif answer in ['a', 'b', 'c']:
            condition_map(answer, expath, exdirpath, verticalstart)

        else:
            stdout_message(message='You must provide a letter a, b, c, or d',
                           indent=16,
                           prefix='INFO')
            sys.stdout.write('\n')
コード例 #6
0
def _configure_rewrite(expath, newlist):
    """
        Rewrite existing exclusion list on local filesystem with
        modified contents from _configure operation

    Return:
        Succsss || Failure, TYPE: bool
    """
    try:
        # write new exclusion list to local disk
        with open(expath, 'w') as f1:
            list(filter(lambda x: f1.write(x.strip() + '\n'), newlist))

    except OSError as e:
        fx = inspect.stack()[0][3]
        stdout_message(
            f'{fx}: Problem writing new file type exclusion list: {expath}: {e}',
            prefix='WARN')
        return False
    return True
コード例 #7
0
def precheck(user_exfiles, user_exdirs, debug):
    """
    Runtime Dependency Check
    """
    _os_configdir = os.path.join(modules_location(), 'config')
    _os_ex_fname = os.path.join(_os_configdir,
                                local_config['EXCLUSIONS']['EX_FILENAME'])
    _os_dir_fname = os.path.join(_os_configdir,
                                 local_config['EXCLUSIONS']['EX_DIR_FILENAME'])
    _config_dir = local_config['CONFIG']['CONFIG_DIR']

    if debug:
        stdout_message(
            f'_os_configdir: {_os_configdir}: system py modules location',
            'DBUG')
        stdout_message(
            f'_os_ex_fname: {_os_ex_fname}: system exclusions.list path',
            'DBUG')
        stdout_message(
            f'_os_dir_fname: {_os_dir_fname}: system directories.list file path',
            'DBUG')
        stdout_message(
            f'_configdir: {_config_dir}: user home config file location',
            'DBUG')

    try:
        # check if exists; copy
        if not os.path.exists(_config_dir):
            os.makedirs(_config_dir)

        # cp system config file to user if user config files absent
        if os.path.exists(_os_ex_fname) and os.path.exists(_os_dir_fname):

            if not os.path.exists(user_exfiles):
                copyfile(_os_ex_fname, user_exfiles)

            if not os.path.exists(user_exdirs):
                copyfile(_os_dir_fname, user_exdirs)

    except OSError:
        fx = inspect.stack()[0][3]
        logger.exception(
            '{}: Problem installing user config files. Exit'.format(fx))
        return False
    return True
コード例 #8
0
 def debug_messages(flag, paths):
     if flag:
         stdout_message('Objects contained in container directories:',
                        prefix='DEBUG')
         for i in paths:
             print(i)
コード例 #9
0
def init_cli():
    ex_files = local_config['EXCLUSIONS']['EX_EXT_PATH']
    ex_dirs = local_config['EXCLUSIONS']['EX_DIR_PATH']

    # process commandline args
    parser = argparse.ArgumentParser(add_help=False)

    try:

        args, unknown = options(parser)

    except Exception as e:
        help_menu()
        stdout_message(str(e), 'ERROR')
        sys.exit(exit_codes['E_BADARG']['Code'])

    # validate configuration files
    if precheck(ex_files, ex_dirs, args.debug):
        _ct_threshold = set_hicount_threshold(
        ) or local_config['OUTPUT']['COUNT_HI_THRESHOLD']

    if len(sys.argv) == 1 or args.help:
        help_menu()
        sys.exit(exit_codes['EX_OK']['Code'])

    elif args.version:
        package_version()

    elif args.exclusions:
        display_exclusions(ex_files, ex_dirs)

    elif args.configure:
        main_menupage(ex_files, ex_dirs)

    elif len(sys.argv) == 2 and (sys.argv[1] != '.'):
        help_menu()
        sys.exit(exit_codes['EX_OK']['Code'])

    elif args.sum:

        ex = ExcludedTypes(ex_path=str(Path.home()) +
                           '/.config/xlines/exclusions.list')
        container = create_container(args.sum)
        abspath = absolute_paths(container)

        if args.debug:
            stdout_message(f'xlines command line option parameter detail',
                           prefix='DEBUG')
            print('\targs.sum: {}'.format(args.sum))
            print('\n\tsys.argv contents:\n')
            for i in sys.argv:
                print('\t\to  {}'.format(i))
            print(f'\n\tcontainer is:\t{container}')
            print(f'\n\tobject "unknown" is:\t{unknown}')
            print('\tabspath bool is {}\n'.format(abspath))
            print('\tmultiprocess bool is {}\n'.format(args.multiprocess))

        if args.multiprocess:
            # --- run with concurrency --
            width, paths = longest_path(container, ex)
            paths = remove_excluded(args.exclude, paths)
            multiprocessing_main(paths, width, _ct_threshold, args.whitespace,
                                 ex, args.debug)

        elif not args.multiprocess:

            io_fail = []
            tcount, tobjects = 0, 0
            width, paths = longest_path(container, ex)

            paths = remove_excluded(args.exclude, paths)

            print_header(width)
            count_width = local_config['OUTPUT']['COUNT_COLUMN_WIDTH']

            for path in paths:

                try:

                    inc = linecount(path, args.whitespace)
                    highlight = acct if inc > _ct_threshold else cm.aqu
                    tcount += inc  # total line count
                    tobjects += 1  # increment total number of objects

                    # truncation
                    lpath, fname = os.path.split(path)

                    if (len(path) + BUFFER * 2) > width:
                        cutoff = (len(path) + BUFFER * 2) - width
                    else:
                        cutoff = 0

                    tab = '\t'.expandtabs(width - len(lpath) - len(fname) -
                                          count_width + BUFFER)

                    # with color codes added
                    if cutoff == 0:
                        lpath = text + lpath + rst
                    else:
                        lpath = text + os.path.split(
                            path)[0][:len(lpath) - cutoff -
                                     BUFFER] + rst + arrow
                        tab = '\t'.expandtabs(width - len(lpath) - len(fname) +
                                              count_width + BUFFER + cut_corr)

                    tab4 = '\t'.expandtabs(4)
                    fname = highlight + fname + rst

                    # incremental count formatting
                    ct_format = acct if inc > _ct_threshold else bwt

                    # format tabular line totals with commas
                    output_str = f'{tab4}{lpath}{div}{fname}{tab}{ct_format}{"{:,}".format(inc):>10}{rst}'
                    print(output_str)

                    if args.debug:
                        print(tab4 * 2 + 'lpath is {}'.format(lpath))
                        print(tab4 * 2 + 'fname is {}\n'.format(fname))

                except Exception:
                    io_fail.append(path)
                    continue

            print_footer(tcount, tobjects, width)

            if args.debug:
                tab4 = '\t'.expandtabs(4)
                stdout_message(
                    f'cli screen columns variable, width: {cm.bdwt}{width}{cm.rst}',
                    prefix='DBUG')
                print('\n' + tab4 + 'Skipped file objects:\n' + tab4 +
                      ('-' * (width + count_width)))
                if io_fail:
                    for file in io_fail:
                        print(
                            '\t{}'.format(file)
                        )  # Write this out to a file in /tmp for later viewing
                else:
                    print('\tNone')
                sys.stdout.write('\n')

            sys.exit(exit_codes['EX_OK']['Code'])

    else:
        stdout_message('Dependency check fail %s' % json.dumps(args, indent=4),
                       prefix='AUTH',
                       severity='WARNING')
        sys.exit(exit_codes['E_DEPENDENCY']['Code'])

    failure = """ : Check of runtime parameters failed for unknown reason.
    Please ensure you have both read and write access to local filesystem. """
    logger.warning(failure +
                   'Exit. Code: %s' % sys.exit(exit_codes['E_MISC']['Code']))
    print(failure)
コード例 #10
0
def precheck(user_exfiles, user_exdirs, debug):
    """
    Runtime Dependency Checks: postinstall artifacts, environment
    """
    def set_environment():
        lang = 'undefined'
        if os.getenv('LANG') is None:
            lang = '{}export LANG=en_US.UTF-8{}'.format(yl, rst)
        elif 'UTF-8' not in os.getenv('LANG'):
            lang = '{}export LANG=$LANG.UTF-8{}'.format(yl, rst)
        return lang

    # local user configuration:  excluded file types
    _os_configdir = os.path.join(modules_location(), 'config')
    _ex_fname = local_config['EXCLUSIONS']['EX_FILENAME']
    _os_ex_fname = os.path.join(_os_configdir, _ex_fname)

    # local user configuration:  excluded directories
    _dir_fname = local_config['EXCLUSIONS']['EX_DIR_FILENAME']
    _os_dir_fname = os.path.join(_os_configdir, _dir_fname)
    _config_dir = local_config['CONFIG']['CONFIG_DIR']
    _language = set_environment()
    _environment_setup = 'fail' if 'UTF-8' in _language else 'success'

    if debug:
        tab = '\t'.expandtabs(16)
        stdout_message(
            f'_os_configdir: {_os_configdir}: system py modules location',
            'DBUG')
        stdout_message(
            f'_os_ex_fname: {_os_ex_fname}: system exclusions.list path',
            'DBUG')
        stdout_message(
            f'_os_dir_fname: {_os_dir_fname}: system directories.list file path',
            'DBUG')
        stdout_message(
            f'_configdir: {_config_dir}: user home config file location',
            'DBUG')
        stdout_message(
            f'Environment setup status: {_environment_setup.upper()}')

        if _environment_setup.upper() == 'FAIL':
            _env = _environment_setup.upper()
            msg = f'Environment setting is {_env}. Add the following code in your .bashrc file'
            stdout_message('{}:  {}'.format(msg, _language))

    try:
        # check if exists; copy
        if not os.path.exists(_config_dir):
            os.makedirs(_config_dir)

        # cp system config file to user if user config files absent
        if os.path.exists(_os_ex_fname) and os.path.exists(_os_dir_fname):

            if not os.path.exists(user_exfiles):
                copyfile(_os_ex_fname, user_exfiles)

            if not os.path.exists(user_exdirs):
                copyfile(_os_dir_fname, user_exdirs)

        # debian-style installation paths
        elif os.path.exists(
                os.path.join('usr/local/lib/xlines/config', _ex_fname)):

            if not os.path.exists(user_exfiles):
                copyfile(
                    os.path.join('usr/local/lib/xlines/config', _ex_fname),
                    user_exfiles)

            if not os.path.exists(user_exdirs):
                copyfile(
                    os.path.join('usr/local/lib/xlines/config', _dir_fname),
                    user_exdirs)

    except OSError:
        fx = inspect.stack()[0][3]
        logger.exception(
            '{}: Problem installing user config files. Exit'.format(fx))
        return False
    return True
コード例 #11
0
def _configure_hicount(expath, exdirpath, startpt):
    """
        User update high line count threshold persisted on local filesystem

    Returns:
        Success || Failure, TYPE: bool

    """
    def _exit(loop_break):
        leave = input('Exit? [quit]')
        if not leave or 'q' in leave:
            loop_break = False
        return loop_break

    tab4 = '\t'.expandtabs(4)
    tab13 = '\t'.expandtabs(13)
    loop = True
    adj = 12
    vert_adj = 2
    local_linecount_file = local_config['CONFIG']['HI_THRESHOLD_FILEPATH']

    try:
        width = _init_screen(starting_row=startpt + vert_adj)
        pattern_width = section_header('threshold', width, tabspaces=14)
        offset_chars = int((width / 2) - (pattern_width / 2))
        offset = '\t'.expandtabs(offset_chars)

        while loop:

            if os.path.exists(local_linecount_file):
                with open(local_linecount_file) as f1:
                    threshold = int(f1.read().strip())

            stdout_message(
                    message='Current high line count threshold: {}{}{}'.format(bdwt, threshold, rst),
                    indent=offset_chars + adj
                )
            answer = input(f'{tab4}{offset}{tab13}Enter high line count threshold [{threshold}]: ')

            try:
                if not answer:
                    stdout_message(
                            f'High line count threshold remains {threshold}',
                            prefix='INFO',
                            indent=offset_chars + adj
                        )
                    loop = False
                    return mainmenu_return(offset)

                elif 'q' in answer:
                    loop = False
                    return mainmenu_return(offset)

                elif type(int(answer)) is int:
                    # rewrite threshold file on local filesystem
                    with open(local_linecount_file, 'w') as f1:
                        f1.write(str(answer) + '\n')
                    stdout_message(
                            message='high line count threshold set to {}'.format(answer),
                            prefix='ok',
                            indent=offset_chars + adj
                        )
                    loop = False
                    return mainmenu_return(offset)

                else:
                    stdout_message(
                            message='You must enter an integer number',
                            prefix='INFO',
                            indent=offset_chars + adj
                        )
            except ValueError:
                pass
    except OSError:
        fx = inspect.stack()[0][3]
        logger.exception(f'{fx}: Problem reading local hicount threshold file. Abort')
        return False
    return True
コード例 #12
0
def _configure_remove(expath, exdirpath, startpt):
    """
        Remove file type extension from exclusion list

    Return:
        Succsss || Failure, TYPE: bool
    """
    delay_seconds = 2
    tabspaces = 4
    tab4 = '\t'.expandtabs(tabspaces)
    loop = True
    adj = tabspaces * 2
    vert_adj = 2

    try:

        # open current file type exclusions
        with open(expath) as f1:
            f2 = [x.strip() for x in f1.readlines()]

        while loop:
            width = _init_screen(starting_row=startpt + vert_adj)
            pattern_width = section_header('delete', width, tabspaces=14)
            offset_chars = int((width / 2) - (pattern_width / 2)) + tabspaces
            offset = '\t'.expandtabs(offset_chars)
            display_exclusions(expath, exdirpath, offset_chars)

            answer = input(offset + tab4 + 'Pick the number of a file type to remove [done]: ')

            try:
                if not answer:
                    loop = False
                    sys.stdout.write('\n')
                    return True

                elif int(answer) in range(1, len(f2) + 1):
                    # correct for f2 list index
                    answer = int(answer) - 1
                    # remove entry selected by user
                    deprecated = f2[answer]
                    f2.pop(int(answer))

                    if not _configure_rewrite(expath, f2):
                        return False

                    # Acknowledge removal
                    if str(answer) in f2:
                        stdout_message(
                            message='Failure to remove {} - reason unknown'.format(f2[answer]),
                            indent=offset_chars + adj,
                            prefix='FAIL'
                        )
                        sleep(delay_seconds)

                else:
                    max_index = len(f2)
                    stdout_message(
                        message=f'You must pick a number between 1 and {max_index}',
                        prefix='WARN',
                        indent=offset_chars + adj
                    )
                    sleep(delay_seconds)
            except ValueError:
                continue

    except OSError:
        stdout_message(
            message='Unable to modify local config file located at {}'.format(expath),
            prefix='WARN')
        return False