diff options
Diffstat (limited to 'gitosis/init.py')
-rw-r--r-- | gitosis/init.py | 113 |
1 files changed, 68 insertions, 45 deletions
diff --git a/gitosis/init.py b/gitosis/init.py index 87ad9a7..ceeaba6 100644 --- a/gitosis/init.py +++ b/gitosis/init.py @@ -2,43 +2,35 @@ Initialize a user account for use with gitosis. """ -import errno import logging import os import sys from pkg_resources import resource_filename from cStringIO import StringIO -from ConfigParser import RawConfigParser +from gitosis import configutil from gitosis import repository from gitosis import run_hook -from gitosis import ssh +from gitosis import sshkey from gitosis import util from gitosis import app +# C0103 - 'log' is a special name +# pylint: disable-msg=C0103 log = logging.getLogger('gitosis.init') -def read_ssh_pubkey(fp=None): - if fp is None: +def read_ssh_pubkey(filename=None): #pragma: no cover + """Read an SSH public key from stdin or file.""" + if filename is None: fp = sys.stdin + else: + fp = file(filename) line = fp.readline() return line -class InsecureSSHKeyUsername(Exception): - """Username contains not allowed characters""" - - def __str__(self): - return '%s: %s' % (self.__doc__, ': '.join(self.args)) - -def ssh_extract_user(pubkey): - _, user = pubkey.rsplit(None, 1) - if ssh.isSafeUsername(user): - return user - else: - raise InsecureSSHKeyUsername(repr(user)) - def initial_commit(git_dir, cfg, pubkey, user): + """Import the initial files into the gitosis-admin repository.""" repository.fast_import( git_dir=git_dir, commit_msg='Automatic creation of gitosis repository.', @@ -49,27 +41,22 @@ def initial_commit(git_dir, cfg, pubkey, user): ], ) -def symlink_config(git_dir): +def symlink_config(git_dir): #pragma: no cover + """ + Place a symlink for the gitosis.conf file in the homedir of the gitosis + user, to make possible to find initially. + """ dst = os.path.expanduser('~/.gitosis.conf') tmp = '%s.%d.tmp' % (dst, os.getpid()) - try: - os.unlink(tmp) - except OSError, e: - if e.errno == errno.ENOENT: - pass - else: - raise + util.unlink(tmp) os.symlink( os.path.join(git_dir, 'gitosis.conf'), tmp, ) os.rename(tmp, dst) -def init_admin_repository( - git_dir, - pubkey, - user, - ): +def init_admin_repository(git_dir, pubkey, user, config): + """Create the initial gitosis-admin reposistory.""" repository.init( path=git_dir, template=resource_filename('gitosis.templates', 'admin') @@ -77,18 +64,26 @@ def init_admin_repository( repository.init( path=git_dir, ) + # Check that the config meets the min requirements + if not config.has_section('gitosis'): + config.add_section('gitosis') + if not config.has_section('group gitosis-admin'): + config.add_section('group gitosis-admin') + if not config.has_option('group gitosis-admin', 'writable'): + config.set('group gitosis-admin', 'writable', 'gitosis-admin') + + # Make sure the admin user is in the admin list, else they will lock themselves out! + adminlist = configutil.get_default(config, 'group gitosis-admin', 'members',' ').split() + if user not in adminlist: + adminlist.append(user) + config.set('group gitosis-admin', 'members', ' '.join(adminlist)) + if not repository.has_initial_commit(git_dir): log.info('Making initial commit...') # ConfigParser does not guarantee order, so jump through hoops # to make sure [gitosis] is first cfg_file = StringIO() - print >>cfg_file, '[gitosis]' - print >>cfg_file - cfg = RawConfigParser() - cfg.add_section('group gitosis-admin') - cfg.set('group gitosis-admin', 'members', user) - cfg.set('group gitosis-admin', 'writable', 'gitosis-admin') - cfg.write(cfg_file) + config.write(cfg_file) initial_commit( git_dir=git_dir, cfg=cfg_file.getvalue(), @@ -97,28 +92,55 @@ def init_admin_repository( ) class Main(app.App): + """gitosis-init program.""" + # W0613 - They also might ignore arguments here, where the descendant + # methods won't. + # pylint: disable-msg=W0613 + def create_parser(self): + """Declare the input for this program.""" parser = super(Main, self).create_parser() parser.set_usage('%prog [OPTS]') parser.set_description( - 'Initialize a user account for use with gitosis') + 'Initialize a user account for use with gitosis' + ) + parser.set_defaults( + adminkey=None, + adminname=None, + ) + parser.add_option('--adminkey', + metavar='FILE', + help='Admin SSH public key FILE location', + ) + parser.add_option('--adminname', + metavar='STRING', + help='Name for administrator public key file', + ) return parser - def read_config(self, *a, **kw): - # ignore errors that result from non-existent config file + def read_config(self, options, cfg): + """Ignore errors that result from non-existent config file.""" + # Pylint gets it wrong. + # pylint: disable-msg=W0704 try: - super(Main, self).read_config(*a, **kw) + super(Main, self).read_config(options, cfg) except app.ConfigFileDoesNotExistError: pass - def handle_args(self, parser, cfg, options, args): + def handle_args(self, parser, cfg, options, args): #pragma: no cover + """Parse the input for this program.""" super(Main, self).handle_args(parser, cfg, options, args) os.umask(0022) log.info('Reading SSH public key...') - pubkey = read_ssh_pubkey() - user = ssh_extract_user(pubkey) + pubkey = read_ssh_pubkey(options.adminkey) + if options.adminname is None: + _ = sshkey.get_ssh_pubkey(pubkey) + user = _.username + else: + user = options.adminname + user = user.strip() if user is None: log.error('Cannot parse user from SSH public key.') sys.exit(1) @@ -134,6 +156,7 @@ class Main(app.App): git_dir=admin_repository, pubkey=pubkey, user=user, + config=cfg, ) log.info('Running post-update hook...') util.mkdir(os.path.expanduser('~/.ssh'), 0700) |