diff options
author | Mike Crute <mcrute@gmail.com> | 2010-04-20 23:02:42 -0400 |
---|---|---|
committer | Mike Crute <mcrute@gmail.com> | 2010-04-20 23:02:42 -0400 |
commit | 5156d1d7635806a237bdf9857702068290fc6340 (patch) | |
tree | 0861c901c7d1e8b5f2003582f0460f0b2a713e9c | |
download | obalie-5156d1d7635806a237bdf9857702068290fc6340.tar.bz2 obalie-5156d1d7635806a237bdf9857702068290fc6340.tar.xz obalie-5156d1d7635806a237bdf9857702068290fc6340.zip |
First pass at the basic client
-rw-r--r-- | .hgignore | 2 | ||||
-rw-r--r-- | obalie/__init__.py | 0 | ||||
-rw-r--r-- | obalie/client.py | 92 | ||||
-rw-r--r-- | obalie/commands/__init__.py | 0 | ||||
-rw-r--r-- | obalie/exceptions.py | 27 | ||||
-rw-r--r-- | obalie/log.py | 44 | ||||
-rw-r--r-- | obalie/utils.py | 32 |
7 files changed, 197 insertions, 0 deletions
diff --git a/.hgignore b/.hgignore new file mode 100644 index 0000000..a26d142 --- /dev/null +++ b/.hgignore | |||
@@ -0,0 +1,2 @@ | |||
1 | syntax:glob | ||
2 | *.pyc | ||
diff --git a/obalie/__init__.py b/obalie/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/obalie/__init__.py | |||
diff --git a/obalie/client.py b/obalie/client.py new file mode 100644 index 0000000..d943bb8 --- /dev/null +++ b/obalie/client.py | |||
@@ -0,0 +1,92 @@ | |||
1 | # vim: set filencoding=utf8 | ||
2 | """ | ||
3 | Subversion Client | ||
4 | |||
5 | @author: Mike Crute (mcrute@ag.com) | ||
6 | @organization: SoftGroup Interactive, Inc. | ||
7 | @date: April 20, 2010 | ||
8 | """ | ||
9 | |||
10 | from urlparse import urlparse | ||
11 | from obalie.commands import load_commands | ||
12 | from obalie.exceptions import UnsupportedCommand | ||
13 | from obalie.log import inject_logger | ||
14 | from obalie.utils import run_command | ||
15 | |||
16 | |||
17 | class Client(object): | ||
18 | |||
19 | @inject_logger | ||
20 | def __init__(self, repo_url, trust_server=True, config_dir=None, | ||
21 | svn_command='svn', logger=None, **config): | ||
22 | self.logger = logger | ||
23 | self.command = svn_command | ||
24 | self.config_dir = config_dir | ||
25 | self.trust_server = trust_server | ||
26 | self.additional_config = config | ||
27 | self.verbosity = None | ||
28 | self.commands = {} | ||
29 | |||
30 | self._unpack_url(repo_url) | ||
31 | |||
32 | def __getattr__(self, name): | ||
33 | """ | ||
34 | Proxy commands through to a command object. | ||
35 | """ | ||
36 | if not self.commands: | ||
37 | self.commands = load_commands() | ||
38 | |||
39 | try: | ||
40 | cmd = self.commands[name](self) | ||
41 | return cmd | ||
42 | except KeyError: | ||
43 | raise UnsupportedCommand(name) | ||
44 | |||
45 | def _unpack_url(self, url): | ||
46 | """ | ||
47 | Parses a repository URL and loads its parts into the instance. | ||
48 | """ | ||
49 | parsed = urlparse(url) | ||
50 | |||
51 | self.repo_url = "{0}://{1}".format(parsed.scheme, parsed.hostname) | ||
52 | if parsed.port: | ||
53 | self.repo_url += ":{0}".format(parsed.port) | ||
54 | self.repo_url += parsed.path | ||
55 | |||
56 | self.logger.debug('Repository URL: %r', self.repo_url) | ||
57 | |||
58 | self.username = parsed.username | ||
59 | self.password = parsed.password | ||
60 | |||
61 | def _get_svn_args(self): | ||
62 | """ | ||
63 | Gets a string of global options for the subversion command. | ||
64 | """ | ||
65 | args = [] | ||
66 | if self.username: | ||
67 | args.append('--username={0}'.format(self.username)) | ||
68 | |||
69 | if self.password: | ||
70 | args.append('--password={0}'.format(self.password)) | ||
71 | args.append('--no-auth-cache') | ||
72 | |||
73 | if self.config_dir: | ||
74 | args.append('--config-dir={0}'.format(self.config_dir)) | ||
75 | |||
76 | if self.trust_server: | ||
77 | args.append('--trust-server-cert') | ||
78 | args.append('--non-interactive') | ||
79 | |||
80 | for key, value in self.additional_config.items(): | ||
81 | option = '{0}={1}'.format(key, value) | ||
82 | args.append('--config-option={0}'.format(option)) | ||
83 | |||
84 | return ' '.join(args) | ||
85 | |||
86 | def run_raw_command(self, subcommand, *args): | ||
87 | command = [self.command, self._get_svn_args(), subcommand] | ||
88 | command = ' '.join(command + list(args)) | ||
89 | |||
90 | self.logger.debug("Command: %r", command) | ||
91 | |||
92 | return run_command(command) | ||
diff --git a/obalie/commands/__init__.py b/obalie/commands/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/obalie/commands/__init__.py | |||
diff --git a/obalie/exceptions.py b/obalie/exceptions.py new file mode 100644 index 0000000..c7cbb4d --- /dev/null +++ b/obalie/exceptions.py | |||
@@ -0,0 +1,27 @@ | |||
1 | # vim: set filencoding=utf8 | ||
2 | """ | ||
3 | Subversion Client Exceptions | ||
4 | |||
5 | @author: Mike Crute (mcrute@ag.com) | ||
6 | @organization: SoftGroup Interactive, Inc. | ||
7 | @date: April 20, 2010 | ||
8 | """ | ||
9 | |||
10 | |||
11 | class SubversionError(Exception): | ||
12 | pass | ||
13 | |||
14 | |||
15 | class ExecutableError(SubversionError): | ||
16 | |||
17 | def __init__(self, return_code, command): | ||
18 | self.return_code = return_code | ||
19 | self.command = command | ||
20 | |||
21 | def __str__(self): | ||
22 | return "Command {0!r} returned with non-zero status: {1}".format( | ||
23 | self.command, self.return_code) | ||
24 | |||
25 | |||
26 | class UnsupportedCommand(SubversionError): | ||
27 | pass | ||
diff --git a/obalie/log.py b/obalie/log.py new file mode 100644 index 0000000..bf65996 --- /dev/null +++ b/obalie/log.py | |||
@@ -0,0 +1,44 @@ | |||
1 | # vim: set filencoding=utf8 | ||
2 | """ | ||
3 | Logging Utlities for obalie | ||
4 | |||
5 | @author: Mike Crute (mcrute@ag.com) | ||
6 | @organization: SoftGroup Interactive, Inc. | ||
7 | @date: April 20, 2010 | ||
8 | """ | ||
9 | |||
10 | |||
11 | import sys | ||
12 | import logging | ||
13 | from logging import Formatter, StreamHandler | ||
14 | from functools import wraps | ||
15 | |||
16 | |||
17 | # Setup root logger | ||
18 | root_logger = logging.getLogger('obalie') | ||
19 | |||
20 | # If the root logger is not already configured then we | ||
21 | # should probably configure it with some sane defaults. | ||
22 | if root_logger.level == logging.NOTSET: | ||
23 | # XXX: RESET THIS! | ||
24 | # root_logger.setLevel(logging.WARN) | ||
25 | root_logger.setLevel(logging.DEBUG) | ||
26 | |||
27 | handler = StreamHandler(sys.stdout) | ||
28 | formatter = Formatter('%(asctime)s %(levelname)s %(name)s %(message)s') | ||
29 | |||
30 | handler.setFormatter(formatter) | ||
31 | root_logger.addHandler(handler) | ||
32 | |||
33 | |||
34 | def inject_logger(cls): | ||
35 | """ | ||
36 | Injects a logger into the kwargs for a class. | ||
37 | """ | ||
38 | @wraps(cls) | ||
39 | def decorator(*args, **kwargs): | ||
40 | inst = args[0] # self | ||
41 | kwargs['logger'] = logging.getLogger('.'.join([inst.__module__, inst.__class__.__name__])) | ||
42 | cls(*args, **kwargs) | ||
43 | |||
44 | return decorator | ||
diff --git a/obalie/utils.py b/obalie/utils.py new file mode 100644 index 0000000..dcf476a --- /dev/null +++ b/obalie/utils.py | |||
@@ -0,0 +1,32 @@ | |||
1 | # vim: set filencoding=utf8 | ||
2 | """ | ||
3 | Miscellaneous Utility Commands | ||
4 | |||
5 | @author: Mike Crute (mcrute@ag.com) | ||
6 | @organization: SoftGroup Interactive, Inc. | ||
7 | @date: April 20, 2010 | ||
8 | """ | ||
9 | |||
10 | |||
11 | import shlex | ||
12 | from subprocess import Popen, PIPE | ||
13 | from obalie.exceptions import ExecutableError | ||
14 | |||
15 | |||
16 | def run_command(command, raw_output=False): | ||
17 | """ | ||
18 | Run a command string returning the output. Passing raw_output | ||
19 | will cause the function to return the raw stdout; otherwise | ||
20 | lines will be split. | ||
21 | """ | ||
22 | cmd = shlex.split(command.encode('ascii')) | ||
23 | proc = Popen(cmd, close_fds=False, stdout=PIPE, stderr=PIPE) | ||
24 | stdout, stderr = proc.communicate() | ||
25 | |||
26 | if proc.returncode != 0: | ||
27 | raise ExecutableError(proc.returncode, command) | ||
28 | |||
29 | if raw_output: | ||
30 | return stdout | ||
31 | else: | ||
32 | return stdout.splitlines(True) | ||