Advertisement
justin_hanekom

create-dpkg-list.py

May 13th, 2019
266
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 8.61 KB | None | 0 0
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3.  
  4. # File: create-dpkg-list.py
  5. # Copyright (c) 2018-2019 Justin Hanekom <justin_hanekom@yahoo.com>
  6. # Licensed under the MIT License
  7.  
  8. # Permission is hereby granted, free of charge, to any person obtaining
  9. # a copy of this software and associated documentation files
  10. # (the "Software"), to deal in the Software without restriction,
  11. # including without limitation the rights to use, copy, modify, merge,
  12. # publish, distribute, sublicense, and/or sell copies of the Software,
  13. # and to permit persons to whom the Software is furnished to do so,
  14. # subject to the following conditions:
  15. #
  16. # The above copyright notice and this permission notice shall be
  17. # included in all copies or substantial portions of the Software.
  18. #
  19. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  20. # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  21. # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  22. # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
  23. # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  24. # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  25. # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  26.  
  27. from __future__ import (
  28.     absolute_import, division, print_function, unicode_literals
  29. )
  30. from nine import (
  31.     IS_PYTHON2, basestring, chr, class_types, filter, integer_types,
  32.     implements_iterator, implements_to_string, implements_repr,
  33.     input, iterkeys, iteritems, itervalues, long, map,
  34.     native_str, nine, nimport, range, range_list, reraise, str, zip
  35. )
  36.  
  37. argparse = nimport('argparse')
  38. glob = nimport('glob')
  39. grp = nimport('grp')
  40. os = nimport('os')
  41. pwd = nimport('pwd')
  42. subprocess = nimport('subprocess')
  43. sys = nimport('sys')
  44. time = nimport('time')
  45.  
  46. DEFAULT_PREFIX = 'dpkg_'
  47. DEFAULT_SUFFIX = '.txt'
  48.  
  49.  
  50. def run():
  51.     """Runs this program.
  52.  
  53.    The program runs 'dpkg --list' to store the current package list
  54.    into a time-stamped file in the given destination directory.
  55.  
  56.    Returns:
  57.        None
  58.    """
  59.     start_time = time.time()
  60.     options = parse_cmd_line(
  61.             default_prefix=DEFAULT_PREFIX,
  62.             default_suffix=DEFAULT_SUFFIX)
  63.     remove_old_files(
  64.         pattern='{destdir}{sep}{prefix}*{suffix}'.format(
  65.             destdir=options['destdir'],
  66.             sep=os.sep,
  67.             prefix=options['prefix'],
  68.             suffix=options['suffix']),
  69.         remove=options['remove'],
  70.         verbose=options['verbose'])
  71.     dest_file = generate_results_file_name(
  72.         dest_dir=options['destdir'],
  73.         prefix=options['prefix'],
  74.         suffix=options['suffix'])
  75.     dpkg_list(
  76.         dest_file=dest_file,
  77.         verbose=options['verbose'])
  78.     change_file_owner_group(
  79.         filename=dest_file,
  80.         user=options['user'],
  81.         group=options['user'],
  82.         verbose=options['verbose'])
  83.     if options['verbose']:
  84.         print('Done, in {} seconds!'.format(time.time() - start_time))
  85.  
  86.  
  87. def parse_cmd_line(default_prefix, default_suffix):
  88.     """Parses the command-line arguments.
  89.  
  90.    Arguments:
  91.        default_prefix: the default prefix for the generated dpkg list file
  92.        default_suffix: the default suffix for the generated dpkg list file
  93.  
  94.    Returns:
  95.        A dictionary with each of the supplied command-line arguments.
  96.    """
  97.     parser = argparse.ArgumentParser(
  98.         description="Stores 'dpkg --list' results")
  99.     parser.add_argument(
  100.         'user',
  101.         help=' '.join([
  102.             'specify the owner of the dpkg list file;',
  103.             'the dpkg list file user and group will be set to this value']))
  104.     parser.add_argument(
  105.         'destdir',
  106.         help=' '.join([
  107.             'specify the directory that the dpkg list file',
  108.             'will be saved to']))
  109.     parser.add_argument(
  110.         '--prefix', '-p',
  111.         default=default_prefix,
  112.         help=' '.join([
  113.             'specify the prefix to use for the dpkg list file',
  114.             "(default: '%(default)s')"]))
  115.     parser.add_argument(
  116.         '--suffix', '-s',
  117.         default=default_suffix,
  118.         help=' '.join([
  119.             'specify the suffix to use for the dpkg list file',
  120.             "(default: '%(default)s')"]))
  121.     parser.add_argument(
  122.         '--remove', '-r',
  123.         action='store_true',
  124.         default=False,
  125.         help='specify this to enable the removal of obsolete dpkg list files')
  126.     parser.add_argument(
  127.         '--verbose', '-v',
  128.         action='store_true',
  129.         default=False,
  130.         help='specify this to display verbose output')
  131.     # vars() turns Namespace into a regular dictionary
  132.     options = vars(parser.parse_args())
  133.     options['destdir'] = chomp_sep(options['destdir'])
  134.     return options
  135.  
  136.  
  137. def chomp_sep(dir_name):
  138.     """Removes any trailing directory separator characters from the given
  139.    directory name.
  140.  
  141.    Arguments:
  142.        dir_name: the name that has to have any trailing slashes removed
  143.  
  144.    Returns:
  145.        The directory name with no trailing separator characters
  146.    """
  147.     while dir_name.endswith(os.sep):
  148.         dir_name = dir_name[:-1]
  149.     return dir_name
  150.  
  151.  
  152. def remove_old_files(**kwargs):
  153.     """Only keeps the newest files that match the given pattern.
  154.  
  155.    Arguments:
  156.        kwargs: a dictionary with the following keys:-
  157.            'pattern'   - the glob pattern of existing files
  158.            'remove'    - whether to remove old files
  159.            'verbose'   - whether to output text describing non-fatal events
  160.  
  161.    Returns:
  162.        None
  163.    """
  164.     pattern = kwargs.pop('pattern')
  165.     remove = kwargs.pop('remove')
  166.     verbose= kwargs.pop('verbose')
  167.     if kwargs:
  168.         raise TypeError('Unexpected **kwargs: %r' % kwargs)
  169.     if not remove:
  170.         return
  171.     for f in glob.glob(pattern):
  172.         os.remove(f)
  173.         if verbose:
  174.             print("Removed file '{filename}'".format(filename=f))
  175.  
  176.  
  177. def generate_results_file_name(dest_dir, prefix, suffix):
  178.     """Generates a results file filename prefix.
  179.  
  180.    Arguments:
  181.        dest_dir:   the directory into which the results file should be saved
  182.        prefix:     the prefix to use for the results file
  183.        suffix:     the suffix to use for the results file
  184.  
  185.    Returns:
  186.        A unique results file filename of the format:
  187.            <dest_dir>/<prefix><year><month><day><hour><minute>second><suffix>
  188.        where the year, month, day, etc. values represent the local time
  189.        at the point at which this function is called.
  190.    """
  191.     localtime = time.localtime()
  192.     return ('{dest_dir}{sep}{prefix}{year:04d}{month:02d}{day:02d}' +
  193.         '{hour:02d}{minute:02d}{second:02d}{suffix}').format(
  194.             dest_dir=dest_dir,
  195.             prefix=prefix,
  196.             suffix=suffix,
  197.             year=localtime[0],
  198.             month=localtime[1],
  199.             day=localtime[2],
  200.             hour=localtime[3],
  201.             minute=localtime[4],
  202.             second=localtime[5],
  203.             sep=os.sep)
  204.  
  205.  
  206. def dpkg_list(dest_file, verbose):
  207.     """Creates a clone file into .
  208.  
  209.    Arguments:
  210.        dest_file:  what to name of the dpkg --list results file
  211.        verbose:    whether to output text describing non-fatal events
  212.  
  213.    Returns:
  214.        None
  215.   """
  216.     subprocess.call(
  217.         'dpkg --list > "{}"'.format(dest_file), shell=True)
  218.     if verbose:
  219.         print('Performed apt-clone clone to: {}'.format(dest_file))
  220.  
  221.  
  222. def change_file_owner_group(**kwargs):
  223.     """Changes the owner and group of the named file.
  224.  
  225.    Arguments:
  226.        kwargs: a dictionary with the following keys:-
  227.            'filename': the file whose ownership is to be changed
  228.            'user':     the new owner to assign to the file
  229.            'group':    the new group to assign to the file;
  230.                        this is the same as 'user' if not given
  231.            'verbose':  whether to output text describing non-fatal events
  232.  
  233.    Returns:
  234.        None
  235.    """
  236.     filename = kwargs.pop('filename')
  237.     user = kwargs.pop('user')
  238.     group = kwargs.pop('group', user)
  239.     verbose= kwargs.pop('verbose')
  240.     if kwargs:
  241.         raise TypeError('Unexpected **kwargs: %r' % kwargs)
  242.     try:
  243.         os.chown(filename,
  244.                  pwd.getpwnam(user).pw_uid,
  245.                  grp.getgrnam(group).gr_gid)
  246.         if verbose:
  247.             print("Changed ownership of '{filename}' to {user}:{group}".format(
  248.                   filename=filename,
  249.                   user=user,
  250.                   group=group))
  251.     except os.OSError:
  252.         print("Unable to change ownership of "
  253.             + "'{filename}' to {user}:{group}".format(
  254.                 filename=filename,
  255.                 user=user,
  256.                 group=group),
  257.             file=sys.stderr)
  258.  
  259.  
  260. if __name__ == '__main__':
  261.     run()
  262.  
  263. # vim: set filetype=python smartindent autoindent smarttab expandtab tabstop=4 softtabstop=4 shiftwidth=4 autoread
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement