1#! /usr/bin/env python3 

2 

3""" Bulk manipulation of the overrides """ 

4# Copyright (C) 2000, 2001, 2002, 2003, 2006 James Troup <james@nocrew.org> 

5 

6# This program is free software; you can redistribute it and/or modify 

7# it under the terms of the GNU General Public License as published by 

8# the Free Software Foundation; either version 2 of the License, or 

9# (at your option) any later version. 

10 

11# This program is distributed in the hope that it will be useful, 

12# but WITHOUT ANY WARRANTY; without even the implied warranty of 

13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

14# GNU General Public License for more details. 

15 

16# You should have received a copy of the GNU General Public License 

17# along with this program; if not, write to the Free Software 

18# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 

19 

20################################################################################ 

21 

22# On 30 Nov 1998, James Troup wrote: 

23# 

24# > James Troup<2> <troup2@debian.org> 

25# > 

26# > James is a clone of James; he's going to take over the world. 

27# > After he gets some sleep. 

28# 

29# Could you clone other things too? Sheep? Llamas? Giant mutant turnips? 

30# 

31# Your clone will need some help to take over the world, maybe clone up an 

32# army of penguins and threaten to unleash them on the world, forcing 

33# governments to sway to the new James' will! 

34# 

35# Yes, I can envision a day when James' duplicate decides to take a horrific 

36# vengance on the James that spawned him and unleashes his fury in the form 

37# of thousands upon thousands of chickens that look just like Captin Blue 

38# Eye! Oh the horror. 

39# 

40# Now you'll have to were name tags to people can tell you apart, unless of 

41# course the new clone is truely evil in which case he should be easy to 

42# identify! 

43# 

44# Jason 

45# Chicken. Black. Helicopters. 

46# Be afraid. 

47 

48# <Pine.LNX.3.96.981130011300.30365Z-100000@wakko> 

49 

50################################################################################ 

51 

52import sys 

53import time 

54import apt_pkg 

55 

56from daklib.dbconn import * 

57from daklib.config import Config 

58from daklib import utils 

59from daklib import daklog 

60from daklib.regexes import re_comments 

61 

62################################################################################ 

63 

64Logger = None 

65 

66################################################################################ 

67 

68 

69def usage(exit_code=0): 

70 print("""Usage: dak control-overrides [OPTIONS] 

71 -h, --help print this help and exit 

72 

73 -c, --component=CMPT list/set overrides by component 

74 (contrib,*main,non-free) 

75 -s, --suite=SUITE list/set overrides by suite 

76 (experimental,stable,testing,*unstable) 

77 -t, --type=TYPE list/set overrides by type 

78 (*deb,dsc,udeb) 

79 

80 -a, --add add overrides (changes and deletions are ignored) 

81 -S, --set set overrides 

82 -C, --change change overrides (additions and deletions are ignored) 

83 -l, --list list overrides 

84 

85 -q, --quiet be less verbose 

86 -n, --no-action only list the action that would have been done 

87 

88 starred (*) values are default""") 

89 sys.exit(exit_code) 

90 

91################################################################################ 

92 

93 

94def process_file(file, suite, component, otype, mode, action, session): 

95 cnf = Config() 

96 

97 s = get_suite(suite, session=session) 

98 if s is None: 98 ↛ 99line 98 didn't jump to line 99, because the condition on line 98 was never true

99 utils.fubar("Suite '%s' not recognised." % (suite)) 

100 suite_id = s.suite_id 

101 

102 c = get_component(component, session=session) 

103 if c is None: 103 ↛ 104line 103 didn't jump to line 104, because the condition on line 103 was never true

104 utils.fubar("Component '%s' not recognised." % (component)) 

105 component_id = c.component_id 

106 

107 o = get_override_type(otype) 

108 if o is None: 108 ↛ 109line 108 didn't jump to line 109, because the condition on line 108 was never true

109 utils.fubar("Type '%s' not recognised. (Valid types are deb, udeb and dsc.)" % (otype)) 

110 type_id = o.overridetype_id 

111 

112 # --set is done mostly internal for performance reasons; most 

113 # invocations of --set will be updates and making people wait 2-3 

114 # minutes while 6000 select+inserts are run needlessly isn't cool. 

115 

116 original = {} 

117 new = {} 

118 c_skipped = 0 

119 c_added = 0 

120 c_updated = 0 

121 c_removed = 0 

122 c_error = 0 

123 

124 q = session.execute("""SELECT o.package, o.priority, o.section, o.maintainer, p.priority, s.section 

125 FROM override o, priority p, section s 

126 WHERE o.suite = :suiteid AND o.component = :componentid AND o.type = :typeid 

127 and o.priority = p.id and o.section = s.id""", 

128 {'suiteid': suite_id, 'componentid': component_id, 'typeid': type_id}) 

129 for i in q.fetchall(): 

130 original[i[0]] = i[1:] 

131 

132 start_time = time.time() 

133 

134 section_cache = get_sections(session) 

135 priority_cache = get_priorities(session) 

136 

137 # Our session is already in a transaction 

138 

139 for line in file.readlines(): 

140 line = re_comments.sub('', line).strip() 

141 if line == "": 141 ↛ 142line 141 didn't jump to line 142, because the condition on line 141 was never true

142 continue 

143 

144 maintainer_override = None 

145 if otype == "dsc": 

146 split_line = line.split(None, 2) 

147 if len(split_line) == 2: 147 ↛ 149line 147 didn't jump to line 149, because the condition on line 147 was never false

148 (package, section) = split_line 

149 elif len(split_line) == 3: 

150 (package, section, maintainer_override) = split_line 

151 else: 

152 utils.warn("'%s' does not break into 'package section [maintainer-override]'." % (line)) 

153 c_error += 1 

154 continue 

155 priority = "optional" 

156 else: # binary or udeb 

157 split_line = line.split(None, 3) 

158 if len(split_line) == 3: 158 ↛ 160line 158 didn't jump to line 160, because the condition on line 158 was never false

159 (package, priority, section) = split_line 

160 elif len(split_line) == 4: 

161 (package, priority, section, maintainer_override) = split_line 

162 else: 

163 utils.warn("'%s' does not break into 'package priority section [maintainer-override]'." % (line)) 

164 c_error += 1 

165 continue 

166 

167 if section not in section_cache: 167 ↛ 168line 167 didn't jump to line 168, because the condition on line 167 was never true

168 utils.warn("'%s' is not a valid section. ['%s' in suite %s, component %s]." % (section, package, suite, component)) 

169 c_error += 1 

170 continue 

171 

172 section_id = section_cache[section] 

173 

174 if priority not in priority_cache: 174 ↛ 175line 174 didn't jump to line 175, because the condition on line 174 was never true

175 utils.warn("'%s' is not a valid priority. ['%s' in suite %s, component %s]." % (priority, package, suite, component)) 

176 c_error += 1 

177 continue 

178 

179 priority_id = priority_cache[priority] 

180 

181 if package in new: 181 ↛ 182line 181 didn't jump to line 182, because the condition on line 181 was never true

182 utils.warn("Can't insert duplicate entry for '%s'; ignoring all but the first. [suite %s, component %s]" % (package, suite, component)) 

183 c_error += 1 

184 continue 

185 new[package] = "" 

186 

187 if package in original: 187 ↛ 188line 187 didn't jump to line 188, because the condition on line 187 was never true

188 (old_priority_id, old_section_id, old_maintainer_override, old_priority, old_section) = original[package] 

189 if mode == "add" or old_priority_id == priority_id and \ 

190 old_section_id == section_id and \ 

191 old_maintainer_override == maintainer_override: 

192 # If it's unchanged or we're in 'add only' mode, ignore it 

193 c_skipped += 1 

194 continue 

195 else: 

196 # If it's changed, delete the old one so we can 

197 # reinsert it with the new information 

198 c_updated += 1 

199 if action: 

200 session.execute("""DELETE FROM override WHERE suite = :suite AND component = :component 

201 AND package = :package AND type = :typeid""", 

202 {'suite': suite_id, 'component': component_id, 

203 'package': package, 'typeid': type_id}) 

204 

205 # Log changes 

206 if old_priority_id != priority_id: 

207 Logger.log(["changed priority", package, old_priority, priority]) 

208 if old_section_id != section_id: 

209 Logger.log(["changed section", package, old_section, section]) 

210 if old_maintainer_override != maintainer_override: 

211 Logger.log(["changed maintainer override", package, old_maintainer_override, maintainer_override]) 

212 update_p = 1 

213 elif mode == "change": 213 ↛ 215line 213 didn't jump to line 215, because the condition on line 213 was never true

214 # Ignore additions in 'change only' mode 

215 c_skipped += 1 

216 continue 

217 else: 

218 c_added += 1 

219 update_p = 0 

220 

221 if action: 221 ↛ 236line 221 didn't jump to line 236, because the condition on line 221 was never false

222 if not maintainer_override: 222 ↛ 225line 222 didn't jump to line 225, because the condition on line 222 was never false

223 m_o = None 

224 else: 

225 m_o = maintainer_override 

226 session.execute("""INSERT INTO override (suite, component, type, package, 

227 priority, section, maintainer) 

228 VALUES (:suiteid, :componentid, :typeid, 

229 :package, :priorityid, :sectionid, 

230 :maintainer)""", 

231 {'suiteid': suite_id, 'componentid': component_id, 

232 'typeid': type_id, 'package': package, 

233 'priorityid': priority_id, 'sectionid': section_id, 

234 'maintainer': m_o}) 

235 

236 if not update_p: 236 ↛ 139line 236 didn't jump to line 139, because the condition on line 236 was never false

237 Logger.log(["new override", suite, component, otype, package, priority, section, maintainer_override]) 

238 

239 if mode == "set": 239 ↛ 241line 239 didn't jump to line 241, because the condition on line 239 was never true

240 # Delete any packages which were removed 

241 for package in original.keys(): 

242 if package not in new: 

243 if action: 

244 session.execute("""DELETE FROM override 

245 WHERE suite = :suiteid AND component = :componentid 

246 AND package = :package AND type = :typeid""", 

247 {'suiteid': suite_id, 'componentid': component_id, 

248 'package': package, 'typeid': type_id}) 

249 c_removed += 1 

250 Logger.log(["removed override", suite, component, otype, package]) 

251 

252 if action: 252 ↛ 255line 252 didn't jump to line 255, because the condition on line 252 was never false

253 session.commit() 

254 

255 if not cnf["Control-Overrides::Options::Quiet"]: 255 ↛ 258line 255 didn't jump to line 258, because the condition on line 255 was never false

256 print("Done in %d seconds. [Updated = %d, Added = %d, Removed = %d, Skipped = %d, Errors = %d]" % (int(time.time() - start_time), c_updated, c_added, c_removed, c_skipped, c_error)) 

257 

258 Logger.log(["set complete", c_updated, c_added, c_removed, c_skipped, c_error]) 

259 

260################################################################################ 

261 

262 

263def list_overrides(suite, component, otype, session): 

264 dat = {} 

265 s = get_suite(suite, session) 

266 if s is None: 266 ↛ 267line 266 didn't jump to line 267, because the condition on line 266 was never true

267 utils.fubar("Suite '%s' not recognised." % (suite)) 

268 

269 dat['suiteid'] = s.suite_id 

270 

271 c = get_component(component, session) 

272 if c is None: 272 ↛ 273line 272 didn't jump to line 273, because the condition on line 272 was never true

273 utils.fubar("Component '%s' not recognised." % (component)) 

274 

275 dat['componentid'] = c.component_id 

276 

277 o = get_override_type(otype) 

278 if o is None: 278 ↛ 279line 278 didn't jump to line 279, because the condition on line 278 was never true

279 utils.fubar("Type '%s' not recognised. (Valid types are deb, udeb and dsc)" % (otype)) 

280 

281 dat['typeid'] = o.overridetype_id 

282 

283 if otype == "dsc": 283 ↛ 284line 283 didn't jump to line 284, because the condition on line 283 was never true

284 q = session.execute("""SELECT o.package, s.section, o.maintainer FROM override o, section s 

285 WHERE o.suite = :suiteid AND o.component = :componentid 

286 AND o.type = :typeid AND o.section = s.id 

287 ORDER BY s.section, o.package""", dat) 

288 for i in q.fetchall(): 

289 print(utils.result_join(i)) 

290 else: 

291 q = session.execute("""SELECT o.package, p.priority, s.section, o.maintainer, p.level 

292 FROM override o, priority p, section s 

293 WHERE o.suite = :suiteid AND o.component = :componentid 

294 AND o.type = :typeid AND o.priority = p.id AND o.section = s.id 

295 ORDER BY s.section, p.level, o.package""", dat) 

296 for i in q.fetchall(): 296 ↛ 297line 296 didn't jump to line 297, because the loop on line 296 never started

297 print(utils.result_join(i[:-1])) 

298 

299################################################################################ 

300 

301 

302def main(): 

303 global Logger 

304 

305 cnf = Config() 

306 Arguments = [('a', "add", "Control-Overrides::Options::Add"), 

307 ('c', "component", "Control-Overrides::Options::Component", "HasArg"), 

308 ('h', "help", "Control-Overrides::Options::Help"), 

309 ('l', "list", "Control-Overrides::Options::List"), 

310 ('q', "quiet", "Control-Overrides::Options::Quiet"), 

311 ('s', "suite", "Control-Overrides::Options::Suite", "HasArg"), 

312 ('S', "set", "Control-Overrides::Options::Set"), 

313 ('C', "change", "Control-Overrides::Options::Change"), 

314 ('n', "no-action", "Control-Overrides::Options::No-Action"), 

315 ('t', "type", "Control-Overrides::Options::Type", "HasArg")] 

316 

317 # Default arguments 

318 for i in ["add", "help", "list", "quiet", "set", "change", "no-action"]: 

319 key = "Control-Overrides::Options::%s" % i 

320 if key not in cnf: 320 ↛ 318line 320 didn't jump to line 318, because the condition on line 320 was never false

321 cnf[key] = "" 

322 if "Control-Overrides::Options::Component" not in cnf: 322 ↛ 324line 322 didn't jump to line 324, because the condition on line 322 was never false

323 cnf["Control-Overrides::Options::Component"] = "main" 

324 if "Control-Overrides::Options::Suite" not in cnf: 324 ↛ 326line 324 didn't jump to line 326, because the condition on line 324 was never false

325 cnf["Control-Overrides::Options::Suite"] = "unstable" 

326 if "Control-Overrides::Options::Type" not in cnf: 326 ↛ 329line 326 didn't jump to line 329, because the condition on line 326 was never false

327 cnf["Control-Overrides::Options::Type"] = "deb" 

328 

329 file_list = apt_pkg.parse_commandline(cnf.Cnf, Arguments, sys.argv) 

330 

331 if cnf["Control-Overrides::Options::Help"]: 

332 usage() 

333 

334 session = DBConn().session() 

335 

336 mode = None 

337 for i in ["add", "list", "set", "change"]: 

338 if cnf["Control-Overrides::Options::%s" % (i)]: 

339 if mode: 339 ↛ 340line 339 didn't jump to line 340, because the condition on line 339 was never true

340 utils.fubar("Can not perform more than one action at once.") 

341 mode = i 

342 

343 # Need an action... 

344 if mode is None: 344 ↛ 345line 344 didn't jump to line 345, because the condition on line 344 was never true

345 utils.fubar("No action specified.") 

346 

347 (suite, component, otype) = (cnf["Control-Overrides::Options::Suite"], 

348 cnf["Control-Overrides::Options::Component"], 

349 cnf["Control-Overrides::Options::Type"]) 

350 

351 if mode == "list": 

352 list_overrides(suite, component, otype, session) 

353 else: 

354 if get_suite(suite).untouchable: 354 ↛ 355line 354 didn't jump to line 355, because the condition on line 354 was never true

355 utils.fubar("%s: suite is untouchable" % suite) 

356 

357 action = True 

358 if cnf["Control-Overrides::Options::No-Action"]: 358 ↛ 359line 358 didn't jump to line 359, because the condition on line 358 was never true

359 utils.warn("In No-Action Mode") 

360 action = False 

361 

362 Logger = daklog.Logger("control-overrides", mode) 

363 if file_list: 363 ↛ 364line 363 didn't jump to line 364, because the condition on line 363 was never true

364 for f in file_list: 

365 process_file(open(f), suite, component, otype, mode, action, session) 

366 else: 

367 process_file(sys.stdin, suite, component, otype, mode, action, session) 

368 Logger.close() 

369 

370####################################################################################### 

371 

372 

373if __name__ == '__main__': 

374 main()