Ticket #8731: 8731-surrogate-keys-r8662.2.patch
| File 8731-surrogate-keys-r8662.2.patch, 35.0 KB (added by rblank, 3 years ago) |
|---|
-
trac/admin/tests/console-tests.txt
diff --git a/trac/admin/tests/console-tests.txt b/trac/admin/tests/console-tests.txt
a b 41 41 repository alias Create an alias for a repository 42 42 repository list List source repositories 43 43 repository remove Remove a source repository 44 repository rename Rename a source repository45 44 repository resync Re-synchronize trac with repositories 46 45 repository set Set an attribute of a repository 47 46 repository sync Resume synchronization of repositories -
trac/db_default.py
diff --git a/trac/db_default.py b/trac/db_default.py
a b 17 17 from trac.db import Table, Column, Index 18 18 19 19 # Database version identifier. Used for automatic upgrades. 20 db_version = 2 320 db_version = 24 21 21 22 22 def __mkreports(reports): 23 23 """Utility function used to create report data in same syntax as the … … 86 86 87 87 # Version control cache 88 88 Table('repository', key=('id', 'name'))[ 89 Column('id' ),89 Column('id', type='int'), 90 90 Column('name'), 91 91 Column('value')], 92 92 Table('revision', key=('repos', 'rev'))[ 93 Column('repos' ),93 Column('repos', type='int'), 94 94 Column('rev'), 95 95 Column('time', type='int'), 96 96 Column('author'), 97 97 Column('message'), 98 98 Index(['repos', 'time'])], 99 99 Table('node_change', key=('repos', 'rev', 'path', 'change_type'))[ 100 Column('repos' ),100 Column('repos', type='int'), 101 101 Column('rev'), 102 102 Column('path'), 103 103 Column('node_type', size=1), -
trac/env.py
diff --git a/trac/env.py b/trac/env.py
a b 451 451 def upgrade(self, backup=False, backup_dest=None): 452 452 """Upgrade database. 453 453 454 Each db version should have its own upgrade module, name s454 Each db version should have its own upgrade module, named 455 455 upgrades/dbN.py, where 'N' is the version number (int). 456 456 457 457 @param backup: whether or not to backup before upgrading -
new file trac/upgrades/db24.py
diff --git a/trac/upgrades/db24.py b/trac/upgrades/db24.py new file mode 100644
- + 1 from trac.db import Table, Column, Index, DatabaseManager 2 3 def do_upgrade(env, ver, cursor): 4 # Change repository key from reponame to a surrogate id 5 cursor.execute("SELECT id FROM repository " 6 "UNION SELECT repos AS id FROM revision " 7 "UNION SELECT repos AS id FROM node_change " 8 "ORDER BY id") 9 id_name_list = [(i + 1, name) for i, (name,) in enumerate(cursor)] 10 11 cursor.execute("CREATE TEMPORARY TABLE repo_old " 12 "AS SELECT * FROM repository") 13 cursor.execute("DROP TABLE repository") 14 cursor.execute("CREATE TEMPORARY TABLE rev_old " 15 "AS SELECT * FROM revision") 16 cursor.execute("DROP TABLE revision") 17 cursor.execute("CREATE TEMPORARY TABLE nc_old " 18 "AS SELECT * FROM node_change") 19 cursor.execute("DROP TABLE node_change") 20 21 tables = [Table('repository', key=('id', 'name'))[ 22 Column('id', type='int'), 23 Column('name'), 24 Column('value')], 25 Table('revision', key=('repos', 'rev'))[ 26 Column('repos', type='int'), 27 Column('rev'), 28 Column('time', type='int'), 29 Column('author'), 30 Column('message'), 31 Index(['repos', 'time'])], 32 Table('node_change', key=('repos', 'rev', 'path', 'change_type'))[ 33 Column('repos', type='int'), 34 Column('rev'), 35 Column('path'), 36 Column('node_type', size=1), 37 Column('change_type', size=1), 38 Column('base_path'), 39 Column('base_rev'), 40 Index(['repos', 'rev'])]] 41 42 db_connector, _ = DatabaseManager(env)._get_connector() 43 for table in tables: 44 for stmt in db_connector.to_sql(table): 45 cursor.execute(stmt) 46 47 cursor.executemany("INSERT INTO repository (id,name,value) " 48 "VALUES (%s,'name',%s)", id_name_list) 49 cursor.executemany("INSERT INTO repository (id,name,value) " 50 "SELECT %s,name,value FROM repo_old WHERE id=%s", 51 id_name_list) 52 cursor.execute("DROP TABLE repo_old") 53 cursor.executemany("INSERT INTO revision (repos,rev,time,author,message) " 54 "SELECT %s,rev,time,author,message FROM rev_old " 55 "WHERE repos=%s", id_name_list) 56 cursor.execute("DROP TABLE rev_old") 57 cursor.executemany("INSERT INTO node_change (repos,rev,path,node_type," 58 " change_type,base_path,base_rev) " 59 "SELECT %s,rev,path,node_type,change_type,base_path," 60 " base_rev FROM nc_old WHERE repos=%s", id_name_list) 61 cursor.execute("DROP TABLE nc_old") -
trac/versioncontrol/admin.py
diff --git a/trac/versioncontrol/admin.py b/trac/versioncontrol/admin.py
a b 121 121 return 122 122 repositories = [repos] 123 123 124 from trac.versioncontrol.cache import CACHE_METADATA_KEYS125 124 db = self.env.get_db_cnx() 126 125 cursor = db.cursor() 127 126 for repos in sorted(repositories, key=lambda r: r.reponame): 128 reponame = repos.reponame129 127 printout(_('Resyncing repository history for %(reponame)s... ', 130 reponame=reponame or '(default)')) 131 if clean: 132 cursor.execute("DELETE FROM revision WHERE repos=%s", 133 (reponame,)) 134 cursor.execute("DELETE FROM node_change " 135 "WHERE repos=%s", (reponame,)) 136 cursor.executemany("DELETE FROM repository " 137 "WHERE id=%s AND name=%s", 138 [(reponame, k) for k in CACHE_METADATA_KEYS]) 139 cursor.executemany("INSERT INTO repository (id, name, value) " 140 "VALUES (%s, %s, %s)", 141 [(reponame, k, '') 142 for k in CACHE_METADATA_KEYS]) 143 db.commit() 144 repos.sync(self._sync_feedback) 128 reponame=repos.reponame or '(default)')) 129 repos.sync(self._sync_feedback, clean=clean) 145 130 cursor.execute("SELECT count(rev) FROM revision WHERE repos=%s", 146 (repo name,))131 (repos.id,)) 147 132 for cnt, in cursor: 148 133 printout(ngettext('%(num)s revision cached.', 149 134 '%(num)s revisions cached.', num=cnt)) … … 187 172 188 173 elif db_provider and req.args.get('save'): 189 174 # Modify repository 190 changed = False191 175 changes = {} 192 176 for field in db_provider.repository_attrs: 193 177 value = normalize_whitespace(req.args.get(field)) … … 196 180 changes[field] = value 197 181 if changes: 198 182 db_provider.modify_repository(reponame, changes) 199 changed = True 200 # Rename repository 183 add_notice(req, _('Your changes have been saved.')) 201 184 name = req.args.get('name') 202 if name and name != path_info:203 db_provider.rename_repository(reponame, name)204 changed = True205 if changed:206 add_notice(req, _('Your changes have been saved.'))207 185 if 'dir' in changes: 208 186 msg = _('You should now run "trac-admin $ENV ' 209 187 'repository resync %(name)s" to synchronize ' -
trac/versioncontrol/api.py
diff --git a/trac/versioncontrol/api.py b/trac/versioncontrol/api.py
a b 96 96 97 97 implements(IRepositoryProvider, IAdminCommandProvider) 98 98 99 repository_attrs = ('alias', 'dir', 'hidden', ' type', 'url')99 repository_attrs = ('alias', 'dir', 'hidden', 'name', 'type', 'url') 100 100 101 101 # IRepositoryProvider methods 102 102 … … 107 107 cursor.execute("SELECT id,name,value FROM repository " 108 108 "WHERE name IN (%s)" % ",".join( 109 109 "'%s'" % each for each in self.repository_attrs)) 110 repos = {} 111 for id, name, value in cursor: 112 if value is not None: 113 repos.setdefault(id, {})[name] = value 110 114 reponames = {} 111 for (id, name, value) in cursor: 112 if value is not None: 113 reponames.setdefault(id, {})[name] = value 115 for id, info in repos.iteritems(): 116 if 'name' in info and ('dir' in info or 'alias' in info): 117 info['id'] = id 118 reponames[info['name']] = info 114 119 return reponames.iteritems() 115 120 116 121 # IAdminCommandProvider methods … … 125 130 yield ('repository remove', '<repos>', 126 131 'Remove a source repository', 127 132 self._complete_repos, self._do_remove) 128 yield ('repository rename', '<repos> <newname>',129 'Rename a source repository',130 self._complete_repos, self._do_rename)131 133 yield ('repository set', '<repos> <key> <value>', 132 134 """Set an attribute of a repository 133 135 … … 169 171 def _do_remove(self, reponame): 170 172 self.remove_repository(reponame) 171 173 172 def _do_rename(self, reponame, newname):173 self.rename_repository(reponame, newname)174 175 174 def _do_set(self, reponame, key, value): 176 175 if key not in self.repository_attrs: 177 176 raise AdminCommandError(_('Invalid key "%(key)s"', key=key)) … … 194 193 raise TracError(_("The repository type '%(type)s' is not " 195 194 "supported", type=type_)) 196 195 db = self.env.get_db_cnx() 196 id = rm.get_repository_id(reponame, db) 197 197 cursor = db.cursor() 198 198 cursor.executemany("INSERT INTO repository (id, name, value) " 199 199 "VALUES (%s, %s, %s)", 200 [( reponame, 'dir', dir),201 ( reponame, 'type', type_ or '')])200 [(id, 'dir', dir), 201 (id, 'type', type_ or '')]) 202 202 db.commit() 203 203 rm.reload_repositories() 204 204 … … 208 208 reponame = '' 209 209 if target == '(default)': 210 210 target = '' 211 rm = RepositoryManager(self.env) 211 212 db = self.env.get_db_cnx() 213 id = rm.get_repository_id(reponame, db) 212 214 cursor = db.cursor() 213 215 cursor.executemany("INSERT INTO repository (id, name, value) " 214 216 "VALUES (%s, %s, %s)", 215 [( reponame, 'dir', None),216 ( reponame, 'alias', target)])217 [(id, 'dir', None), 218 (id, 'alias', target)]) 217 219 db.commit() 218 RepositoryManager(self.env).reload_repositories()220 rm.reload_repositories() 219 221 220 222 def remove_repository(self, reponame): 221 223 """Remove a repository.""" 222 224 if reponame == '(default)': 223 225 reponame = '' 226 rm = RepositoryManager(self.env) 224 227 db = self.env.get_db_cnx() 228 id = rm.get_repository_id(reponame, db) 225 229 cursor = db.cursor() 226 cursor.execute("DELETE FROM repository WHERE id=%s", ( reponame,))227 cursor.execute("DELETE FROM revision WHERE repos=%s", ( reponame,))228 cursor.execute("DELETE FROM node_change WHERE repos=%s", ( reponame,))230 cursor.execute("DELETE FROM repository WHERE id=%s", (id,)) 231 cursor.execute("DELETE FROM revision WHERE repos=%s", (id,)) 232 cursor.execute("DELETE FROM node_change WHERE repos=%s", (id,)) 229 233 db.commit() 230 RepositoryManager(self.env).reload_repositories() 231 232 def rename_repository(self, reponame, newname): 233 """Rename a repository.""" 234 if reponame == '(default)': 235 reponame = '' 236 if newname == '(default)': 237 newname = '' 238 db = self.env.get_db_cnx() 239 cursor = db.cursor() 240 cursor.execute("UPDATE repository SET id=%s WHERE id=%s", 241 (newname, reponame)) 242 cursor.execute("UPDATE revision SET repos=%s WHERE repos=%s", 243 (newname, reponame)) 244 cursor.execute("UPDATE node_change SET repos=%s WHERE repos=%s", 245 (newname, reponame)) 246 db.commit() 247 RepositoryManager(self.env).reload_repositories() 234 rm.reload_repositories() 248 235 249 236 def modify_repository(self, reponame, changes): 250 237 """Modify attributes of a repository.""" 251 238 if reponame == '(default)': 252 239 reponame = '' 240 rm = RepositoryManager(self.env) 253 241 db = self.env.get_db_cnx() 242 id = rm.get_repository_id(reponame, db) 254 243 cursor = db.cursor() 255 244 for (k, v) in changes.iteritems(): 256 245 if k not in self.repository_attrs: 257 246 continue 258 if k == 'alias'and v == '(default)':247 if k in('alias', 'name') and v == '(default)': 259 248 v = '' 260 249 cursor.execute("UPDATE repository SET value=%s " 261 "WHERE id=%s AND name=%s", (v, reponame, k))250 "WHERE id=%s AND name=%s", (v, id, k)) 262 251 cursor.execute("SELECT value FROM repository " 263 "WHERE id=%s AND name=%s", ( reponame, k))252 "WHERE id=%s AND name=%s", (id, k)) 264 253 if not cursor.fetchone(): 265 cursor.execute("INSERT INTO repository VALUES (%s, %s, %s)",266 (reponame, k, v))254 cursor.execute("INSERT INTO repository (id, name, value) " 255 "VALUES (%s, %s, %s)", (id, k, v)) 267 256 db.commit() 268 RepositoryManager(self.env).reload_repositories()257 rm.reload_repositories() 269 258 270 259 271 260 class RepositoryManager(Component): … … 445 434 repositories.append(repos) 446 435 return repositories 447 436 437 def get_repository_id(self, reponame, db=None): 438 """Return a unique id for the given repository name.""" 439 handle_ta = False 440 if db is None: 441 db = self.env.get_db_cnx() 442 handle_ta = True 443 cursor = db.cursor() 444 cursor.execute("SELECT id FROM repository " 445 "WHERE name='name' AND value=%s", (reponame,)) 446 for id, in cursor: 447 return id 448 cursor.execute("SELECT COALESCE(MAX(id),0) FROM repository") 449 id = cursor.fetchone()[0] + 1 450 cursor.execute("INSERT INTO repository (id, name, value) " 451 "VALUES (%s,%s,%s)", (id, 'name', reponame)) 452 if handle_ta: 453 db.commit() 454 return id 455 448 456 def get_repository(self, reponame, authname): 449 457 """Retrieve the appropriate Repository for the given name. 450 458 … … 455 463 :return: if no corresponding repository was defined, 456 464 simply return `None`. 457 465 """ 466 reponame = reponame or '' 458 467 repoinfo = self.get_all_repositories().get(reponame, {}) 459 468 if repoinfo and 'alias' in repoinfo: 460 469 reponame = repoinfo['alias'] … … 488 497 rdir = os.path.join(self.env.path, rdir) 489 498 connector = self._get_connector(rtype) 490 499 repos = connector.get_repository(rtype, rdir, repoinfo) 491 repos.reponame = reponame492 500 repositories[reponame] = repos 493 501 return repos 494 502 finally: … … 538 546 self.log.warn("Discarding duplicate repository '%s'", 539 547 reponame) 540 548 else: 549 info['name'] = reponame 550 if 'id' not in info: 551 info['id'] = self.get_repository_id(reponame) 541 552 self._all_repositories[reponame] = info 542 553 return self._all_repositories 543 554 … … 668 679 class Repository(object): 669 680 """Base class for a repository provided by a version control system.""" 670 681 671 def __init__(self, name, authz, log): 682 def __init__(self, reponame, id, name, authz, log): 683 self.reponame = reponame 684 self.id = id 672 685 self.name = name 673 686 self.authz = authz or Authorizer() 674 687 self.log = log 675 self.reponame = name # overriden by the reponame key used to create it676 688 677 689 def close(self): 678 690 """Close the connection to the repository.""" … … 695 707 """ 696 708 pass 697 709 698 def sync(self, rev_callback=None ):710 def sync(self, rev_callback=None, clean=False): 699 711 """Perform a sync of the repository cache, if relevant. 700 712 701 713 If given, `rev_callback` must be a callable taking a `rev` parameter. 702 714 The backend will call this function for each `rev` it decided to 703 715 synchronize, once the synchronization changes are committed to the 704 cache. 716 cache. When `clean` is `True`, the cache is cleaned first. 705 717 """ 706 718 pass 707 719 -
trac/versioncontrol/cache.py
diff --git a/trac/versioncontrol/cache.py b/trac/versioncontrol/cache.py
a b 48 48 self.repos = repos 49 49 self.metadata = CacheProxy(self.__class__.__module__ + '.' 50 50 + self.__class__.__name__ + '.metadata:' 51 + s elf.repos.reponame, self._metadata,51 + str(self.repos.id), self._metadata, 52 52 self.env) 53 Repository.__init__(self, repos.name, authz, log) 53 Repository.__init__(self, repos.reponame, repos.id, repos.name, authz, 54 log) 54 55 55 def _set_reponame(self, value):56 self.repos.reponame = value57 self.metadata.id = self.__class__.__module__ + '.' \58 + self.__class__.__name__ + '.metadata:' \59 + value60 61 reponame = property(fget=lambda self: self.repos.reponame,62 fset=_set_reponame)63 64 56 def close(self): 65 57 self.repos.close() 66 58 … … 86 78 cursor.execute("SELECT rev FROM revision " 87 79 "WHERE repos=%s AND time >= %s AND time < %s " 88 80 "ORDER BY time DESC, rev DESC", 89 (self. reponame, to_timestamp(start),81 (self.id, to_timestamp(start), 90 82 to_timestamp(stop))) 91 83 for rev, in cursor: 92 84 try: … … 101 93 cursor = db.cursor() 102 94 cursor.execute("SELECT time,author,message FROM revision " 103 95 "WHERE repos=%s AND rev=%s", 104 (self. reponame, str(cset.rev)))96 (self.id, str(cset.rev))) 105 97 old_changeset = None 106 98 for time, author, message in cursor: 107 99 date = datetime.fromtimestamp(time, utc) … … 110 102 cursor.execute("UPDATE revision SET time=%s, author=%s, message=%s " 111 103 "WHERE repos=%s AND rev=%s", 112 104 (to_timestamp(cset.date), cset.author, cset.message, 113 self. reponame, str(cset.rev)))105 self.id, str(cset.rev))) 114 106 db.commit() 115 107 return old_changeset 116 108 … … 120 112 cursor.execute("SELECT name, value FROM repository " 121 113 "WHERE id=%%s AND name IN (%s)" % 122 114 ','.join(['%s'] * len(CACHE_METADATA_KEYS)), 123 (self. reponame,) + CACHE_METADATA_KEYS)115 (self.id,) + CACHE_METADATA_KEYS) 124 116 return dict(cursor) 125 117 126 def sync(self, feedback=None ):118 def sync(self, feedback=None, clean=False): 127 119 db = self.env.get_db_cnx() 128 120 cursor = db.cursor() 121 if clean: 122 self.log.info('Cleaning cache') 123 cursor.execute("DELETE FROM revision WHERE repos=%s", (self.id,)) 124 cursor.execute("DELETE FROM node_change WHERE repos=%s", 125 (self.id,)) 126 cursor.executemany("DELETE FROM repository " 127 "WHERE id=%s AND name=%s", 128 [(self.id, k) for k in CACHE_METADATA_KEYS]) 129 cursor.executemany("INSERT INTO repository (id, name, value) " 130 "VALUES (%s, %s, %s)", 131 [(self.id, k, '') for k in CACHE_METADATA_KEYS]) 132 self.metadata.invalidate(db) 133 db.commit() 134 129 135 metadata = self.metadata.get(db) 130 136 do_commit = False 131 137 … … 143 149 self.log.info('Storing initial "repository_dir": %s' % self.name) 144 150 cursor.execute("INSERT INTO repository (id,name,value) " 145 151 "VALUES (%s,%s,%s)", 146 (self. reponame, CACHE_REPOSITORY_DIR, self.name))152 (self.id, CACHE_REPOSITORY_DIR, self.name)) 147 153 do_commit = True 148 154 else: # 'repository_dir' cleared by a resync 149 155 self.log.info('Resetting "repository_dir": %s' % self.name) 150 156 cursor.execute("UPDATE repository SET value=%s " 151 157 "WHERE id=%s AND name=%s", 152 (self.name, self. reponame, CACHE_REPOSITORY_DIR))158 (self.name, self.id, CACHE_REPOSITORY_DIR)) 153 159 do_commit = True 154 160 155 161 # -- retrieve the youngest revision in the repository … … 161 167 if youngest is None: 162 168 cursor.execute("INSERT INTO repository (id,name,value) " 163 169 "VALUES (%s,%s,%s)", 164 (self. reponame, CACHE_YOUNGEST_REV, ''))170 (self.id, CACHE_YOUNGEST_REV, '')) 165 171 do_commit = True 166 172 167 173 if do_commit: … … 205 211 # 0. first check if there's no (obvious) resync in progress 206 212 cursor.execute("SELECT rev FROM revision " 207 213 "WHERE repos=%s AND rev=%s", 208 (self. reponame, str(next_youngest)))214 (self.id, str(next_youngest))) 209 215 for rev, in cursor: 210 216 # already there, but in progress, so keep ''previous'' 211 217 # notion of 'youngest' … … 232 238 cursor.execute("INSERT INTO revision " 233 239 " (repos,rev,time,author,message) " 234 240 "VALUES (%s,%s,%s,%s,%s)", 235 (self. reponame, str(next_youngest),241 (self.id, str(next_youngest), 236 242 to_timestamp(cset.date), 237 243 cset.author, cset.message)) 238 244 except Exception, e: # *another* 1.1. resync attempt won … … 257 263 " (repos,rev,path,node_type," 258 264 " change_type,base_path,base_rev) " 259 265 "VALUES (%s,%s,%s,%s,%s,%s,%s)", 260 (self. reponame, str(next_youngest),266 (self.id, str(next_youngest), 261 267 path, kind, action, bpath, brev)) 262 268 263 269 # 1.3. iterate (1.1 should always succeed now) … … 268 274 # (minimize possibility of failures at point 0.) 269 275 cursor.execute("UPDATE repository SET value=%s " 270 276 "WHERE id=%s AND name=%s", 271 (str(youngest), self. reponame,277 (str(youngest), self.id, 272 278 CACHE_YOUNGEST_REV)) 273 279 self.metadata.invalidate(db) 274 280 db.commit() … … 336 342 # the changeset revs are sequence of ints: 337 343 sql = "SELECT rev FROM node_change WHERE repos=%s AND " + \ 338 344 db.cast('rev', 'int') + " " + direction + " %s" 339 args = [self. reponame, rev]345 args = [self.id, rev] 340 346 341 347 if path: 342 348 path = path.lstrip('/') … … 406 412 cursor = db.cursor() 407 413 cursor.execute("SELECT time,author,message FROM revision " 408 414 "WHERE repos=%s AND rev=%s", 409 (self.repos. reponame, str(rev)))415 (self.repos.id, str(rev))) 410 416 row = cursor.fetchone() 411 417 if row: 412 418 _date, author, message = row … … 421 427 cursor = db.cursor() 422 428 cursor.execute("SELECT path,node_type,change_type,base_path,base_rev " 423 429 "FROM node_change WHERE repos=%s AND rev=%s " 424 "ORDER BY path", (self.repos. reponame, str(self.rev)))430 "ORDER BY path", (self.repos.id, str(self.rev))) 425 431 for path, kind, change, base_path, base_rev in cursor: 426 432 if not self.authz.has_permission(posixpath.join(self.scope, 427 433 path.strip('/'))): -
trac/versioncontrol/svn_fs.py
diff --git a/trac/versioncontrol/svn_fs.py b/trac/versioncontrol/svn_fs.py
a b 278 278 if not self._version: 279 279 self._version = self._get_version() 280 280 self.env.systeminfo.append(('Subversion', self._version)) 281 fs_repos = SubversionRepository(dir, None, self.log, 281 fs_repos = SubversionRepository(options['name'], options['id'], 282 dir, None, self.log, 282 283 {'tags': self.tags, 283 284 'branches': self.branches, 284 285 'url': options.get('url') or ''}) … … 306 307 class SubversionRepository(Repository): 307 308 """Repository implementation based on the svn.fs API.""" 308 309 309 def __init__(self, path, authz, log, options={}):310 def __init__(self, reponame, id, path, authz, log, options={}): 310 311 self.log = log 311 312 self.options = options 312 313 self.pool = Pool() … … 337 338 self.base = 'svn:%s:%s' % (self.uuid, _from_svn(root_path_utf8)) 338 339 name = 'svn:%s:%s' % (self.uuid, self.path) 339 340 340 Repository.__init__(self, name, authz, log)341 Repository.__init__(self, reponame, id, name, authz, log) 341 342 342 343 # if root_path_utf8 is shorter than the path_utf8, the difference is 343 344 # this scope (which always starts with a '/') -
trac/versioncontrol/templates/admin_repositories.html
diff --git a/trac/versioncontrol/templates/admin_repositories.html b/trac/versioncontrol/templates/admin_repositories.html
a b 91 91 </fieldset> 92 92 </form> 93 93 94 <form class="addnew" id="trac-addalias" method="post" action=""> 94 <form py:if="any(not info.alias for info in repositories.itervalues())" 95 class="addnew" id="trac-addalias" method="post" action=""> 95 96 <fieldset> 96 97 <legend>Add Alias:</legend> 97 98 <div class="field"> -
trac/versioncontrol/tests/api.py
diff --git a/trac/versioncontrol/tests/api.py b/trac/versioncontrol/tests/api.py
a b 21 21 class ApiTestCase(unittest.TestCase): 22 22 23 23 def setUp(self): 24 self.repo_base = Repository('testrepo', None, None)24 self.repo_base = Repository('testrepo', 1, 'testrepo', None, None) 25 25 26 26 def test_raise_NotImplementedError_close(self): 27 27 self.failUnlessRaises(NotImplementedError, self.repo_base.close) -
trac/versioncontrol/tests/cache.py
diff --git a/trac/versioncontrol/tests/cache.py b/trac/versioncontrol/tests/cache.py
a b 33 33 self.db = self.env.get_db_cnx() 34 34 self.log = self.env.log 35 35 cursor = self.db.cursor() 36 cursor.execute("INSERT INTO repository (id, name, value) " 37 "VALUES (%s,%s,%s)", 38 ('test-repos', 'youngest_rev', '')) 36 cursor.executemany("INSERT INTO repository (id,name,value) " 37 "VALUES (%s,%s,%s)", 38 [(1, 'name', 'test-repos'), 39 (1, 'youngest_rev', '')]) 39 40 40 41 def tearDown(self): 41 42 self.env.reset_db() … … 45 46 def no_changeset(rev): 46 47 raise NoSuchChangeset(rev) 47 48 48 repos = Mock(Repository, 'test-repos', None, self.log,49 repos = Mock(Repository, 'test-repos', 1, 'test-repos', None, self.log, 49 50 get_changeset=no_changeset, 50 51 get_oldest_rev=lambda: 1, 51 52 get_youngest_rev=lambda: 0, … … 69 70 get_changes=lambda: []), 70 71 Mock(Changeset, 1, 'Import', 'joe', t2, 71 72 get_changes=lambda: iter(changes))] 72 repos = Mock(Repository, 'test-repos', None, self.log,73 repos = Mock(Repository, 'test-repos', 1, 'test-repos', None, self.log, 73 74 get_changeset=lambda x: changesets[int(x)], 74 75 get_oldest_rev=lambda: 0, 75 76 get_youngest_rev=lambda: 1, … … 97 98 t3 = datetime(2003, 1, 1, 1, 1, 1, 0, utc) 98 99 cursor = self.db.cursor() 99 100 cursor.execute("INSERT INTO revision (repos,rev,time,author,message) " 100 "VALUES ( 'test-repos',0,%s,'','')",101 "VALUES (1,0,%s,'','')", 101 102 (to_timestamp(t1),)) 102 103 cursor.execute("INSERT INTO revision (repos,rev,time,author,message) " 103 "VALUES ( 'test-repos',1,%s,'joe','Import')",104 "VALUES (1,1,%s,'joe','Import')", 104 105 (to_timestamp(t2),)) 105 106 cursor.executemany("INSERT INTO node_change (repos,rev,path," 106 107 "node_type,change_type,base_path,base_rev) " 107 "VALUES ( 'test-repos','1',%s,%s,%s,%s,%s)",108 "VALUES (1,'1',%s,%s,%s,%s,%s)", 108 109 [('trunk', 'D', 'A', None, None), 109 110 ('trunk/README', 'F', 'A', None, None)]) 110 111 cursor.execute("UPDATE repository SET value='1' " 111 "WHERE id= 'test-repos'AND name='youngest_rev'")112 "WHERE id=1 AND name='youngest_rev'") 112 113 113 114 changes = [('trunk/README', Node.FILE, Changeset.EDIT, 'trunk/README', 1)] 114 115 changeset = Mock(Changeset, 2, 'Update', 'joe', t3, 115 116 get_changes=lambda: iter(changes)) 116 repos = Mock(Repository, 'test-repos', None, self.log,117 repos = Mock(Repository, 'test-repos', 1, 'test-repos', None, self.log, 117 118 get_changeset=lambda x: changeset, 118 119 get_youngest_rev=lambda: 2, 119 120 get_oldest_rev=lambda: 0, … … 137 138 t2 = datetime(2002, 1, 1, 1, 1, 1, 0, utc) 138 139 cursor = self.db.cursor() 139 140 cursor.execute("INSERT INTO revision (repos,rev,time,author,message) " 140 "VALUES ( 'test-repos',0,%s,'','')",141 "VALUES (1,0,%s,'','')", 141 142 (to_timestamp(t1),)) 142 143 cursor.execute("INSERT INTO revision (repos,rev,time,author,message) " 143 "VALUES ( 'test-repos',1,%s,'joe','Import')",144 "VALUES (1,1,%s,'joe','Import')", 144 145 (to_timestamp(t2),)) 145 146 cursor.executemany("INSERT INTO node_change (repos,rev,path," 146 147 "node_type,change_type,base_path,base_rev) " 147 "VALUES ( 'test-repos','1',%s,%s,%s,%s,%s)",148 "VALUES (1,'1',%s,%s,%s,%s,%s)", 148 149 [('trunk', 'D', 'A', None, None), 149 150 ('trunk/README', 'F', 'A', None, None)]) 150 151 cursor.execute("UPDATE repository SET value='1' " 151 "WHERE id= 'test-repos'AND name='youngest_rev'")152 "WHERE id=1 AND name='youngest_rev'") 152 153 153 repos = Mock(Repository, 'test-repos', None, self.log,154 repos = Mock(Repository, 'test-repos', 1, 'test-repos', None, self.log, 154 155 get_changeset=lambda x: None, 155 156 get_youngest_rev=lambda: 1, 156 157 get_oldest_rev=lambda: 0, -
trac/versioncontrol/tests/svn_fs.py
diff --git a/trac/versioncontrol/tests/svn_fs.py b/trac/versioncontrol/tests/svn_fs.py
a b 86 86 class SubversionRepositoryTestCase(unittest.TestCase): 87 87 88 88 def setUp(self): 89 self.repos = SubversionRepository( REPOS_PATH, None,89 self.repos = SubversionRepository('repo', 1, REPOS_PATH, None, 90 90 logger_factory('test')) 91 91 92 92 def tearDown(self): … … 508 508 class ScopedSubversionRepositoryTestCase(unittest.TestCase): 509 509 510 510 def setUp(self): 511 self.repos = SubversionRepository( REPOS_PATH + u'/tête', None,512 logger_factory('test'))511 self.repos = SubversionRepository('repo', 1, REPOS_PATH + u'/tête', 512 None, logger_factory('test')) 513 513 514 514 def tearDown(self): 515 515 self.repos = None … … 757 757 class RecentPathScopedRepositoryTestCase(unittest.TestCase): 758 758 759 759 def setUp(self): 760 self.repos = SubversionRepository(REPOS_PATH + u'/tête/dir1', None, 760 self.repos = SubversionRepository('repo', 1, 761 REPOS_PATH + u'/tête/dir1', None, 761 762 logger_factory('test')) 762 763 763 764 def tearDown(self): … … 777 778 class NonSelfContainedScopedTestCase(unittest.TestCase): 778 779 779 780 def setUp(self): 780 self.repos = SubversionRepository( REPOS_PATH + '/tags/v1', None,781 logger_factory('test'))781 self.repos = SubversionRepository('repo', 1, REPOS_PATH + '/tags/v1', 782 None, logger_factory('test')) 782 783 783 784 def tearDown(self): 784 785 self.repos = None … … 795 796 class AnotherNonSelfContainedScopedTestCase(unittest.TestCase): 796 797 797 798 def setUp(self): 798 self.repos = SubversionRepository( REPOS_PATH + '/branches', None,799 logger_factory('test'))799 self.repos = SubversionRepository('repo', 1, REPOS_PATH + '/branches', 800 None, logger_factory('test')) 800 801 801 802 def tearDown(self): 802 803 self.repos = None
