aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTommi Virtanen <tv@eagain.net>2007-09-03 17:04:41 -0700
committerTommi Virtanen <tv@eagain.net>2007-09-03 17:09:12 -0700
commit8a0654abe2db919b04683d40100b469e8c3adc4b (patch)
tree57903f32603cc57bd894c62ec2a0fa87d0985e15
parentMake setuptools include templates in the egg. (diff)
downloadgitosis-dakkar-8a0654abe2db919b04683d40100b469e8c3adc4b.tar.gz
gitosis-dakkar-8a0654abe2db919b04683d40100b469e8c3adc4b.tar.bz2
gitosis-dakkar-8a0654abe2db919b04683d40100b469e8c3adc4b.zip
Refactor command line utilities to share setup.
Hide internal gitosis-ssh and gitosis-gitweb, it's all in gitosis-run-hook.
-rw-r--r--gitosis/app.py73
-rw-r--r--gitosis/gitweb.py30
-rw-r--r--gitosis/init.py114
-rw-r--r--gitosis/run_hook.py90
-rw-r--r--gitosis/serve.py109
-rw-r--r--gitosis/ssh.py25
-rwxr-xr-xsetup.py8
7 files changed, 196 insertions, 253 deletions
diff --git a/gitosis/app.py b/gitosis/app.py
new file mode 100644
index 0000000..5ae796f
--- /dev/null
+++ b/gitosis/app.py
@@ -0,0 +1,73 @@
+import os
+import sys
+import logging
+import optparse
+import ConfigParser
+
+class App(object):
+ name = None
+
+ @classmethod
+ def run(class_):
+ app = class_()
+ return app.main()
+
+ def main(self):
+ parser = self.create_parser()
+ (options, args) = parser.parse_args()
+ cfg = self.read_config(options)
+ self.setup_logging(cfg)
+ self.handle_args(parser, cfg, options, args)
+
+ def create_parser(self):
+ parser = optparse.OptionParser()
+ parser.set_defaults(
+ config=os.path.expanduser('~/.gitosis.conf'),
+ )
+ parser.add_option('--config',
+ metavar='FILE',
+ help='read config from FILE',
+ )
+
+ return parser
+
+ def read_config(self, options):
+ cfg = ConfigParser.RawConfigParser()
+ try:
+ conffile = file(options.config)
+ except (IOError, OSError), e:
+ # I trust the exception has the path.
+ print >>sys.stderr, '%s: Unable to read config file: %s' \
+ % (options.get_prog_name(), e)
+ sys.exit(1)
+ try:
+ cfg.readfp(conffile)
+ finally:
+ conffile.close()
+ return cfg
+
+ def setup_logging(self, cfg):
+ logging.basicConfig()
+
+ try:
+ loglevel = cfg.get('gitosis', 'loglevel')
+ except (ConfigParser.NoSectionError,
+ ConfigParser.NoOptionError):
+ pass
+ else:
+ try:
+ symbolic = logging._levelNames[loglevel]
+ except KeyError:
+ # need to delay error reporting until we've called
+ # basicConfig
+ log = logging.getLogger('gitosis.app')
+ log.warning(
+ 'Ignored invalid loglevel configuration: %r',
+ loglevel,
+ )
+ else:
+ logging.root.setLevel(symbolic)
+
+ def handle_args(self, parser, options, args):
+ if args:
+ parser.error('not expecting arguments')
diff --git a/gitosis/gitweb.py b/gitosis/gitweb.py
index 69f6c7d..1682a05 100644
--- a/gitosis/gitweb.py
+++ b/gitosis/gitweb.py
@@ -27,7 +27,7 @@ To plug this into ``gitweb``, you have two choices.
import os, urllib, logging
-from ConfigParser import RawConfigParser, NoSectionError, NoOptionError
+from ConfigParser import NoSectionError, NoOptionError
from gitosis import util
@@ -113,31 +113,3 @@ def generate(config, path):
f.close()
os.rename(tmp, path)
-
-def _getParser():
- import optparse
- parser = optparse.OptionParser(
- usage="%prog [--config=FILE] PROJECTSLIST")
- parser.set_defaults(
- config=os.path.expanduser('~/.gitosis.conf'),
- )
- parser.add_option('--config',
- metavar='FILE',
- help='read config from FILE (default %s)'
- % parser.defaults['config'],
- )
- return parser
-
-def main():
- parser = _getParser()
- (options, args) = parser.parse_args()
-
- if len(args) != 1:
- parser.error('Expected one command line argument.')
-
- path, = args
-
- cfg = RawConfigParser()
- cfg.read(options.config)
-
- generate(config=cfg, path=path)
diff --git a/gitosis/init.py b/gitosis/init.py
index bf0eb9b..ba2e4c6 100644
--- a/gitosis/init.py
+++ b/gitosis/init.py
@@ -4,7 +4,6 @@ Initialize a user account for use with gitosis.
import errno
import logging
-import optparse
import os
import re
import subprocess
@@ -16,13 +15,10 @@ from ConfigParser import RawConfigParser
from gitosis import repository
from gitosis import util
+from gitosis import app
log = logging.getLogger('gitosis.init')
-def die(msg):
- log.error(msg)
- sys.exit(1)
-
def read_ssh_pubkey(fp=None):
if fp is None:
fp = sys.stdin
@@ -55,6 +51,12 @@ def initial_commit(git_dir, cfg, pubkey, user):
],
)
+class PostUpdateFailedError(Exception):
+ """post-update hook failed"""
+
+ def __str__(self):
+ return '%s: %s' % (self.__doc__, ': '.join(self.args))
+
def run_post_update(git_dir):
args = [os.path.join(git_dir, 'hooks', 'post-update')]
returncode = subprocess.call(
@@ -64,10 +66,7 @@ def run_post_update(git_dir):
env=dict(GIT_DIR='.'),
)
if returncode != 0:
- die(
- ("post-update returned non-zero exit status %d"
- % returncode),
- )
+ raise PostUpdateFailedError('exit status %d' % returncode)
def symlink_config(git_dir):
dst = os.path.expanduser('~/.gitosis.conf')
@@ -85,20 +84,6 @@ def symlink_config(git_dir):
)
os.rename(tmp, dst)
-def getParser():
- parser = optparse.OptionParser(
- usage='%prog',
- description='Initialize a user account for use with gitosis',
- )
- parser.set_defaults(
- config=os.path.expanduser('~/.gitosis.conf'),
- )
- parser.add_option('--config',
- metavar='FILE',
- help='read config from FILE',
- )
- return parser
-
def init_admin_repository(
git_dir,
pubkey,
@@ -130,49 +115,42 @@ def init_admin_repository(
user=user,
)
-def main():
- logging.basicConfig(level=logging.INFO)
- os.umask(0022)
-
- parser = getParser()
- (options, args) = parser.parse_args()
- if args:
- parser.error('Did not expect arguments.')
-
- cfg = RawConfigParser()
- try:
- conffile = file(options.config)
- except (IOError, OSError), e:
- if e.errno == errno.ENOENT:
- # not existing is ok
- pass
- else:
- # I trust the exception has the path.
- die("Unable to read config file: %s." % e)
- else:
+class Main(app.App):
+ def create_parser(self):
+ parser = super(Main, self).create_parser()
+ parser.set_usage('%prog [OPTS]')
+ parser.set_description(
+ 'Initialize a user account for use with gitosis')
+ return parser
+
+ def handle_args(self, parser, cfg, options, args):
+ super(Main, self).handle_args(parser, cfg, options, args)
+
+ logging.basicConfig(level=logging.INFO)
+ os.umask(0022)
+
+ log.info('Reading SSH public key...')
+ pubkey = read_ssh_pubkey()
+ user = ssh_extract_user(pubkey)
+ 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 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,
+ )
+ log.info('Running post-update hook...')
try:
- cfg.readfp(conffile)
- finally:
- conffile.close()
-
-
- log.info('Reading SSH public key...')
- pubkey = read_ssh_pubkey()
- user = ssh_extract_user(pubkey)
- if user is None:
- die('Cannot parse user from SSH public key.')
- log.info('Admin user is %r', user)
- 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,
- )
- log.info('Running post-update hook...')
- run_post_update(git_dir=admin_repository)
- log.info('Symlinking ~/.gitosis.conf to repository...')
- symlink_config(git_dir=admin_repository)
- log.info('Done.')
+ run_post_update(git_dir=admin_repository)
+ except PostUpdateFailedError, e:
+ log.error('%s', e)
+ sys.exit(1)
+ log.info('Symlinking ~/.gitosis.conf to repository...')
+ symlink_config(git_dir=admin_repository)
+ log.info('Done.')
diff --git a/gitosis/run_hook.py b/gitosis/run_hook.py
index 2bc4aaa..de5076e 100644
--- a/gitosis/run_hook.py
+++ b/gitosis/run_hook.py
@@ -4,36 +4,14 @@ Perform gitosis actions for a git hook.
import errno
import logging
-import optparse
import os
import sys
import shutil
-from ConfigParser import RawConfigParser
-
from gitosis import repository
from gitosis import ssh
from gitosis import gitweb
-
-log = logging.getLogger('gitosis.run_hook')
-
-def die(msg):
- log.error(msg)
- sys.exit(1)
-
-def getParser():
- parser = optparse.OptionParser(
- usage='%prog HOOK',
- description='Perform gitosis actions for a git hook',
- )
- parser.set_defaults(
- config=os.path.expanduser('~/.gitosis.conf'),
- )
- parser.add_option('--config',
- metavar='FILE',
- help='read config from FILE',
- )
- return parser
+from gitosis import app
def post_update(cfg):
try:
@@ -51,43 +29,33 @@ def post_update(cfg):
keydir='gitosis-export/keydir',
)
-def main():
- logging.basicConfig(level=logging.INFO)
- os.umask(0022)
-
- parser = getParser()
- (options, args) = parser.parse_args()
- try:
- (hook,) = args
- except ValueError:
- parser.error('Missing argument HOOK.')
+class Main(app.App):
+ def create_parser(self):
+ parser = super(Main, self).create_parser()
+ parser.set_usage('%prog [OPTS] HOOK')
+ parser.set_description(
+ 'Perform gitosis actions for a git hook')
+ return parser
- cfg = RawConfigParser()
- try:
- conffile = file(options.config)
- except (IOError, OSError), e:
- if e.errno == errno.ENOENT:
- # not existing is ok
- pass
- else:
- # I trust the exception has the path.
- die("Unable to read config file: %s." % e)
- else:
+ def handle_args(self, parser, cfg, options, args):
try:
- cfg.readfp(conffile)
- finally:
- conffile.close()
-
- git_dir = os.environ.get('GIT_DIR')
- if git_dir is None:
- die('Must have GIT_DIR set in enviroment.')
- os.chdir(git_dir)
- os.environ['GIT_DIR'] = '.'
-
- if hook == 'post-update':
- log.info('Running hook %s', hook)
- post_update(cfg)
- log.info('Done.')
- else:
- log.warning('Ignoring unknown hook: %r', hook)
- return 0
+ (hook,) = args
+ except ValueError:
+ parser.error('Missing argument HOOK.')
+
+ log = logging.getLogger('gitosis.run_hook')
+ os.umask(0022)
+
+ git_dir = os.environ.get('GIT_DIR')
+ if git_dir is None:
+ log.error('Must have GIT_DIR set in enviroment')
+ sys.exit(1)
+ os.chdir(git_dir)
+ os.environ['GIT_DIR'] = '.'
+
+ if hook == 'post-update':
+ log.info('Running hook %s', hook)
+ post_update(cfg)
+ log.info('Done.')
+ else:
+ log.warning('Ignoring unknown hook: %r', hook)
diff --git a/gitosis/serve.py b/gitosis/serve.py
index f47fe23..4b7c6a7 100644
--- a/gitosis/serve.py
+++ b/gitosis/serve.py
@@ -6,29 +6,11 @@ prefix. Repository names are forced to match ALLOW_RE.
import logging
-import sys, os, optparse, re
-from ConfigParser import RawConfigParser
+import sys, os, re
from gitosis import access
from gitosis import repository
-
-def die(msg):
- print >>sys.stderr, '%s: %s' % (sys.argv[0], msg)
- sys.exit(1)
-
-def getParser():
- parser = optparse.OptionParser(
- usage='%prog [--config=FILE] USER',
- description='Allow restricted git operations under DIR',
- )
- parser.set_defaults(
- config=os.path.expanduser('~/.gitosis.conf'),
- )
- parser.add_option('--config',
- metavar='FILE',
- help='read config from FILE',
- )
- return parser
+from gitosis import app
ALLOW_RE = re.compile("^'(?P<path>[a-zA-Z0-9][a-zA-Z0-9@._-]*(/[a-zA-Z0-9][a-zA-Z0-9@._-]*)*)'$")
@@ -124,48 +106,45 @@ def serve(
)
return newcmd
-def main():
- logging.basicConfig(level=logging.DEBUG)
- log = logging.getLogger('gitosis.serve.main')
- os.umask(0022)
-
- parser = getParser()
- (options, args) = parser.parse_args()
- try:
- (user,) = args
- except ValueError:
- parser.error('Missing argument USER.')
-
- cmd = os.environ.get('SSH_ORIGINAL_COMMAND', None)
- if cmd is None:
- die("Need SSH_ORIGINAL_COMMAND in environment.")
-
- log.debug('Got command %(cmd)r' % dict(
- cmd=cmd,
- ))
-
- cfg = RawConfigParser()
- try:
- conffile = file(options.config)
- except (IOError, OSError), e:
- # I trust the exception has the path.
- die("Unable to read config file: %s." % e)
- try:
- cfg.readfp(conffile)
- finally:
- conffile.close()
-
- os.chdir(os.path.expanduser('~'))
-
- try:
- newcmd = serve(
- cfg=cfg,
- user=user,
- command=cmd,
- )
- except ServingError, e:
- die(str(e))
-
- log.debug('Serving %s', newcmd)
- os.execvpe('git-shell', ['git-shell', '-c', newcmd], {})
- die("Cannot execute git-shell.")
+class Main(app.App):
+ def create_parser(self):
+ parser = super(Main, self).create_parser()
+ parser.set_usage('%prog [OPTS] USER')
+ parser.set_description(
+ 'Allow restricted git operations under DIR')
+ return parser
+
+ def handle_args(self, parser, cfg, options, args):
+ try:
+ (user,) = args
+ except ValueError:
+ parser.error('Missing argument USER.')
+
+ log = logging.getLogger('gitosis.serve.main')
+ os.umask(0022)
+
+ cmd = os.environ.get('SSH_ORIGINAL_COMMAND', None)
+ if cmd is None:
+ log.error('Need SSH_ORIGINAL_COMMAND in environment.')
+ sys.exit(1)
+
+ log.debug('Got command %(cmd)r' % dict(
+ cmd=cmd,
+ ))
+
+ os.chdir(os.path.expanduser('~'))
+
+ try:
+ newcmd = serve(
+ cfg=cfg,
+ user=user,
+ command=cmd,
+ )
+ except ServingError, e:
+ log.error('%s', e)
+ sys.exit(1)
+
+ log.debug('Serving %s', newcmd)
+ os.execvpe('git-shell', ['git-shell', '-c', newcmd], {})
+ log.error('Cannot execute git-shell.')
+ sys.exit(1)
diff --git a/gitosis/ssh.py b/gitosis/ssh.py
index 21f351a..7a70ed4 100644
--- a/gitosis/ssh.py
+++ b/gitosis/ssh.py
@@ -77,28 +77,3 @@ def writeAuthorizedKeys(path, keydir):
if in_ is not None:
in_.close()
os.rename(tmp, path)
-
-def _getParser():
- import optparse
- parser = optparse.OptionParser(
- usage="%prog [--authkeys=FILE] KEYDIR")
- parser.set_defaults(
- authkeys=os.path.expanduser('~/.ssh/authorized_keys'),
- )
- parser.add_option(
- "--authkeys",
- help="path to SSH authorized keys file")
- return parser
-
-def main():
- parser = _getParser()
- (options, args) = parser.parse_args()
-
- if len(args) != 1:
- parser.error('Need one argument on the command line.')
-
- keydir, = args
-
- writeAuthorizedKeys(
- path=options.authkeys,
- keydir=keydir)
diff --git a/setup.py b/setup.py
index 50d1a6d..dd24285 100755
--- a/setup.py
+++ b/setup.py
@@ -30,11 +30,9 @@ setup(
entry_points = {
'console_scripts': [
- 'gitosis-ssh = gitosis.ssh:main',
- 'gitosis-serve = gitosis.serve:main',
- 'gitosis-gitweb = gitosis.gitweb:main',
- 'gitosis-run-hook = gitosis.run_hook:main',
- 'gitosis-init = gitosis.init:main',
+ 'gitosis-serve = gitosis.serve:Main.run',
+ 'gitosis-run-hook = gitosis.run_hook:Main.run',
+ 'gitosis-init = gitosis.init:Main.run',
],
},