3 """ Various statistical pr0nography fun and games """
4 # Copyright (C) 2000, 2001, 2002, 2003, 2006 James Troup <james@nocrew.org>
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.
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.
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
20 ################################################################################
22 # <aj> can we change the standards instead?
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
29 # [aj's attempt to avoid ABI changes for released architecture(s)]
31 ################################################################################
36 from daklib import utils
37 from daklib.dbconn import DBConn, get_suite_architectures, Suite, Architecture, \
40 ################################################################################
44 ################################################################################
46 def usage(exit_code=0):
47 print """Usage: dak stats MODE
50 -h, --help show this help and exit.
52 The following MODEs are available:
54 arch-space - displays space used by each architecture
55 pkg-nums - displays the number of packages by suite/architecture
56 daily-install - displays daily install stats suitable for graphing
60 ################################################################################
62 def per_arch_space_use():
63 session = DBConn().session()
64 q = session.execute("""
65 SELECT a.arch_string as Architecture, sum(f.size) AS sum
66 FROM files f, binaries b, architecture a
67 WHERE a.id=b.architecture AND f.id=b.file
68 GROUP BY a.arch_string ORDER BY sum""").fetchall()
70 print "%-15.15s %s" % (j[0], j[1])
72 q = session.execute("SELECT sum(size) FROM files WHERE filename ~ '.(diff.gz|tar.gz|dsc)$'").fetchall()
73 print "%-15.15s %s" % ("Source", q[0][0])
75 ################################################################################
77 def daily_install_stats():
79 f = utils.open_file("2001-11")
80 for line in f.readlines():
81 split = line.strip().split('|')
83 if program != "katie" and program != "process-accepted":
86 if action != "installing changes" and action != "installed":
89 if not stats.has_key(date):
91 stats[date]["packages"] = 0
92 stats[date]["size"] = 0.0
93 if action == "installing changes":
94 stats[date]["packages"] += 1
95 elif action == "installed":
96 stats[date]["size"] += float(split[5])
101 packages = stats[date]["packages"]
102 size = int(stats[date]["size"] / 1024.0 / 1024.0)
103 print "%s %s %s" % (date, packages, size)
105 ################################################################################
115 def suite_sort(a, b):
116 if Cnf.has_key("Suite::%s::Priority" % (a)):
117 a_priority = int(Cnf["Suite::%s::Priority" % (a)])
120 if Cnf.has_key("Suite::%s::Priority" % (b)):
121 b_priority = int(Cnf["Suite::%s::Priority" % (b)])
124 return cmp(a_priority, b_priority)
126 def output_format(suite):
128 for word in suite.split("-"):
129 output_suite.append(word[0])
130 return "-".join(output_suite)
132 def number_of_packages():
138 session = DBConn().session()
139 # Build up suite mapping
140 for i in session.query(Suite).all():
141 suites[i.suite_id] = i.suite_name
142 suite_ids[i.suite_name] = i.suite_id
143 # Build up architecture mapping
144 for i in session.query(Architecture).all():
145 arches[i.arch_id] = i.arch_string
146 arch_ids[i.arch_string] = i.arch_id
147 # Pre-create the dictionary
148 for suite_id in suites.keys():
150 for arch_id in arches.keys():
151 d[suite_id][arch_id] = 0
152 # Get the raw data for binaries
153 # Simultate 'GROUP by suite, architecture' with a dictionary
154 # XXX: Why don't we just get the DB to do this?
155 for i in session.execute("""SELECT suite, architecture, COUNT(suite)
156 FROM bin_associations
157 LEFT JOIN binaries ON bin = binaries.id
158 GROUP BY suite, architecture""").fetchall():
159 d[ i[0] ][ i[1] ] = i[2]
160 # Get the raw data for source
161 arch_id = arch_ids["source"]
162 for i in session.execute('SELECT suite, COUNT(suite) FROM src_associations GROUP BY suite').fetchall():
163 (suite_id, count) = i
164 d[suite_id][arch_id] = d[suite_id][arch_id] + count
167 suite_list = suites.values()
168 suite_list.sort(suite_sort)
171 for suite in suite_list:
172 suite_id = suite_ids[suite]
173 suite_arches[suite_id] = {}
174 for arch in get_suite_architectures(suite):
175 suite_arches[suite_id][arch.arch_string] = ""
176 suite_id_list.append(suite_id)
177 output_list = [ output_format(i) for i in suite_list ]
178 longest_suite = longest(output_list)
179 arch_list = arches.values()
181 longest_arch = longest(arch_list)
183 output = (" "*longest_arch) + " |"
184 for suite in output_list:
185 output = output + suite.center(longest_suite)+" |"
186 output = output + "\n"+(len(output)*"-")+"\n"
188 arch_list = arches.values()
190 longest_arch = longest(arch_list)
191 for arch in arch_list:
192 arch_id = arch_ids[arch]
193 output = output + arch.center(longest_arch)+" |"
194 for suite_id in suite_id_list:
195 if suite_arches[suite_id].has_key(arch):
196 count = "%d" % d[suite_id][arch_id]
199 output = output + count.rjust(longest_suite)+" |"
200 output = output + "\n"
203 ################################################################################
208 Cnf = utils.get_conf()
209 Arguments = [('h',"help","Stats::Options::Help")]
211 if not Cnf.has_key("Stats::Options::%s" % (i)):
212 Cnf["Stats::Options::%s" % (i)] = ""
214 args = apt_pkg.ParseCommandLine(Cnf, Arguments, sys.argv)
216 Options = Cnf.SubTree("Stats::Options")
221 utils.warn("dak stats requires a MODE argument")
224 utils.warn("dak stats accepts only one MODE argument")
226 mode = args[0].lower()
228 if mode == "arch-space":
230 elif mode == "pkg-nums":
232 elif mode == "daily-install":
233 daily_install_stats()
235 utils.warn("unknown mode '%s'" % (mode))
238 ################################################################################
240 if __name__ == '__main__':