CCCPaste

chown-dir-user.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from __future__ import (
    absolute_import, division, print_function, unicode_literals
)
from nine import (
    IS_PYTHON2, basestring, chr, class_types, filter, integer_types,
    implements_iterator, implements_to_string, implements_repr,
    input, iterkeys, iteritems, itervalues, long, map,
    native_str, nine, nimport, range, range_list, reraise, str, zip
)

argparse = nimport('argparse')
grp = nimport('grp')
os = nimport('os')
pwd = nimport('pwd')
sys = nimport('sys')
time = nimport('time')


def run():
    """Runs this program.

    The program ensures that all files under a directory belong to
    a certain user and group.
    """
    start_time = time.time()
    options = parse_cmd_line()
    chown_dir_user(
        user=options['user'],
        directory=options['directory'],
        verbose=options['verbose'])
    if options['verbose']:
        print('Done, in {} seconds!'.format(time.time() - start_time))


def parse_cmd_line():
    """Parses the command-line arguments.

    Arguments:
        None

    Returns:
        A dictionary with each of the supplied command-line arguments.
    """
    parser = argparse.ArgumentParser(
        description=' '.join([
            'Sets the user and group of all files under/within a given',
            'directory to a particular user and group']))
    parser.add_argument(
        'user',
        help=' '.join([
            'specify the name of the user/group for files within this',
            'directory']))
    parser.add_argument(
        'directory',
        help=' '.join([
            'specify the directory to look for files',
            'whose owner/group should to be modified']))
    parser.add_argument(
        '--verbose', '-v',
        action='store_true',
        default=False,
        help='specify this to display verbose output')
    # vars() turns Namespace into a regular dictionary
    options = vars(parser.parse_args())
    options['directory'] = chomp_sep(options['directory']) + os.sep
    return options


def chomp_sep(dir_name):
    """Removes any trailing directory separator characters from the given
    directory name.

    Arguments:
        dir_name: the name that has to have any trailing slashes removed

    Returns:
        The directory name with no trailing separator characters
    """
    while dir_name.endswith(os.sep):
        dir_name = dir_name[:-1]
    return dir_name


def chown_dir_user(**kwargs):
    """Removes unneeded files under directory dir_name.

    Arguments:
        kwargs: a dictionary with the following keys:-
            user:       the name of the user/group to assign to files under
                        the given directory
            directory:  the root directory under which to search for
                        unneccessary files to delete
            verbose:    whether to output text describing non-fatal events

    Returns:
        None
    """
    user = kwargs.pop('user')
    directory = kwargs.pop('directory')
    verbose= kwargs.pop('verbose')
    if kwargs:
        raise TypeError('Unexpected **kwargs: %r' % kwargs)
    uid = pwd.getpwnam(user).pw_uid
    gid = grp.getgrnam(user).gr_gid
    for tupl in os.walk(directory):
        # (dir, subdirs, filenames)
        dir_name = tupl[0].decode(encoding='utf-8', errors='ignore')
        for fname in tupl[2]:
            dir_fname = os.path.join(
                dir_name,
                fname.decode(encoding='utf-8', errors='ignore'))
            if os.path.exists(dir_fname):
                try:
                    stat = os.stat(dir_fname)
                except OSError as err:
                    print("Unable to stat '{}' - {}".format(dir_fname, err))
                if stat.st_uid != uid or stat.st_gid != gid:
                    os.chown(dir_fname, uid, gid)
                    if verbose:
                        print("Changed the owner of '{}' to {}:{}".format(
                            dir_fname,
                            user,
                            user))


if __name__ == '__main__':
    run()