comparison contrib/deletebuild.py @ 869:467e993df52d 0.6.x

0.6dev: Merged [940:942] from trunk.
author hodgestar
date Mon, 18 Oct 2010 11:55:44 +0000
parents
children
comparison
equal deleted inserted replaced
868:242f2e225c4e 869:467e993df52d
1 # -*- coding: utf-8 -*-
2 #
3 # Maintained by Simon Cross <hodegstar+bittencontrib@gmail.com>
4 #
5 # Copyright (C) 2010 Edgewall Software
6 # All rights reserved.
7 #
8 # This software is licensed as described in the file COPYING, which
9 # you should have received as part of this distribution. The terms
10 # are also available at http://bitten.edgewall.org/wiki/License.
11
12 """Utility for deleting duplicate builds encounted while upgrading
13 to schema version 10."""
14
15 import os
16
17 from trac.env import Environment
18 from trac.attachment import Attachment
19 from trac.resource import Resource
20
21 __version__ = "1.0a1"
22
23 class BuildDeleter(object):
24 """Class for deleting a build."""
25
26 def __init__(self, env_path):
27 self.env = Environment(env_path)
28 self.logs_dir = self.env.config.get('bitten', 'logs_dir', 'log/bitten')
29
30 def _log_files(self, cursor, build):
31 """Return a list of log files."""
32 cursor.execute("SELECT filename FROM bitten_log WHERE build=%s",
33 (build,))
34 rows = cursor.fetchall()
35
36 all_files = []
37 for row in rows:
38 filename = row[0]
39 file_prefix = os.path.join(self.logs_dir, filename)
40 for suffix in ['', '.level', '.levels']:
41 log_file = file_prefix + suffix
42 if os.path.isfile(log_file):
43 all_files.append(log_file)
44
45 return all_files
46
47 def discover(self, build):
48 """Print a summary of what is linked to the build."""
49 print "Items to delete for build %r" % (build,)
50 print "-------------------------------"
51
52 db = self.env.get_db_cnx()
53 cursor = db.cursor()
54
55 print "Attachments for build resource:"
56 cursor.execute("SELECT config FROM bitten_build WHERE id=%s", (build,))
57 config = cursor.fetchone()[0]
58 print " %s/%s" % (config, build)
59
60 print "Log files:"
61 print " ", "\n ".join(self._log_files(cursor, build))
62
63 print "Rows from bitten_log with ids:"
64 cursor.execute("SELECT id FROM bitten_log WHERE build=%s", (build,))
65 print " ", "\n ".join(str(row[0]) for row in cursor.fetchall())
66
67 print "Rows from bitten_report with ids:"
68 cursor.execute("SELECT id FROM bitten_report WHERE build=%s", (build,))
69 print " ", "\n ".join(str(row[0]) for row in cursor.fetchall())
70 print "Rows from bitten_report_item with report set to these ids will"
71 print "also be deleted."
72
73 print "Rows from bitten_step for this build with names:"
74 cursor.execute("SELECT name FROM bitten_step WHERE build=%s", (build,))
75 print " ", "\n ".join(str(row[0]) for row in cursor.fetchall())
76
77 print "Row from bitten_build with id:"
78 cursor.execute("SELECT id FROM bitten_build WHERE id=%s", (build,))
79 print " ", "\n ".join(str(row[0]) for row in cursor.fetchall())
80
81 def remove(self, build):
82 """Delete what is linked to the build."""
83 print "Deleting items for build %r" % (build,)
84
85 db = self.env.get_db_cnx()
86 cursor = db.cursor()
87
88 print "Determining associated config."
89 cursor.execute("SELECT config FROM bitten_build WHERE id=%s", (build,))
90 config = cursor.fetchone()[0]
91
92 print "Collecting log files."
93 filenames = self._log_files(cursor, build)
94
95 try:
96 print "Deleting bitten_log entries."
97 cursor.execute("DELETE FROM bitten_log WHERE build=%s", (build,))
98
99 print "Deleting bitten_report_item_entries."
100 cursor.execute("DELETE FROM bitten_report_item WHERE report IN ("
101 "SELECT bitten_report.id FROM bitten_report "
102 "WHERE bitten_report.build=%s"
103 ")", (build,))
104
105 print "Deleting bitten_report entires."
106 cursor.execute("DELETE FROM bitten_report WHERE build=%s",
107 (build,))
108
109 print "Deleting bitten_step entries."
110 cursor.execute("DELETE FROM bitten_step WHERE build=%s", (build,))
111
112 print "Delete bitten_build entry."
113 cursor.execute("DELETE FROM bitten_build WHERE id=%s", (build,))
114 except:
115 db.rollback()
116 print "Build deletion failed. Database rolled back."
117 raise
118
119 print "Bitten database changes committed."
120 db.commit()
121
122 print "Removing log files."
123 for filename in filenames:
124 os.remove(filename)
125
126 print "Removing attachments."
127 resource = Resource('build', '%s/%s' % (config, build))
128 Attachment.delete_all(self.env, 'build', resource.id, db)
129
130
131 def main():
132 from optparse import OptionParser
133
134 parser = OptionParser(usage='usage: %prog env_path build_id',
135 version='%%prog %s' % __version__)
136
137 options, args = parser.parse_args()
138
139 if len(args) != 2:
140 parser.error('incorrect number of arguments')
141
142 env_path, build_id = args
143
144 deleter = BuildDeleter(env_path)
145 deleter.discover(build_id)
146 proceed = raw_input('Continue [y/n]? ')
147 if proceed == 'y':
148 deleter.remove(build_id)
149
150
151 if __name__ == "__main__":
152 import sys
153 sys.exit(main())
Copyright (C) 2012-2017 Edgewall Software