| 1 | #!/usr/bin/python |
|---|
| 2 | ### Warning removes all trace of T&E from your computer ### |
|---|
| 3 | ### USE ONLY IN DIREST NEED AND WITH CAUTION ### |
|---|
| 4 | |
|---|
| 5 | import re,shutil,traceback |
|---|
| 6 | from optparse import OptionParser |
|---|
| 7 | from trac.env import Environment |
|---|
| 8 | |
|---|
| 9 | parser = OptionParser("""usage: [options] trac-install |
|---|
| 10 | trac-install <- The path to your trac install.""") |
|---|
| 11 | |
|---|
| 12 | def p(question): |
|---|
| 13 | return raw_input('%s\nT&E-uninstall> '%question) |
|---|
| 14 | |
|---|
| 15 | def cast_bool(s): |
|---|
| 16 | return len(re.findall('(?i)(y|t|1)', s))>0 |
|---|
| 17 | |
|---|
| 18 | def p_bool(question): |
|---|
| 19 | return cast_bool(raw_input('%s\nT&E-uninstall> '%question)) |
|---|
| 20 | |
|---|
| 21 | field_list = ['estimatedhours', 'hours', 'billable', 'totalhours', 'internal'] |
|---|
| 22 | fields = "'estimatedhours', 'hours', 'billable', 'totalhours', 'internal'" |
|---|
| 23 | |
|---|
| 24 | class Script ( object ): |
|---|
| 25 | def __init__(self): |
|---|
| 26 | while self.find_and_remove_installs():pass |
|---|
| 27 | (options,args) = parser.parse_args() |
|---|
| 28 | if(len(args) == 0) : |
|---|
| 29 | self.trac= p('Please type your trac path (or run this script passing it the path):') |
|---|
| 30 | else: |
|---|
| 31 | self.trac = args[0] |
|---|
| 32 | print "Opening trac environment" |
|---|
| 33 | self.env = Environment(self.trac) |
|---|
| 34 | self.env.with_transaction() |
|---|
| 35 | |
|---|
| 36 | print "Removing T&E from trac env" |
|---|
| 37 | self.find_and_remove_custom_vars() |
|---|
| 38 | self.find_and_remove_ticket_change() |
|---|
| 39 | self.find_and_remove_reports() |
|---|
| 40 | self.remove_configuration() |
|---|
| 41 | self.remove_system_keys() |
|---|
| 42 | print "Done uninstalling" |
|---|
| 43 | |
|---|
| 44 | |
|---|
| 45 | def execute_in_trans(self, *args): |
|---|
| 46 | result = True |
|---|
| 47 | c_sql =[None] |
|---|
| 48 | c_params = [None] |
|---|
| 49 | @self.env.with_transaction() |
|---|
| 50 | def fn(db): |
|---|
| 51 | try: |
|---|
| 52 | cur = db.cursor() |
|---|
| 53 | for sql, params in args: |
|---|
| 54 | c_sql[0] = sql |
|---|
| 55 | c_params[0] = params |
|---|
| 56 | cur.execute(sql, params) |
|---|
| 57 | except Exception, e : |
|---|
| 58 | print 'There was a problem executing sql:%s \n \ |
|---|
| 59 | with parameters:%s\nException:%s'%(c_sql[0], c_params[0], e); |
|---|
| 60 | raise e |
|---|
| 61 | return result |
|---|
| 62 | |
|---|
| 63 | def execute(self, sql, *params): |
|---|
| 64 | """Executes the query on the given project""" |
|---|
| 65 | self.execute_in_trans((sql, params)) |
|---|
| 66 | |
|---|
| 67 | def get_first_row(self, sql,*params): |
|---|
| 68 | """ Returns the first row of the query results as a tuple of values (or None)""" |
|---|
| 69 | db = self.env.get_read_db() |
|---|
| 70 | cur = db.cursor() |
|---|
| 71 | data = None; |
|---|
| 72 | try: |
|---|
| 73 | cur.execute(sql, params) |
|---|
| 74 | data = cur.fetchone(); |
|---|
| 75 | except Exception, e: |
|---|
| 76 | print 'There was a problem executing sql:%s \n \ |
|---|
| 77 | with parameters:%s\nException:%s'%(sql, params, e) |
|---|
| 78 | return data; |
|---|
| 79 | |
|---|
| 80 | |
|---|
| 81 | def find_and_remove_installs(self): |
|---|
| 82 | try: |
|---|
| 83 | import timingandestimationplugin |
|---|
| 84 | path = timingandestimationplugin.__file__ |
|---|
| 85 | install_path = re.findall( '^.*egg', path) |
|---|
| 86 | if len(install_path)>0: |
|---|
| 87 | install_path = install_path[0] |
|---|
| 88 | else: |
|---|
| 89 | print "Cant remove this install: %s" % install_path |
|---|
| 90 | return False |
|---|
| 91 | if p_bool('Remove: %s (y/n)'%install_path): |
|---|
| 92 | shutil.rmtree(install_path) |
|---|
| 93 | return true #could be true, but just run it more than once |
|---|
| 94 | return False |
|---|
| 95 | except ImportError: |
|---|
| 96 | return False |
|---|
| 97 | |
|---|
| 98 | def find_and_remove_custom_vars(self): |
|---|
| 99 | try: |
|---|
| 100 | if self.get_first_row("SELECT * FROM ticket_custom WHERE name in (%s)"%fields): |
|---|
| 101 | if p_bool("Remove custom fields (%s) (y/n)"%fields): |
|---|
| 102 | self.execute('DELETE FROM ticket_custom WHERE name in (%s)'%fields) |
|---|
| 103 | except Exception,e: |
|---|
| 104 | print "Failed to remove ticket_custom",e |
|---|
| 105 | traceback.print_exc() |
|---|
| 106 | |
|---|
| 107 | def find_and_remove_ticket_change(self): |
|---|
| 108 | try: |
|---|
| 109 | if self.get_first_row("SELECT * FROM ticket_change WHERE field in (%s)"%fields): |
|---|
| 110 | if p_bool("Remove ticket changes (%s) (y/n)"%fields): |
|---|
| 111 | self.execute('DELETE FROM ticket_change WHERE field in (%s)'%fields) |
|---|
| 112 | except Exception,e: |
|---|
| 113 | print "Failed to remove ticket_changes",e |
|---|
| 114 | traceback.print_exc() |
|---|
| 115 | |
|---|
| 116 | def find_and_remove_reports(self): |
|---|
| 117 | try: |
|---|
| 118 | if self.get_first_row( |
|---|
| 119 | "SELECT * FROM report WHERE id in (" |
|---|
| 120 | "SELECT id FROM custom_report WHERE " |
|---|
| 121 | "maingroup='Timing and Estimation Plugin')"): |
|---|
| 122 | if p_bool("Remove T&E reports (y/n)"): |
|---|
| 123 | self.execute("DELETE FROM report WHERE id in (" |
|---|
| 124 | "SELECT id FROM custom_report WHERE " |
|---|
| 125 | "maingroup='Timing and Estimation Plugin')") |
|---|
| 126 | self.execute("DELETE FROM custom_report WHERE " |
|---|
| 127 | "maingroup='Timing and Estimation Plugin'") |
|---|
| 128 | |
|---|
| 129 | except Exception,e: |
|---|
| 130 | print "Failed to remove reports",e |
|---|
| 131 | traceback.print_exc() |
|---|
| 132 | |
|---|
| 133 | def remove_configuration(self): |
|---|
| 134 | if not p_bool('Remove T&E configuration (y/n)'): return |
|---|
| 135 | for k,v in self.env.config.options('ticket-custom'): |
|---|
| 136 | if any(re.search('(?i)'+f,k) for f in field_list): |
|---|
| 137 | self.env.config.remove('ticket-custom',k) |
|---|
| 138 | for k,v in self.env.config.options('field settings'): |
|---|
| 139 | self.env.config.remove('field settings',k) |
|---|
| 140 | |
|---|
| 141 | for k,v in self.env.config.options('components'): |
|---|
| 142 | if re.search('timingandestimationplugin',k): |
|---|
| 143 | self.env.config.remove('components', k); |
|---|
| 144 | |
|---|
| 145 | for k,v in self.env.config.options('field settings'): |
|---|
| 146 | self.env.config.remove('field settings',k) |
|---|
| 147 | |
|---|
| 148 | if re.search('InternalTicketsPolicy', |
|---|
| 149 | self.env.config.get('trac','permission_policies','')): |
|---|
| 150 | print "Please remove InternalTicketsPolicy from your trac.ini [trac] permission_policies" |
|---|
| 151 | self.env.config.save() |
|---|
| 152 | |
|---|
| 153 | def remove_system_keys(self): |
|---|
| 154 | if not p_bool('Remove T&E system keys'): return |
|---|
| 155 | self.execute("DELETE FROM system WHERE name in " |
|---|
| 156 | "('TimingAndEstimationPlugin_Db_Version','T&E-statuses');") |
|---|
| 157 | |
|---|
| 158 | |
|---|
| 159 | |
|---|
| 160 | if __name__ == '__main__' : |
|---|
| 161 | Script() |
|---|