aboutsummaryrefslogtreecommitdiff
path: root/gitosis/init.py
blob: ceeaba6956bde93be50d937c16319725c2b76cd4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
"""
Initialize a user account for use with gitosis.
"""
 
import logging
import os
import sys
 
from pkg_resources import resource_filename
from cStringIO import StringIO
 
from gitosis import configutil
from gitosis import repository
from gitosis import run_hook
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(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
 
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.',
        committer='Gitosis Admin <%s>' % user,
        files=[ 
            ('keydir/%s.pub' % userpubkey), 
            ('gitosis.conf'cfg), 
            ],
        )
 
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' % (dstos.getpid())
    util.unlink(tmp)
    os.symlink(
        os.path.join(git_dir'gitosis.conf'),
        tmp,
        )
    os.rename(tmpdst)
 
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') 
        )
    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()
        config.write(cfg_file)
        initial_commit(
            git_dir=git_dir,
            cfg=cfg_file.getvalue(),
            pubkey=pubkey,
            user=user,
            )
 
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(Mainself).create_parser()
        parser.set_usage('%prog [OPTS]')
        parser.set_description(
            '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, options, cfg):
        """Ignore errors that result from non-existent config file."""
        # Pylint gets it wrong. 
        # pylint: disable-msg=W0704 
        try:
            super(Mainself).read_config(optionscfg)
        except app.ConfigFileDoesNotExistError:
            pass
 
    def handle_args(self, parser, cfg, options, args): #pragma: no cover 
        """Parse the input for this program."""
        super(Mainself).handle_args(parsercfgoptionsargs)
 
        os.umask(0022)
 
        log.info('Reading SSH public key...')
        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)
        log.info('Admin user is %r'user)
        log.info('Creating generated files directory...')
        generated = util.getGeneratedFilesDir(config=cfg)
        util.mkdir(generated)
        log.info('Creating repository structure...')
        repositories = util.getRepositoryDir(cfg)
        util.mkdir(repositories)
        admin_repository = os.path.join(repositories'gitosis-admin.git')
        init_admin_repository(
            git_dir=admin_repository,
            pubkey=pubkey,
            user=user,
            config=cfg,
            )
        log.info('Running post-update hook...')
        util.mkdir(os.path.expanduser('~/.ssh')0700)
        run_hook.post_update(cfg=cfg, git_dir=admin_repository)
        log.info('Symlinking ~/.gitosis.conf to repository...')
        symlink_config(git_dir=admin_repository)
        log.info('Done.')