- #!/usr/bin/env python
- #
- # Python script to facilitate the hardlinking of directories and their files.
- import sys
- if sys.version_info < (2, 3):
- raise RuntimeError('Python 2.3+ is required.')
- import logging
- import optparse
- import os
- version = '\nhardlinkify-1.0 - by Jake Wharton <jakewharton@gmail.com>\n'
- #CLI argument parser
- parser = optparse.OptionParser(usage='Usage: %prog [options] source [source ...] destination', version=version)
- parser.add_option('-d', '--debug', dest='is_debug', action='store_true', default=False, help='print detailed execution information')
- parser.add_option('-q', '--quiet', dest='is_quiet', action='store_true', default=False, help='no output except warnings and errors')
- options, targets = parser.parse_args()
- #Print version if not quiet
- if not options.is_quiet:
- parser.print_version()
- #Logging setup
- level = logging.INFO
- if options.is_quiet:
- level = logging.WARN
- if options.is_debug:
- level = logging.DEBUG
- logging.basicConfig(format='%(asctime)s %(levelname)-7s %(message)s')
- logger = logging.getLogger(os.path.basename(__file__))
- logger.setLevel(level)
- #Error checking
- if options.is_quiet and options.is_debug:
- logger.warn('Options --quiet and --debug are mutually exclusive. Ignoring --quiet.')
- if len(targets) < 2:
- logger.error('You must specify at least one source and the destination.')
- sys.exit(1)
- def link(file=None, dest=None, unroll=False):
- if file is None:
- raise ValueError('File parameter is required.')
- if dest is None:
- raise ValueError('Destination parameter is required.')
- if not os.path.exists(file):
- logger.warn('File "%s" does not exist. Skipping.', file)
- return
- elif os.path.isdir(file):
- if unroll:
- logger.debug('Unrolling directory "%s" in "%s".', file, dest)
- new_dest = dest if unroll else os.path.join(dest, os.path.basename(file))
- for new_file_name in os.listdir(file):
- new_file = os.path.join(file, new_file_name)
- logger.debug('> link("%s", "%s")', new_file, new_dest)
- link(new_file, new_dest)
- return
- if not os.path.exists(dest):
- logger.info('Directory "%s" does not exist. Creating.', dest)
- os.makedirs(dest)
- new_file = os.path.join(dest, os.path.basename(file))
- if os.path.exists(new_file):
- logger.warn('File "%s" already exists. Skipping.', new_file)
- return
- logger.info('Linking "%s" to "%s"...', new_file, file)
- os.link(file, new_file)
- #Get arguments and perform linking
- destination = os.path.abspath(targets[-1])
- logger.debug('Destination: %s', destination)
- files = [os.path.abspath(file) for file in targets[:-1]]
- for file in files:
- logger.debug('File: %s', file)
- for file in files:
- logger.debug('> link("%s", "%s")', file, destination)
- link(file, destination, True)