Advertisement
justin_hanekom

setup-links-to-dropbox.py

May 13th, 2019
775
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 9.54 KB | None | 0 0
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3.  
  4. # File: setup-links-to-dropbox.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. os = nimport('os')
  39. shutil = nimport('shutil')
  40. sys = nimport('sys')
  41. time = nimport('time')
  42.  
  43.  
  44. def run():
  45.     """Runs this program.
  46.  
  47.    The program creates symbolic links in the source directory to content
  48.    stored in the Dropbox directory.
  49.    """
  50.     COMMON_LINK_DIRS = [
  51.         'Documents',
  52.         'Music',
  53.         'Pictures',
  54.         'src',
  55.         'Videos'
  56.     ]
  57.     LINUX_LINK_DIRS  = [
  58.         'bin',
  59.         'Downloads',
  60.         '.gnupg',
  61.         '.m2',
  62.         '.pki',
  63.         'sbin',
  64.         '.ssh',
  65.         '.vim',
  66.         'VirtualBox VMs'
  67.     ]
  68.     ALL_LINK_DIRS = COMMON_LINK_DIRS + LINUX_LINK_DIRS
  69.     LINUX_LINK_FILES = [
  70.         '.bash_justin',
  71.         '.gitconfig',
  72.         '.gitignore',
  73.         '.hgignore',
  74.         '.hgrc',
  75.         '.perltidyrc',
  76.         'hosts',
  77.         '.tmux.conf',
  78.         '.vimrc'
  79.     ]
  80.  
  81.     start_time = time.time()
  82.     options = parse_cmd_line()
  83.     COMMON_DIR = os.path.join(options['srcdir'], 'Common')
  84.     LINUX_DIR = os.path.join(options['srcdir'], 'Linux')
  85.     remove_conflicting_links(
  86.         dest_dir=options['destdir'],
  87.         dir_links=ALL_LINK_DIRS,
  88.         file_links=LINUX_LINK_FILES,
  89.         remove=options['remove'],
  90.         verbose=options['verbose'])
  91.     setup_links_to_dropbox(
  92.         common_src_dir=COMMON_DIR,
  93.         common_link_dir_names=COMMON_LINK_DIRS,
  94.         linux_src_dir=LINUX_DIR,
  95.         linux_link_dir_names=LINUX_LINK_DIRS,
  96.         linux_link_file_names=LINUX_LINK_FILES,
  97.         dest_dir=options['destdir'],
  98.         verbose=options['verbose'])
  99.     if options['verbose']:
  100.         print('Done, in {} seconds!'.format(time.time() - start_time))
  101.  
  102.  
  103. def parse_cmd_line():
  104.     """Parses the command-line arguments.
  105.  
  106.    Arguments:
  107.        None
  108.  
  109.    Returns:
  110.        A dictionary with each of the supplied command-line arguments. If
  111.        no value for an item was supplied on the command-line, then the
  112.        default value for that it is returned.
  113.    """
  114.     parser = argparse.ArgumentParser(
  115.         description=' '.join([
  116.             'Creates symbolic links in the destination directory to content',
  117.             'that is stored under the Dropbox source directory']))
  118.     parser.add_argument(
  119.         'srcdir',
  120.         help='specify the source (Dropbox) directory')
  121.     parser.add_argument(
  122.         'destdir',
  123.         help=' '.join([
  124.             'specify the directory that will receive symbolic links to content',
  125.             'stored in the source directory']))
  126.     parser.add_argument(
  127.         '--remove', '-r',
  128.         action='store_true',
  129.         default=False,
  130.         help=' '.join([
  131.             'specify this so that any content stored in the destination',
  132.             'directory with the same name as any of the links',
  133.             'will be removed before the symbolic links are created']))
  134.     parser.add_argument(
  135.         '--verbose', '-v',
  136.         action='store_true',
  137.         default=False,
  138.         help='specify this to display verbose output')
  139.     # vars() turns Namespace into a regular dictionary
  140.     options = vars(parser.parse_args())
  141.     options['srcdir'] = chomp_sep(options['srcdir'].strip())
  142.     options['destdir'] = chomp_sep(options['destdir'].strip())
  143.     return options
  144.  
  145.  
  146. def chomp_sep(dir_name):
  147.     """Removes any trailing directory separator characters from the given
  148.    directory name.
  149.  
  150.    Arguments:
  151.        dir_name: the name that has to have any trailing slashes removed
  152.  
  153.    Returns:
  154.        The directory name with no trailing separator characters
  155.    """
  156.     while dir_name.endswith(os.sep):
  157.         dir_name = dir_name[:-1]
  158.     return dir_name
  159.  
  160.  
  161. def remove_conflicting_links(**kwargs):
  162.     """Removes any files or directories in the destination directory, dest_dir,
  163.    that will be overwritten when the links to the Dropbox source are created
  164.  
  165.    Arguments:
  166.        kwargs: a dictionary with the following keys:-
  167.            dest_dir:   the directory from which to remove any conflicting files
  168.                        or directories
  169.            dir_links:  a list of directory links that will be created in the
  170.                        dest_dir
  171.            file_links: a list of the file links that will be created in the
  172.                        dest_dir
  173.            remove:     whether or not to remove conflicting files/directories
  174.            verbose:    whether or not to output text describing non-fatal
  175.                        events
  176.  
  177.    Returns:
  178.        None
  179.    """
  180.     dest_dir = kwargs.pop('dest_dir')
  181.     dir_links = kwargs.pop('dir_links')
  182.     file_links = kwargs.pop('file_links')
  183.     remove = kwargs.pop('remove')
  184.     verbose= kwargs.pop('verbose')
  185.     if kwargs:
  186.         raise TypeError('Unexpected **kwargs: %r' % kwargs)
  187.     if not remove:
  188.         return
  189.     for dir_name in dir_links:
  190.         dir_path = os.path.join(dest_dir, dir_name)
  191.         if os.path.exists(dir_path):
  192.             try:
  193.                 shutil.rmtree(dir_path, ignore_errors=False, onerror=None)
  194.             except:
  195.                 print(
  196.                     "Unable to remove directory '{}'".format(dir_path),
  197.                     file=sys.stderr)
  198.             if verbose:
  199.                 print("Removed '{}'".format(dir_path))
  200.     for file_name in file_links:
  201.         file_path = os.path.join(dest_dir, file_name)
  202.         if os.path.exists(file_path):
  203.             try:
  204.                 os.remove(file_path)
  205.             except:
  206.                 print(
  207.                     "Unable to remove file '{}'".format(file_path),
  208.                     file=sys.stderr)
  209.             if verbose:
  210.                 print("Removed '{}'".format(file_path))
  211.  
  212. def setup_links_to_dropbox(**kwargs):
  213.     """Creates symbolic links in the destination directory, dest_dir.
  214.  
  215.    These links point to files and directories that are stored under the
  216.    Dropbox folder.
  217.  
  218.    Arguments:
  219.        kwargs: a dictionary with the following keys:-
  220.            common_src_dir:         the name of the source directory that
  221.                                    contains common content
  222.            common_link_dir_names:  names of the directories that contain
  223.                                    common content
  224.            linux_src_dir:          the name of the source directory that
  225.                                    contains Linux-specific content
  226.            linux_link_dir_names:   names of the directories that contain
  227.                                    Linux-specific content
  228.            linux_link_file_names:  names of the Linux-specific files
  229.            dest_dir:               the name of the destination directory where
  230.                                    symbolic links are to be created
  231.            verbose:                whether or not to output text describing
  232.                                    non-fatal events
  233.    """
  234.     common_src_dir = kwargs.pop('common_src_dir')
  235.     common_link_dir_names = kwargs.pop('common_link_dir_names')
  236.     linux_src_dir = kwargs.pop('linux_src_dir')
  237.     linux_link_dir_names = kwargs.pop('linux_link_dir_names')
  238.     linux_link_file_names = kwargs.pop('linux_link_file_names')
  239.     dest_dir = kwargs.pop('dest_dir')
  240.     verbose = kwargs.pop('verbose')
  241.     if kwargs:
  242.         raise TypeError('Unexpected **kwargs: %r' % kwargs)
  243.     for dir_name in common_link_dir_names:
  244.         src_path = os.path.join(common_src_dir, dir_name)
  245.         dest_path = os.path.join(dest_dir, dir_name)
  246.         os.symlink(src_path, dest_path)
  247.         if verbose:
  248.             print("'{}' => '{}'".format(dest_path, src_path))
  249.     for dir_name in linux_link_dir_names:
  250.         src_path = os.path.join(linux_src_dir, dir_name)
  251.         dest_path = os.path.join(dest_dir, dir_name)
  252.         os.symlink(src_path, dest_path)
  253.         if verbose:
  254.             print("'{}' => '{}'".format(dest_path, src_path))
  255.     for file_name in linux_link_file_names:
  256.         src_path = os.path.join(linux_src_dir, file_name)
  257.         dest_path = os.path.join(dest_dir, file_name)
  258.         os.symlink(src_path, dest_path)
  259.         if verbose:
  260.             print("'{}' => '{}'".format(dest_path, src_path))
  261.  
  262.  
  263. if __name__ == '__main__':
  264.     run()
  265.  
  266. # vim: set filetype=sh autoread expandtab smarttab softtabstop=4 shiftwidth=4 tabstop=4 autoindent smartindent
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement