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