| 1 | #!/usr/bin/env python |
|---|
| 2 | """ |
|---|
| 3 | functionality for the setup of repositories; |
|---|
| 4 | this should really be more interface consuming |
|---|
| 5 | """ |
|---|
| 6 | |
|---|
| 7 | import os |
|---|
| 8 | import pkg_resources |
|---|
| 9 | import subprocess |
|---|
| 10 | |
|---|
| 11 | from paste.script.templates import var |
|---|
| 12 | |
|---|
| 13 | class RepositorySetupError(Exception): |
|---|
| 14 | """marker exception for errors occuring during repository setup""" |
|---|
| 15 | |
|---|
| 16 | class RepositorySetup(object): |
|---|
| 17 | """interface defining repository setup via TracLegos""" |
|---|
| 18 | |
|---|
| 19 | options = [] # variables needed for this repository |
|---|
| 20 | |
|---|
| 21 | def __init__(self): |
|---|
| 22 | self.name = self.__class__.__name__ |
|---|
| 23 | if not hasattr(self, 'description'): |
|---|
| 24 | self.description = self.__doc__ |
|---|
| 25 | |
|---|
| 26 | def options_fulfilled(self, vars): |
|---|
| 27 | """returns whether all of the options are provided in vars""" |
|---|
| 28 | return set([option.name for option in self.options]).issubset(vars) |
|---|
| 29 | |
|---|
| 30 | def enabled(self): |
|---|
| 31 | """ |
|---|
| 32 | is this type of repository capable of being created |
|---|
| 33 | on this computer? |
|---|
| 34 | """ |
|---|
| 35 | return False |
|---|
| 36 | |
|---|
| 37 | def config(self): |
|---|
| 38 | """return a dictionary of .ini options""" |
|---|
| 39 | return {} |
|---|
| 40 | |
|---|
| 41 | def setup(self, **vars): |
|---|
| 42 | """ |
|---|
| 43 | create the repository |
|---|
| 44 | """ |
|---|
| 45 | |
|---|
| 46 | class NoRepository(RepositorySetup): |
|---|
| 47 | """No repository""" |
|---|
| 48 | options = [] |
|---|
| 49 | |
|---|
| 50 | def enabled(self): |
|---|
| 51 | return True |
|---|
| 52 | |
|---|
| 53 | def __len__(self): |
|---|
| 54 | """test False""" |
|---|
| 55 | return 0 |
|---|
| 56 | |
|---|
| 57 | |
|---|
| 58 | class NewSVN(RepositorySetup): |
|---|
| 59 | """Create a new SVN repository""" |
|---|
| 60 | options = [ var('repository_dir', 'location to create the SVN repository')] |
|---|
| 61 | |
|---|
| 62 | def enabled(self): |
|---|
| 63 | try: |
|---|
| 64 | subprocess.call(['svnadmin', 'help'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
|---|
| 65 | return True |
|---|
| 66 | except OSError: |
|---|
| 67 | return False |
|---|
| 68 | |
|---|
| 69 | def config(self): |
|---|
| 70 | return { 'trac': { 'repository_dir': '${repository_dir}', |
|---|
| 71 | 'repository_type': 'svn' } } |
|---|
| 72 | |
|---|
| 73 | def setup(self, **vars): |
|---|
| 74 | if not self.options_fulfilled(vars): |
|---|
| 75 | raise RepositorySetupError("Missing directory") |
|---|
| 76 | subprocess.call(['svnadmin', 'create', vars['repository_dir']]) |
|---|
| 77 | |
|---|
| 78 | class ExistingSVN(RepositorySetup): |
|---|
| 79 | """Use an existing repository""" |
|---|
| 80 | options = [ var('repository_dir', 'location of SVN repository') ] |
|---|
| 81 | |
|---|
| 82 | def enabled(self): |
|---|
| 83 | return True |
|---|
| 84 | |
|---|
| 85 | def config(self): |
|---|
| 86 | return { 'trac': { 'repository_dir': '${repository_dir}', |
|---|
| 87 | 'repository_type': 'svn' } } |
|---|
| 88 | |
|---|
| 89 | class SVNSync(RepositorySetup): |
|---|
| 90 | """Mirror SVN (1.4) repository""" |
|---|
| 91 | options = [ var('repository_url', 'URL of remote svn repository (must be SVN v1.4)', |
|---|
| 92 | default='http://'), |
|---|
| 93 | var('repository_dir', 'desired mirror location') ] |
|---|
| 94 | |
|---|
| 95 | def enabled(self): |
|---|
| 96 | try: |
|---|
| 97 | import svnsyncplugin |
|---|
| 98 | except ImportError: |
|---|
| 99 | return False |
|---|
| 100 | return True |
|---|
| 101 | |
|---|
| 102 | def config(self): |
|---|
| 103 | return { 'svn': { 'repository_url': '${repository_url}', }, |
|---|
| 104 | 'trac': { 'repository_dir': '${repository_dir}', |
|---|
| 105 | 'repository_type': 'svnsync' } } |
|---|
| 106 | |
|---|
| 107 | def setup(self, **vars): |
|---|
| 108 | if not self.options_fulfilled(vars): |
|---|
| 109 | raise RepositorySetupError("Missing options") |
|---|
| 110 | raise NotImplementedError # TODO |
|---|
| 111 | |
|---|
| 112 | |
|---|
| 113 | class NewMercurialRepository(RepositorySetup): |
|---|
| 114 | """Create a new Mercurial repository""" |
|---|
| 115 | |
|---|
| 116 | options = [ var('hg_repository_dir', 'location to create Hg repository') ] |
|---|
| 117 | |
|---|
| 118 | def enabled(self): |
|---|
| 119 | try: |
|---|
| 120 | import tracext.hg |
|---|
| 121 | except ImportError: |
|---|
| 122 | return False |
|---|
| 123 | try: |
|---|
| 124 | import subprocess |
|---|
| 125 | retval = subprocess.call(["hg"], stdout=subprocess.PIPE) |
|---|
| 126 | return not retval |
|---|
| 127 | except: |
|---|
| 128 | return False |
|---|
| 129 | |
|---|
| 130 | def config(self): |
|---|
| 131 | return { 'components': { 'tracext.hg': 'enabled' }, |
|---|
| 132 | 'trac': { 'repository_dir': '${hg_repository_dir}', |
|---|
| 133 | 'repository_type': 'hg' } } |
|---|
| 134 | |
|---|
| 135 | |
|---|
| 136 | def available_repositories(): |
|---|
| 137 | """return installed and enabled repository setup methods""" |
|---|
| 138 | repositories = [] |
|---|
| 139 | for entry_point in pkg_resources.iter_entry_points('traclegos.respository'): |
|---|
| 140 | try: |
|---|
| 141 | repository = entry_point.load() |
|---|
| 142 | except: |
|---|
| 143 | continue |
|---|
| 144 | repository = repository() |
|---|
| 145 | if repository.enabled(): |
|---|
| 146 | repositories.append(repository) |
|---|
| 147 | return dict((repository.name, repository) for repository in repositories) |
|---|
| 148 | |
|---|
| 149 | |
|---|
| 150 | if __name__ == '__main__': |
|---|
| 151 | print 'Available repositories:' |
|---|
| 152 | for name, repository in available_repositories().items(): |
|---|
| 153 | print '%s: %s' % (name, repository.description) |
|---|