1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266

267

268

269

270

271

272

273

274

275

276

277

278

279

280

281

282

283

284

285

286

287

288

289

290

291

292

293

294

295

296

297

298

299

300

301

302

303

304

305

306

307

308

309

310

311

312

313

314

315

316

317

318

319

320

321

322

323

324

325

326

327

328

329

330

331

332

333

334

335

336

337

338

339

340

341

342

343

344

345

346

347

348

349

350

351

352

353

354

355

356

357

358

359

360

361

362

363

364

365

366

367

# -*- coding: utf-8 -*- 

 

# Copyright 2013 The Distro Tracker Developers 

# See the COPYRIGHT file at the top-level directory of this distribution and 

# at https://deb.li/DTAuthors 

# 

# This file is part of Distro Tracker. It is subject to the license terms 

# in the LICENSE file found in the top-level directory of this 

# distribution and at https://deb.li/DTLicense. No part of Distro Tracker, 

# including this file, may be copied, modified, propagated, or distributed 

# except according to the terms contained in the LICENSE file. 

"""Debian specific panels on the package page.""" 

 

from django.urls import reverse 

from django.utils.encoding import force_text 

from django.utils.functional import cached_property 

from django.utils.http import urlencode, urlquote, urlquote_plus 

from django.utils.safestring import mark_safe 

 

from distro_tracker.core.models import ( 

PackageData, 

Repository, 

SourcePackageName 

) 

from distro_tracker.core.panels import ( 

BasePanel, 

HtmlPanelItem, 

LinksPanel, 

TemplatePanelItem 

) 

from distro_tracker.core.utils import get_or_none 

from distro_tracker.vendor.debian.models import ( 

BuildLogCheckStats, 

LintianStats, 

PackageExcuses, 

UbuntuPackage 

) 

 

 

class LintianLink(LinksPanel.ItemProvider): 

""" 

If there are any known lintian issues for the package, provides a link to 

the lintian page. 

""" 

def get_panel_items(self): 

try: 

lintian_stats = self.package.lintian_stats 

except LintianStats.DoesNotExist: 

return [] 

 

if sum(lintian_stats.stats.values()): 

url = lintian_stats.get_lintian_url() 

return [ 

TemplatePanelItem('debian/lintian-link.html', { 

'lintian_stats': lintian_stats.stats, 

'lintian_url': url, 

}) 

] 

 

return [] 

 

 

class BuildLogCheckLinks(LinksPanel.ItemProvider): 

def get_experimental_context(self): 

has_experimental = False 

experimental_repo = get_or_none(Repository, suite='experimental') 

67 ↛ 68line 67 didn't jump to line 68, because the condition on line 67 was never true if experimental_repo: 

has_experimental = experimental_repo.has_source_package_name( 

self.package.name) 

return {'has_experimental': has_experimental} 

 

def get_logcheck_context(self): 

try: 

self.package.build_logcheck_stats 

has_checks = True 

except BuildLogCheckStats.DoesNotExist: 

has_checks = False 

logcheck_url = \ 

"https://qa.debian.org/bls/packages/{hash}/{pkg}.html".format( 

hash=urlquote(self.package.name[0], safe=""), 

pkg=urlquote(self.package.name, safe="")) 

return {'has_checks': has_checks, 'logcheck_url': logcheck_url} 

 

def get_reproducible_context(self): 

try: 

infos = self.package.data.get(key='reproducibility') 

has_reproducibility = True 

reproducibility_status = infos.value['reproducibility'] 

except PackageData.DoesNotExist: 

has_reproducibility = False 

reproducibility_status = None 

reproducibility_url = \ 

"https://tests.reproducible-builds.org/debian/rb-pkg/{}.html" 

reproducibility_url = reproducibility_url.format( 

urlquote(self.package.name, safe="")) 

return {'has_reproducibility': has_reproducibility, 

'reproducibility_url': reproducibility_url, 

'reproducibility_status': reproducibility_status, 

} 

 

def get_debcheck_context(self): 

# display debcheck link if there is at least one kind of problem 

has_debcheck = False 

for k in ['dependency_satisfaction', 

'builddependency_satisfaction']: 

try: 

self.package.data.get(key=k) 

has_debcheck = True 

break 

except PackageData.DoesNotExist: 

pass 

 

debcheck_url = \ 

"https://qa.debian.org/dose/debcheck/src" \ 

"/{}.html".format(urlquote(self.package.name, safe="")) 

return {'has_debcheck': has_debcheck, 'debcheck_url': debcheck_url} 

 

def get_crossqa_context(self): 

try: 

has_crossqa = False 

arches = self.package.data.get( 

key='general').value.get('architectures') 

# might be wrong due to https://bugs.debian.org/920024 

124 ↛ 125line 124 didn't jump to line 125, because the condition on line 124 was never true if arches is not None and arches != ['all']: 

has_crossqa = True 

except PackageData.DoesNotExist: 

has_crossqa = False 

return {'has_crossqa': has_crossqa} 

 

def get_panel_items(self): 

if not isinstance(self.package, SourcePackageName): 

# Only source packages can have build log check info 

return 

 

query_string = urlencode({'p': self.package.name}) 

 

return [ 

TemplatePanelItem('debian/logcheck-links.html', { 

'package_name': urlquote(self.package.name), 

'package_query_string': query_string, 

**self.get_logcheck_context(), 

**self.get_reproducible_context(), 

**self.get_experimental_context(), 

**self.get_debcheck_context(), 

**self.get_crossqa_context(), 

}) 

] 

 

 

class PopconLink(LinksPanel.ItemProvider): 

POPCON_URL = 'https://qa.debian.org/popcon.php?package={package}' 

 

def get_panel_items(self): 

if not isinstance(self.package, SourcePackageName): 

return 

 

return [ 

LinksPanel.SimpleLinkItem( 

'popcon', 

self.POPCON_URL.format( 

package=urlquote_plus(self.package.name))) 

] 

 

 

class SourceCodeSearchLinks(LinksPanel.ItemProvider): 

""" 

Add links to sources.debian.org source code browser and the 

codesearch.debian.net code search (if the package is found in unstable). 

""" 

#: A list of repositories that cause the sources.debian.org link to be 

#: displayed if the package is found in one of them. 

ALLOWED_REPOSITORIES = ( 

'unstable', 

'experimental', 

'testing', 

'stable', 

'oldstable', 

) 

SOURCES_URL_TEMPLATE = 'https://sources.debian.org/src/{package}/{suite}/' 

SEARCH_FORM_TEMPLATE = ( 

'<form class="code-search-form"' 

' action="' + reverse('dtracker-code-search') + '"' 

' method="get" target="_blank">' 

'<input type="hidden" name="package" value="{package}">' 

'<input type="search" name="query" placeholder="search source code">' 

'</form>') 

 

def get_panel_items(self): 

if not isinstance(self.package, SourcePackageName): 

# Only source packages can have these links 

return 

 

repositories = [repo.suite for repo in self.package.repositories] + \ 

[repo.codename for repo in self.package.repositories] 

links = [] 

for allowed_repo in self.ALLOWED_REPOSITORIES: 

if allowed_repo in repositories: 

links.append(LinksPanel.SimpleLinkItem( 

'browse source code', 

self.SOURCES_URL_TEMPLATE.format( 

package=urlquote(self.package.name, safe=""), 

suite=urlquote(allowed_repo, safe="")))) 

break 

 

if 'unstable' in repositories: 

# Add a search form 

links.append(HtmlPanelItem(self.SEARCH_FORM_TEMPLATE.format( 

package=self.package.name))) 

 

return links 

 

 

class DebtagsLink(LinksPanel.ItemProvider): 

""" 

Add a link to debtags editor. 

""" 

SOURCES_URL_TEMPLATE = \ 

'https://debtags.debian.org/rep/todo/maint/{maint}#{package}' 

 

def get_panel_items(self): 

if not isinstance(self.package, SourcePackageName): 

return 

try: 

infos = self.package.data.get(key='general') 

except PackageData.DoesNotExist: 

return 

maintainer = infos.value['maintainer']['email'] 

return [ 

LinksPanel.SimpleLinkItem( 

'edit tags', 

self.SOURCES_URL_TEMPLATE.format( 

package=urlquote(self.package.name, safe=""), 

maint=urlquote(maintainer, safe="")) 

) 

] 

 

 

class SecurityTrackerLink(LinksPanel.ItemProvider): 

""" 

Add a link to the security tracker. 

""" 

URL_TEMPLATE = \ 

'https://security-tracker.debian.org/tracker/source-package/{package}' 

 

def get_panel_items(self): 

246 ↛ 248line 246 didn't jump to line 248, because the condition on line 246 was never false if self.package.data.filter(key='debian-security').count() == 0: 

return 

return [ 

LinksPanel.SimpleLinkItem( 

'security tracker', 

self.URL_TEMPLATE.format(package=self.package.name) 

) 

] 

 

 

class ScreenshotsLink(LinksPanel.ItemProvider): 

""" 

Add a link to screenshots.debian.net 

""" 

SOURCES_URL_TEMPLATE = \ 

'https://screenshots.debian.net/package/{package}' 

 

def get_panel_items(self): 

if not isinstance(self.package, SourcePackageName): 

return 

try: 

infos = self.package.data.get(key='screenshots') 

except PackageData.DoesNotExist: 

return 

270 ↛ 279line 270 didn't jump to line 279, because the condition on line 270 was never false if infos.value['screenshots'] == 'true': 

return [ 

LinksPanel.SimpleLinkItem( 

'screenshots', 

self.SOURCES_URL_TEMPLATE.format( 

package=urlquote(self.package.name, safe="")) 

) 

] 

else: 

return 

 

 

class TransitionsPanel(BasePanel): 

template_name = 'debian/transitions-panel.html' 

panel_importance = 2 

position = 'center' 

title = 'testing migrations' 

 

@cached_property 

def context(self): 

try: 

excuses = self.package.excuses.excuses 

except PackageExcuses.DoesNotExist: 

excuses = None 

294 ↛ 295line 294 didn't jump to line 295, because the condition on line 294 was never true if excuses: 

excuses = [mark_safe(excuse) for excuse in excuses] 

return { 

'transitions': self.package.package_transitions.all(), 

'excuses': excuses, 

'package_name': self.package.name, 

} 

 

@property 

def has_content(self): 

return bool(self.context['transitions']) or \ 

bool(self.context['excuses']) 

 

 

class UbuntuPanel(BasePanel): 

template_name = 'debian/ubuntu-panel.html' 

position = 'right' 

title = 'ubuntu' 

 

@cached_property 

def context(self): 

try: 

ubuntu_package = self.package.ubuntu_package 

except UbuntuPackage.DoesNotExist: 

return 

 

return { 

'ubuntu_package': ubuntu_package, 

} 

 

@property 

def has_content(self): 

return bool(self.context) 

 

 

class BackToOldPTS(BasePanel): 

""" 

Display a message to users of the old PTS to encourage them to file bugs 

about issues that they discover and also to offer them a link back to the 

old PTS in case they need it. 

""" 

template_name = 'debian/back-to-old-pts.html' 

position = 'center' 

title = 'About the new package tracker' 

panel_importance = 100 

 

@cached_property 

def context(self): 

return { 

'package': self.package.name 

} 

 

@property 

def has_content(self): 

return "packages.qa.debian.org" in \ 

force_text(self.request.META.get('HTTP_REFERER', ''), 

encoding='latin1', errors='replace') 

 

 

class Dl10nLinks(LinksPanel.ItemProvider): 

def get_panel_items(self): 

if not isinstance(self.package, SourcePackageName): 

return 

 

try: 

dl10n_stats = self.package.data.get(key='dl10n').value 

except PackageData.DoesNotExist: 

return 

 

return [ 

TemplatePanelItem('debian/dl10n-links.html', { 

'dl10n_stats': dl10n_stats, 

}) 

]