| 1 | # -*- coding: iso-8859-1 -*- |
|---|
| 2 | # |
|---|
| 3 | # Copyright (C) 2005 Edgewall Software |
|---|
| 4 | # Copyright (C) 2005,2006 Lele Gaifax <lele@metapensiero.it> |
|---|
| 5 | # |
|---|
| 6 | # This software is licensed as described in the file COPYING, which |
|---|
| 7 | # you should have received as part of this distribution. The terms |
|---|
| 8 | # are also available at http://trac.edgewall.com/license.html. |
|---|
| 9 | # |
|---|
| 10 | # This software consists of voluntary contributions made by many |
|---|
| 11 | # individuals. For the exact contribution history, see the revision |
|---|
| 12 | # history and logs, available at http://projects.edgewall.com/trac/. |
|---|
| 13 | # |
|---|
| 14 | # Author: Lele Gaifax <lele@metapensiero.it> |
|---|
| 15 | |
|---|
| 16 | from trac.config import BoolOption, Option |
|---|
| 17 | from trac.core import Component, implements |
|---|
| 18 | from trac.db import Table, Column, DatabaseManager |
|---|
| 19 | from trac.env import IEnvironmentSetupParticipant |
|---|
| 20 | from trac.versioncontrol import IRepositoryConnector |
|---|
| 21 | |
|---|
| 22 | from tracdarcs.repository import DarcsRepository |
|---|
| 23 | |
|---|
| 24 | class DarcsConnector(Component): |
|---|
| 25 | |
|---|
| 26 | implements(IRepositoryConnector) |
|---|
| 27 | |
|---|
| 28 | dont_escape_8bit = BoolOption('darcs', 'dont_escape_8bit', 'false', |
|---|
| 29 | "Avoid darcs automatic escape of non-7bit chars.") |
|---|
| 30 | |
|---|
| 31 | darcs_command = Option('darcs', 'command', 'darcs', |
|---|
| 32 | "Name of the external darcs binary.") |
|---|
| 33 | |
|---|
| 34 | # IRepositoryConnector methods |
|---|
| 35 | |
|---|
| 36 | def get_supported_types(self): |
|---|
| 37 | """Support the `darcs:` scheme""" |
|---|
| 38 | yield ("darcs", 8) |
|---|
| 39 | |
|---|
| 40 | def get_repository(self, type, dir, authname): |
|---|
| 41 | """Return a `DarcsRepository`""" |
|---|
| 42 | db = self.env.get_db_cnx() |
|---|
| 43 | darcs = self.darcs_command |
|---|
| 44 | if self.dont_escape_8bit: |
|---|
| 45 | darcs = "DARCS_DONT_ESCAPE_8BIT=1 " + darcs |
|---|
| 46 | return DarcsRepository( db, dir, self.env.log, darcs ) |
|---|
| 47 | |
|---|
| 48 | class DarcsSetup(Component): |
|---|
| 49 | """Darcs customizer. |
|---|
| 50 | |
|---|
| 51 | The db tables required for the darcs backend are created here. |
|---|
| 52 | """ |
|---|
| 53 | |
|---|
| 54 | implements(IEnvironmentSetupParticipant) |
|---|
| 55 | |
|---|
| 56 | def environment_created(self): |
|---|
| 57 | """After standard environment has been created, add the needed |
|---|
| 58 | tables.""" |
|---|
| 59 | |
|---|
| 60 | db = self.env.get_db_cnx() |
|---|
| 61 | self.upgrade_environment(db) |
|---|
| 62 | db.commit() |
|---|
| 63 | |
|---|
| 64 | def environment_needs_upgrade(self, db): |
|---|
| 65 | """Check to see if the darcs tables are already there.""" |
|---|
| 66 | |
|---|
| 67 | c = db.cursor() |
|---|
| 68 | try: |
|---|
| 69 | c.execute( 'SELECT rev,author,time,hash,name,comment ' |
|---|
| 70 | 'FROM darcs_revisions LIMIT 1' ) |
|---|
| 71 | c.execute( 'SELECT node_id,node_type,add_rev,remove_rev ' |
|---|
| 72 | 'FROM darcs_nodes LIMIT 1' ) |
|---|
| 73 | c.execute( 'SELECT node_id,rev,path,parent_id,the_change ' |
|---|
| 74 | 'FROM darcs_node_changes LIMIT 1' ) |
|---|
| 75 | c.execute( 'SELECT node_id,rev,content ' |
|---|
| 76 | 'FROM darcs_cache LIMIT 1' ) |
|---|
| 77 | return False |
|---|
| 78 | except: |
|---|
| 79 | db.rollback() |
|---|
| 80 | return True |
|---|
| 81 | |
|---|
| 82 | def upgrade_environment(self, db): |
|---|
| 83 | """Actually add the new db tables.""" |
|---|
| 84 | |
|---|
| 85 | def drop_table( table_name ) : |
|---|
| 86 | c = db.cursor() |
|---|
| 87 | try : |
|---|
| 88 | c.execute( 'drop table %s' % table_name ) |
|---|
| 89 | except : |
|---|
| 90 | db.rollback() |
|---|
| 91 | pass |
|---|
| 92 | |
|---|
| 93 | drop_table( 'darcs_revisions' ) |
|---|
| 94 | drop_table( 'darcs_nodes' ) |
|---|
| 95 | drop_table( 'darcs_node_changes' ) |
|---|
| 96 | drop_table( 'darcs_cache' ) |
|---|
| 97 | |
|---|
| 98 | connector = DatabaseManager(self.env)._get_connector()[0] |
|---|
| 99 | if 'postgres' in [supp[0] for supp in connector.get_supported_schemes()]: |
|---|
| 100 | blobtype = 'bytea' |
|---|
| 101 | else: |
|---|
| 102 | blobtype = 'blob' |
|---|
| 103 | rev_table = Table( 'darcs_revisions', key='rev' )[ |
|---|
| 104 | Column('rev',type='int'), |
|---|
| 105 | Column('author'), |
|---|
| 106 | Column('time',type='datetime'), |
|---|
| 107 | Column('hash'), |
|---|
| 108 | Column('name'), |
|---|
| 109 | Column('comment') ] |
|---|
| 110 | node_table = Table( 'darcs_nodes', key='node_id' )[ |
|---|
| 111 | Column('node_id',type='int'), |
|---|
| 112 | Column('node_type'), |
|---|
| 113 | Column('add_rev',type='int'), |
|---|
| 114 | Column('remove_rev',type='int') ] |
|---|
| 115 | change_table = Table( 'darcs_node_changes', key=('node_id','rev') )[ |
|---|
| 116 | Column('node_id',type='int'), |
|---|
| 117 | Column('rev',type='int'), |
|---|
| 118 | Column('path'), |
|---|
| 119 | Column('parent_id',type='int'), |
|---|
| 120 | Column('the_change') ] |
|---|
| 121 | cache_table = Table( 'darcs_cache', key=('node_id','rev') )[ |
|---|
| 122 | Column('node_id',type='int'), |
|---|
| 123 | Column('rev',type='int'), |
|---|
| 124 | Column('content',type=blobtype) ] |
|---|
| 125 | c = db.cursor() |
|---|
| 126 | for t in [rev_table,node_table,change_table,cache_table] : |
|---|
| 127 | for stmt in connector.to_sql(t) : |
|---|
| 128 | c.execute( stmt ) |
|---|