]> git.decadent.org.uk Git - dak.git/blob - dak/stats.py
Merge remote-tracking branch 'ansgar/pu/wheezy' into merge
[dak.git] / dak / stats.py
1 #!/usr/bin/env python
2
3 """ Various statistical pr0nography fun and games """
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 # <aj>    can we change the standards instead?
23 # <neuro> standards?
24 # <aj>    whatever we're not conforming to
25 # <aj>    if there's no written standard, why don't we declare linux as
26 #         the defacto standard
27 # <aj>    go us!
28
29 # [aj's attempt to avoid ABI changes for released architecture(s)]
30
31 ################################################################################
32
33 import sys
34 import apt_pkg
35
36 from daklib import utils
37 from daklib.dbconn import DBConn, get_suite_architectures, Suite, Architecture
38
39 ################################################################################
40
41 Cnf = None
42
43 ################################################################################
44
45 def usage(exit_code=0):
46     print """Usage: dak stats MODE
47 Print various stats.
48
49   -h, --help                show this help and exit.
50
51 The following MODEs are available:
52
53   arch-space    - displays space used by each architecture
54   pkg-nums      - displays the number of packages by suite/architecture
55   daily-install - displays daily install stats suitable for graphing
56 """
57     sys.exit(exit_code)
58
59 ################################################################################
60
61 def per_arch_space_use():
62     session = DBConn().session()
63     q = session.execute("""
64 SELECT a.arch_string as Architecture, sum(f.size) AS sum
65   FROM files f, binaries b, architecture a
66   WHERE a.id=b.architecture AND f.id=b.file
67   GROUP BY a.arch_string ORDER BY sum""").fetchall()
68     for j in q:
69         print "%-15.15s %s" % (j[0], j[1])
70     print
71     q = session.execute("SELECT sum(size) FROM files WHERE filename ~ '.(diff.gz|tar.gz|dsc)$'").fetchall()
72     print "%-15.15s %s" % ("Source", q[0][0])
73
74 ################################################################################
75
76 def daily_install_stats():
77     stats = {}
78     f = utils.open_file("2001-11")
79     for line in f.readlines():
80         split = line.strip().split('|')
81         program = split[1]
82         if program != "katie" and program != "process-accepted":
83             continue
84         action = split[2]
85         if action != "installing changes" and action != "installed":
86             continue
87         date = split[0][:8]
88         if not stats.has_key(date):
89             stats[date] = {}
90             stats[date]["packages"] = 0
91             stats[date]["size"] = 0.0
92         if action == "installing changes":
93             stats[date]["packages"] += 1
94         elif action == "installed":
95             stats[date]["size"] += float(split[5])
96
97     dates = stats.keys()
98     dates.sort()
99     for date in dates:
100         packages = stats[date]["packages"]
101         size = int(stats[date]["size"] / 1024.0 / 1024.0)
102         print "%s %s %s" % (date, packages, size)
103
104 ################################################################################
105
106 def longest(list):
107     longest = 0
108     for i in list:
109         l = len(i)
110         if l > longest:
111             longest = l
112     return longest
113
114 def output_format(suite):
115     output_suite = []
116     for word in suite.split("-"):
117         output_suite.append(word[0])
118     return "-".join(output_suite)
119
120 def number_of_packages():
121     arches = {}
122     arch_ids = {}
123     suites = {}
124     suite_ids = {}
125     d = {}
126     session = DBConn().session()
127     # Build up suite mapping
128     for i in session.query(Suite).all():
129         suites[i.suite_id] = i.suite_name
130         suite_ids[i.suite_name] = i.suite_id
131     # Build up architecture mapping
132     for i in session.query(Architecture).all():
133         arches[i.arch_id] = i.arch_string
134         arch_ids[i.arch_string] = i.arch_id
135     # Pre-create the dictionary
136     for suite_id in suites.keys():
137         d[suite_id] = {}
138         for arch_id in arches.keys():
139             d[suite_id][arch_id] = 0
140     # Get the raw data for binaries
141     # Simultate 'GROUP by suite, architecture' with a dictionary
142     # XXX: Why don't we just get the DB to do this?
143     for i in session.execute("""SELECT suite, architecture, COUNT(suite)
144                                 FROM bin_associations
145                            LEFT JOIN binaries ON bin = binaries.id
146                             GROUP BY suite, architecture""").fetchall():
147         d[ i[0] ][ i[1] ] = i[2]
148     # Get the raw data for source
149     arch_id = arch_ids["source"]
150     for i in session.execute('SELECT suite, COUNT(suite) FROM src_associations GROUP BY suite').fetchall():
151         (suite_id, count) = i
152         d[suite_id][arch_id] = d[suite_id][arch_id] + count
153     ## Print the results
154     # Setup
155     suite_list = suites.values()
156     suite_id_list = []
157     suite_arches = {}
158     for suite in suite_list:
159         suite_id = suite_ids[suite]
160         suite_arches[suite_id] = {}
161         for arch in get_suite_architectures(suite):
162             suite_arches[suite_id][arch.arch_string] = ""
163         suite_id_list.append(suite_id)
164     output_list = [ output_format(i) for i in suite_list ]
165     longest_suite = longest(output_list)
166     arch_list = arches.values()
167     arch_list.sort()
168     longest_arch = longest(arch_list)
169     # Header
170     output = (" "*longest_arch) + " |"
171     for suite in output_list:
172         output = output + suite.center(longest_suite)+" |"
173     output = output + "\n"+(len(output)*"-")+"\n"
174     # per-arch data
175     arch_list = arches.values()
176     arch_list.sort()
177     longest_arch = longest(arch_list)
178     for arch in arch_list:
179         arch_id = arch_ids[arch]
180         output = output + arch.center(longest_arch)+" |"
181         for suite_id in suite_id_list:
182             if suite_arches[suite_id].has_key(arch):
183                 count = "%d" % d[suite_id][arch_id]
184             else:
185                 count = "-"
186             output = output + count.rjust(longest_suite)+" |"
187         output = output + "\n"
188     print output
189
190 ################################################################################
191
192 def main ():
193     global Cnf
194
195     Cnf = utils.get_conf()
196     Arguments = [('h',"help","Stats::Options::Help")]
197     for i in [ "help" ]:
198         if not Cnf.has_key("Stats::Options::%s" % (i)):
199             Cnf["Stats::Options::%s" % (i)] = ""
200
201     args = apt_pkg.parse_commandline(Cnf, Arguments, sys.argv)
202
203     Options = Cnf.subtree("Stats::Options")
204     if Options["Help"]:
205         usage()
206
207     if len(args) < 1:
208         utils.warn("dak stats requires a MODE argument")
209         usage(1)
210     elif len(args) > 1:
211         utils.warn("dak stats accepts only one MODE argument")
212         usage(1)
213     mode = args[0].lower()
214
215     if mode == "arch-space":
216         per_arch_space_use()
217     elif mode == "pkg-nums":
218         number_of_packages()
219     elif mode == "daily-install":
220         daily_install_stats()
221     else:
222         utils.warn("unknown mode '%s'" % (mode))
223         usage(1)
224
225 ################################################################################
226
227 if __name__ == '__main__':
228     main()