Coverage for dak/graph.py: 26%
88 statements
« prev ^ index » next coverage.py v7.6.0, created at 2026-01-04 16:18 +0000
« prev ^ index » next coverage.py v7.6.0, created at 2026-01-04 16:18 +0000
1#! /usr/bin/env python3
3"""Produces a set of graphs of NEW/BYHAND/DEFERRED
5@contact: Debian FTPMaster <ftpmaster@debian.org>
6@copyright: 2011 Paul Wise <pabs@debian.org>
7"""
9# This program is free software; you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation; either version 2 of the License, or
12# (at your option) any later version.
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17# GNU General Public License for more details.
19# You should have received a copy of the GNU General Public License
20# along with this program; if not, write to the Free Software
21# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23import colorsys
24import os
25import sys
26from typing import NoReturn
28import apt_pkg
29import rrdtool
31from daklib import utils
33Cnf: apt_pkg.Configuration
34default_names = ["byhand", "new", "deferred"]
36################################################################################
39def usage(exit_code=0) -> NoReturn:
40 print(
41 """Usage: dak graph
42Graphs the number of packages in queue directories (usually new and byhand).
44 -h, --help show this help and exit.
45 -r, --rrd=key Directory where rrd files to be updated are stored
46 -x, --extra-rrd=key File containing extra options to rrdtool graphing
47 -i, --images=key Directory where image graphs to be updated are stored
48 -n, --names=key A comma separated list of rrd files to be scanned
50"""
51 )
52 sys.exit(exit_code)
55################################################################################
58def graph(
59 rrd_dir: str,
60 image_dir: str,
61 name: str,
62 extra_args: list[str],
63 graph: str,
64 title: str,
65 start: str,
66 year_lines=False,
67) -> None:
68 fn = graph_deferred if name == "deferred" else graph_normal
69 fn(rrd_dir, image_dir, name, extra_args, graph, title, start, year_lines)
72colours = [
73 "".join(
74 "%02X" % int(c * 255)
75 for c in colorsys.hsv_to_rgb(i / 16.0, 1.0, 0.5 + i / 32.0)
76 )
77 for i in range(0, 16)
78]
81def graph_deferred(
82 rrd_dir: str,
83 image_dir: str,
84 name: str,
85 extra_args: list[str],
86 graph: str,
87 title: str,
88 start: str,
89 year_lines=False,
90) -> None:
91 image_file = os.path.join(image_dir, "%s-%s.png" % (name, graph))
92 rrd_file = os.path.join(rrd_dir, "%s.rrd" % name)
93 rrd_args = [image_file, "--start", start]
94 rrd_args += (
95 (
96 """
97--end
98now
99--width
100600
101--height
102150
103--vertical-label
104changes
105--title
106%s changes count for the last %s
107--lower-limit
1080
109-E
110"""
111 % (name.upper(), title)
112 )
113 .strip()
114 .split("\n")
115 )
117 if year_lines:
118 rrd_args += ["--x-grid", "MONTH:1:YEAR:1:YEAR:1:31536000:%Y"]
120 for i in range(0, 16):
121 rrd_args += (
122 (
123 """
124DEF:d%i=%s:day%i:AVERAGE
125AREA:d%i#%s:%i-day changes count:STACK
126VDEF:ld%i=d%i,LAST
127VDEF:mind%i=d%i,MINIMUM
128VDEF:maxd%i=d%i,MAXIMUM
129VDEF:avgd%i=d%i,AVERAGE
130GPRINT:ld%i:cur\\: %%.0lf
131GPRINT:mind%i:min\\: %%.0lf
132GPRINT:maxd%i:max\\: %%.0lf
133GPRINT:avgd%i:avg\\: %%.0lf\\j
134"""
135 % ((i, rrd_file, i, i, colours[i]) + (i,) * 13)
136 )
137 .strip()
138 .split("\n")
139 )
141 rrd_args += extra_args
142 try:
143 rrdtool.graph(*rrd_args)
144 except rrdtool.error as e:
145 print(
146 ("warning: graph: rrdtool error, skipping %s-%s.png: %s" % (name, graph, e))
147 )
150def graph_normal(
151 rrd_dir: str,
152 image_dir: str,
153 name: str,
154 extra_args: list[str],
155 graph: str,
156 title: str,
157 start: str,
158 year_lines=False,
159) -> None:
160 image_file = os.path.join(image_dir, "%s-%s.png" % (name, graph))
161 rrd_file = os.path.join(rrd_dir, "%s.rrd" % name)
162 rrd_args = [image_file, "--start", start]
163 rrd_args += (
164 (
165 """
166--end
167now
168--width
169600
170--height
171150
172--vertical-label
173packages
174--title
175%s package count for the last %s
176--lower-limit
1770
178-E
179"""
180 % (name.upper(), title)
181 )
182 .strip()
183 .split("\n")
184 )
186 if year_lines:
187 rrd_args += ["--x-grid", "MONTH:1:YEAR:1:YEAR:1:31536000:%Y"]
189 rrd_args += (
190 (
191 """
192DEF:ds1=%s:ds1:AVERAGE
193LINE2:ds1#D9382B:changes count
194VDEF:lds1=ds1,LAST
195VDEF:minds1=ds1,MINIMUM
196VDEF:maxds1=ds1,MAXIMUM
197VDEF:avgds1=ds1,AVERAGE
198GPRINT:lds1:cur\\: %%.0lf
199GPRINT:minds1:min\\: %%.0lf
200GPRINT:maxds1:max\\: %%.0lf
201GPRINT:avgds1:avg\\: %%.0lf\\j
202DEF:ds0=%s:ds0:AVERAGE
203VDEF:lds0=ds0,LAST
204VDEF:minds0=ds0,MINIMUM
205VDEF:maxds0=ds0,MAXIMUM
206VDEF:avgds0=ds0,AVERAGE
207LINE2:ds0#3069DA:src pkg count
208GPRINT:lds0:cur\\: %%.0lf
209GPRINT:minds0:min\\: %%.0lf
210GPRINT:maxds0:max\\: %%.0lf
211GPRINT:avgds0:avg\\: %%.0lf\\j
212"""
213 % (rrd_file, rrd_file)
214 )
215 .strip()
216 .split("\n")
217 )
219 rrd_args += extra_args
220 try:
221 rrdtool.graph(*rrd_args)
222 except rrdtool.error as e:
223 print(
224 ("warning: graph: rrdtool error, skipping %s-%s.png: %s" % (name, graph, e))
225 )
228################################################################################
231def main() -> None:
232 global Cnf
234 Cnf = utils.get_conf()
235 Arguments = [
236 ("h", "help", "Graph::Options::Help"),
237 ("x", "extra-rrd", "Graph::Options::Extra-Rrd", "HasArg"),
238 ("r", "rrd", "Graph::Options::Rrd", "HasArg"),
239 ("i", "images", "Graph::Options::Images", "HasArg"),
240 ("n", "names", "Graph::Options::Names", "HasArg"),
241 ]
242 for i in ["help"]:
243 key = "Graph::Options::%s" % i
244 if key not in Cnf: 244 ↛ 242line 244 didn't jump to line 242 because the condition on line 244 was always true
245 Cnf[key] = "" # type: ignore[index]
247 apt_pkg.parse_commandline(Cnf, Arguments, sys.argv) # type: ignore[attr-defined]
249 Options = Cnf.subtree("Graph::Options") # type: ignore[attr-defined]
250 if Options["Help"]: 250 ↛ 253line 250 didn't jump to line 253 because the condition on line 250 was always true
251 usage()
253 names = []
255 if "Graph::Options::Names" in Cnf:
256 for i in Cnf["Graph::Options::Names"].split(","):
257 names.append(i)
258 elif "Graph::Names" in Cnf:
259 names = Cnf.value_list("Graph::Names")
260 else:
261 names = default_names
263 extra_rrdtool_args = []
265 if "Graph::Options::Extra-Rrd" in Cnf:
266 for i in Cnf["Graph::Options::Extra-Rrd"].split(","):
267 with open(i) as f:
268 extra_rrdtool_args.extend(f.read().strip().split("\n"))
269 elif "Graph::Extra-Rrd" in Cnf:
270 for i in Cnf.value_list("Graph::Extra-Rrd"):
271 with open(i) as f:
272 extra_rrdtool_args.extend(f.read().strip().split("\n"))
274 if "Graph::Options::Rrd" in Cnf:
275 rrd_dir = Cnf["Graph::Options::Rrd"]
276 elif "Dir::Rrd" in Cnf:
277 rrd_dir = Cnf["Dir::Rrd"]
278 else:
279 print("No directory to read RRD files from\n", file=sys.stderr)
280 sys.exit(1)
282 if "Graph::Options::Images" in Cnf:
283 image_dir = Cnf["Graph::Options::Images"]
284 else:
285 print("No directory to write graph images to\n", file=sys.stderr)
286 sys.exit(1)
288 for name in names:
289 stdargs = (rrd_dir, image_dir, name, extra_rrdtool_args)
290 graph(*stdargs, "day", "day", "now-1d")
291 graph(*stdargs, "week", "week", "now-1w")
292 graph(*stdargs, "month", "month", "now-1m")
293 graph(*stdargs, "year", "year", "now-1y")
294 graph(*stdargs, "5years", "5 years", "now-5y", True)
295 graph(*stdargs, "10years", "10 years", "now-10y", True)
298################################################################################
301if __name__ == "__main__":
302 main()