comparison contrib/deletebuild.py @ 862:9d65ffa31414

Add script for deleting duplicate builds encountered during upgrades.
author hodgestar
date Mon, 18 Oct 2010 00:21:17 +0000
parents
children a24744710a65
comparison
equal deleted inserted replaced
860:ac28bc3feb2a 862:9d65ffa31414
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
51 db = self.env.get_db_cnx()
52 cursor = db.cursor()
53
54 print "Attachments for build resource:"
55 cursor.execute("SELECT config FROM bitten_build WHERE id=%s", (build,))
56 config = cursor.fetchone()[0]
57 print "\n %s/%s" % (config, build)
58
59 print "Log files:"
60 print "\n ".join(self._log_files(cursor, build))
61
62 print "Rows from bitten_log with ids:"
63 cursor.execute("SELECT id FROM bitten_log WHERE build=%s", (build,))
64 print "\n ".join(row[0] for row in cursor.fetchall())
65
66 print "Rows from bitten_report with ids:"
67 cursor.execute("SELECT id FROM bitten_report WHERE build=%s", (build,))
68 print "\n ".join(row[0] for row in cursor.fetchall())
69 print "Rows from bitten_report_item with report set to these ids will"
70 print "also be deleted."
71
72 print "Rows from bitten_step for this build with names:"
73 cursor.execute("SELECT name FROM bitten_step WHERE build=%s", (build,))
74 print "\n ".join(row[0] for row in cursor.fetchall())
75
76 print "Row from bitten_build with id:"
77 cursor.execute("SELECT name FROM bitten_step WHERE build=%s", (build,))
78 print "\n ".join(row[0] for row in cursor.fetchall())
79
80 def remove(self, build):
81 """Delete what is linked to the build."""
82 print "Deleting items for build %r" % (build,)
83
84 db = self.env.get_db_cnx()
85 cursor = db.cursor()
86
87 print "Determining associated config."
88 cursor.execute("SELECT config FROM bitten_build WHERE id=%s", (build,))
89 config = cursor.fetchone()[0]
90
91 print "Collecting log files."
92 filenames = self._log_files(cursor, build)
93
94 try:
95 print "Deleting bitten_log entries."
96 cursor.execute("DELETE FROM bitten_log WHERE build=%s", (build,))
97
98 print "Deleting bitten_report_item_entries."
99 cursor.execute("DELETE FROM bitten_report_item WHERE report IN ("
100 "SELECT bitten_report.id FROM bitten_report "
101 "WHERE bitten_report.build=%s"
102 ")", (build,))
103
104 print "Deleting bitten_report entires."
105 cursor.execute("DELETE FROM bitten_report WHERE build=%s",
106 (build,))
107
108 print "Deleting bitten_step entries."
109 cursor.execute("DELETE FROM bitten_step WHERE build=%s", (build,))
110
111 print "Delete bitten_build entry."
112 cursor.execute("DELETE FROM bitten_build WHERE id=%s", (build,))
113 except:
114 db.rollback()
115 print "Build deletion failed. Database rolled back."
116 raise
117
118 print "Bitten database changes committed."
119 db.commit()
120
121 print "Removing log files."
122 for filename in filenames:
123 os.remove(filename)
124
125 print "Removing attachments."
126 resource = Resource('build', '%s/%s' % (config, build))
127 Attachment.delete_all(self.env, 'build', resource.id, db)
128
129
130 def main():
131 from optparse import OptionParser
132
133 parser = OptionParser(usage='usage: %prog env_path build_id',
134 version='%%prog %s' % __version__)
135
136 options, args = parser.parse_args()
137
138 if len(args) != 2:
139 parser.error('incorrect number of arguments')
140
141 env_path, build_id = args
142
143 deleter = BuildDeleter(env_path)
144 deleter.discover(build_id)
145 proceed = raw_input('Continue [y/n]? ')
146 if proceed == 'y':
147 deleter.remove(build_id)
148
149
150 if __name__ == "__main__":
151 import sys
152 sys.exit(main())
Copyright (C) 2012-2017 Edgewall Software