274 lines
		
	
	
	
		
			7.8 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable file
		
	
	
	
	
			
		
		
	
	
			274 lines
		
	
	
	
		
			7.8 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable file
		
	
	
	
	
#! /usr/bin/env python
 | 
						|
 | 
						|
"""Migrate a post-receive-email configuration to be usable with git_multimail.py.
 | 
						|
 | 
						|
See README.migrate-from-post-receive-email for more information.
 | 
						|
 | 
						|
"""
 | 
						|
 | 
						|
import sys
 | 
						|
import optparse
 | 
						|
 | 
						|
from git_multimail import CommandError
 | 
						|
from git_multimail import Config
 | 
						|
from git_multimail import read_output
 | 
						|
 | 
						|
 | 
						|
OLD_NAMES = [
 | 
						|
    'mailinglist',
 | 
						|
    'announcelist',
 | 
						|
    'envelopesender',
 | 
						|
    'emailprefix',
 | 
						|
    'showrev',
 | 
						|
    'emailmaxlines',
 | 
						|
    'diffopts',
 | 
						|
    'scancommitforcc',
 | 
						|
    ]
 | 
						|
 | 
						|
NEW_NAMES = [
 | 
						|
    'environment',
 | 
						|
    'reponame',
 | 
						|
    'mailinglist',
 | 
						|
    'refchangelist',
 | 
						|
    'commitlist',
 | 
						|
    'announcelist',
 | 
						|
    'announceshortlog',
 | 
						|
    'envelopesender',
 | 
						|
    'administrator',
 | 
						|
    'emailprefix',
 | 
						|
    'emailmaxlines',
 | 
						|
    'diffopts',
 | 
						|
    'emaildomain',
 | 
						|
    'scancommitforcc',
 | 
						|
    ]
 | 
						|
 | 
						|
 | 
						|
INFO = """\
 | 
						|
 | 
						|
SUCCESS!
 | 
						|
 | 
						|
Your post-receive-email configuration has been converted to
 | 
						|
git-multimail format.  Please see README and
 | 
						|
README.migrate-from-post-receive-email to learn about other
 | 
						|
git-multimail configuration possibilities.
 | 
						|
 | 
						|
For example, git-multimail has the following new options with no
 | 
						|
equivalent in post-receive-email.  You might want to read about them
 | 
						|
to see if they would be useful in your situation:
 | 
						|
 | 
						|
"""
 | 
						|
 | 
						|
 | 
						|
def _check_old_config_exists(old):
 | 
						|
    """Check that at least one old configuration value is set."""
 | 
						|
 | 
						|
    for name in OLD_NAMES:
 | 
						|
        if name in old:
 | 
						|
            return True
 | 
						|
 | 
						|
    return False
 | 
						|
 | 
						|
 | 
						|
def _check_new_config_clear(new):
 | 
						|
    """Check that none of the new configuration names are set."""
 | 
						|
 | 
						|
    retval = True
 | 
						|
    for name in NEW_NAMES:
 | 
						|
        if name in new:
 | 
						|
            if retval:
 | 
						|
                sys.stderr.write('INFO: The following configuration values already exist:\n\n')
 | 
						|
            sys.stderr.write('    "%s.%s"\n' % (new.section, name))
 | 
						|
            retval = False
 | 
						|
 | 
						|
    return retval
 | 
						|
 | 
						|
 | 
						|
def erase_values(config, names):
 | 
						|
    for name in names:
 | 
						|
        if name in config:
 | 
						|
            try:
 | 
						|
                sys.stderr.write('...unsetting "%s.%s"\n' % (config.section, name))
 | 
						|
                config.unset_all(name)
 | 
						|
            except CommandError:
 | 
						|
                sys.stderr.write(
 | 
						|
                    '\nWARNING: could not unset "%s.%s".  '
 | 
						|
                    'Perhaps it is not set at the --local level?\n\n'
 | 
						|
                    % (config.section, name)
 | 
						|
                    )
 | 
						|
 | 
						|
 | 
						|
def is_section_empty(section, local):
 | 
						|
    """Return True iff the specified configuration section is empty.
 | 
						|
 | 
						|
    Iff local is True, use the --local option when invoking 'git
 | 
						|
    config'."""
 | 
						|
 | 
						|
    if local:
 | 
						|
        local_option = ['--local']
 | 
						|
    else:
 | 
						|
        local_option = []
 | 
						|
 | 
						|
    try:
 | 
						|
        read_output(
 | 
						|
            ['git', 'config'] +
 | 
						|
            local_option +
 | 
						|
            ['--get-regexp', '^%s\.' % (section,)]
 | 
						|
            )
 | 
						|
    except CommandError:
 | 
						|
        t, e, traceback = sys.exc_info()
 | 
						|
        if e.retcode == 1:
 | 
						|
            # This means that no settings were found.
 | 
						|
            return True
 | 
						|
        else:
 | 
						|
            raise
 | 
						|
    else:
 | 
						|
        return False
 | 
						|
 | 
						|
 | 
						|
def remove_section_if_empty(section):
 | 
						|
    """If the specified configuration section is empty, delete it."""
 | 
						|
 | 
						|
    try:
 | 
						|
        empty = is_section_empty(section, local=True)
 | 
						|
    except CommandError:
 | 
						|
        # Older versions of git do not support the --local option, so
 | 
						|
        # if the first attempt fails, try without --local.
 | 
						|
        try:
 | 
						|
            empty = is_section_empty(section, local=False)
 | 
						|
        except CommandError:
 | 
						|
            sys.stderr.write(
 | 
						|
                '\nINFO: If configuration section "%s.*" is empty, you might want '
 | 
						|
                'to delete it.\n\n'
 | 
						|
                % (section,)
 | 
						|
                )
 | 
						|
            return
 | 
						|
 | 
						|
    if empty:
 | 
						|
        sys.stderr.write('...removing section "%s.*"\n' % (section,))
 | 
						|
        read_output(['git', 'config', '--remove-section', section])
 | 
						|
    else:
 | 
						|
        sys.stderr.write(
 | 
						|
            '\nINFO: Configuration section "%s.*" still has contents.  '
 | 
						|
            'It will not be deleted.\n\n'
 | 
						|
            % (section,)
 | 
						|
            )
 | 
						|
 | 
						|
 | 
						|
def migrate_config(strict=False, retain=False, overwrite=False):
 | 
						|
    old = Config('hooks')
 | 
						|
    new = Config('multimailhook')
 | 
						|
    if not _check_old_config_exists(old):
 | 
						|
        sys.exit(
 | 
						|
            'Your repository has no post-receive-email configuration.  '
 | 
						|
            'Nothing to do.'
 | 
						|
            )
 | 
						|
    if not _check_new_config_clear(new):
 | 
						|
        if overwrite:
 | 
						|
            sys.stderr.write('\nWARNING: Erasing the above values...\n\n')
 | 
						|
            erase_values(new, NEW_NAMES)
 | 
						|
        else:
 | 
						|
            sys.exit(
 | 
						|
                '\nERROR: Refusing to overwrite existing values.  Use the --overwrite\n'
 | 
						|
                'option to continue anyway.'
 | 
						|
                )
 | 
						|
 | 
						|
    name = 'showrev'
 | 
						|
    if name in old:
 | 
						|
        msg = 'git-multimail does not support "%s.%s"' % (old.section, name,)
 | 
						|
        if strict:
 | 
						|
            sys.exit(
 | 
						|
                'ERROR: %s.\n'
 | 
						|
                'Please unset that value then try again, or run without --strict.'
 | 
						|
                % (msg,)
 | 
						|
                )
 | 
						|
        else:
 | 
						|
            sys.stderr.write('\nWARNING: %s (ignoring).\n\n' % (msg,))
 | 
						|
 | 
						|
    for name in ['mailinglist', 'announcelist']:
 | 
						|
        if name in old:
 | 
						|
            sys.stderr.write(
 | 
						|
                '...copying "%s.%s" to "%s.%s"\n' % (old.section, name, new.section, name)
 | 
						|
                )
 | 
						|
            old_recipients = old.get_all(name, default=None)
 | 
						|
            old_recipients = ', '.join(o.strip() for o in old_recipients)
 | 
						|
            new.set_recipients(name, old_recipients)
 | 
						|
 | 
						|
    if strict:
 | 
						|
        sys.stderr.write(
 | 
						|
            '...setting "%s.commitlist" to the empty string\n' % (new.section,)
 | 
						|
            )
 | 
						|
        new.set_recipients('commitlist', '')
 | 
						|
        sys.stderr.write(
 | 
						|
            '...setting "%s.announceshortlog" to "true"\n' % (new.section,)
 | 
						|
            )
 | 
						|
        new.set('announceshortlog', 'true')
 | 
						|
 | 
						|
    for name in ['envelopesender', 'emailmaxlines', 'diffopts', 'scancommitforcc']:
 | 
						|
        if name in old:
 | 
						|
            sys.stderr.write(
 | 
						|
                '...copying "%s.%s" to "%s.%s"\n' % (old.section, name, new.section, name)
 | 
						|
                )
 | 
						|
            new.set(name, old.get(name))
 | 
						|
 | 
						|
    name = 'emailprefix'
 | 
						|
    if name in old:
 | 
						|
        sys.stderr.write(
 | 
						|
            '...copying "%s.%s" to "%s.%s"\n' % (old.section, name, new.section, name)
 | 
						|
            )
 | 
						|
        new.set(name, old.get(name))
 | 
						|
    elif strict:
 | 
						|
        sys.stderr.write(
 | 
						|
            '...setting "%s.%s" to "[SCM]" to preserve old subject lines\n'
 | 
						|
            % (new.section, name)
 | 
						|
            )
 | 
						|
        new.set(name, '[SCM]')
 | 
						|
 | 
						|
    if not retain:
 | 
						|
        erase_values(old, OLD_NAMES)
 | 
						|
        remove_section_if_empty(old.section)
 | 
						|
 | 
						|
    sys.stderr.write(INFO)
 | 
						|
    for name in NEW_NAMES:
 | 
						|
        if name not in OLD_NAMES:
 | 
						|
            sys.stderr.write('    "%s.%s"\n' % (new.section, name,))
 | 
						|
    sys.stderr.write('\n')
 | 
						|
 | 
						|
 | 
						|
def main(args):
 | 
						|
    parser = optparse.OptionParser(
 | 
						|
        description=__doc__,
 | 
						|
        usage='%prog [OPTIONS]',
 | 
						|
        )
 | 
						|
 | 
						|
    parser.add_option(
 | 
						|
        '--strict', action='store_true', default=False,
 | 
						|
        help=(
 | 
						|
            'Slavishly configure git-multimail as closely as possible to '
 | 
						|
            'the post-receive-email configuration.  Default is to turn '
 | 
						|
            'on some new features that have no equivalent in post-receive-email.'
 | 
						|
            ),
 | 
						|
        )
 | 
						|
    parser.add_option(
 | 
						|
        '--retain', action='store_true', default=False,
 | 
						|
        help=(
 | 
						|
            'Retain the post-receive-email configuration values.  '
 | 
						|
            'Default is to delete them after the new values are set.'
 | 
						|
            ),
 | 
						|
        )
 | 
						|
    parser.add_option(
 | 
						|
        '--overwrite', action='store_true', default=False,
 | 
						|
        help=(
 | 
						|
            'Overwrite any existing git-multimail configuration settings.  '
 | 
						|
            'Default is to abort if such settings already exist.'
 | 
						|
            ),
 | 
						|
        )
 | 
						|
 | 
						|
    (options, args) = parser.parse_args(args)
 | 
						|
 | 
						|
    if args:
 | 
						|
        parser.error('Unexpected arguments: %s' % (' '.join(args),))
 | 
						|
 | 
						|
    migrate_config(strict=options.strict, retain=options.retain, overwrite=options.overwrite)
 | 
						|
 | 
						|
 | 
						|
main(sys.argv[1:])
 |