| 1 | #!/usr/bin/python -OO |
1 | #!/usr/bin/python -O |
|
|
2 | |
|
|
3 | __revision__ = '$Revision: 1.8 $' |
|
|
4 | # $Source: /var/cvsroot/gentoo/src/packages/ebuilddb.py,v $ |
| 2 | |
5 | |
| 3 | import config |
6 | import config |
| 4 | import sys |
7 | import sys |
| 5 | import os |
8 | import os |
| 6 | import time |
9 | import time |
| 7 | import re |
|
|
| 8 | import changelogs |
10 | import changelogs |
| 9 | import MySQLdb |
11 | import MySQLdb |
| 10 | import md5 |
|
|
| 11 | |
|
|
| 12 | FINDVER = re.compile('-[0-9]') |
|
|
| 13 | |
12 | |
| 14 | def db_connect(): |
13 | def db_connect(): |
| 15 | return MySQLdb.connect(host = config.HOST, |
14 | return MySQLdb.connect(host = config.HOST, |
| 16 | user = config.USER, |
15 | user = config.USER, |
| 17 | passwd = config.PASSWD, |
16 | passwd = config.PASSWD, |
| 18 | db = config.DATABASE) |
17 | db = config.DATABASE) |
| 19 | |
18 | |
| 20 | def find_ebuilds(): |
19 | def find_ebuilds(): |
| 21 | #print "walking..." |
20 | #print "walking..." |
| 22 | ebuilds=[] |
|
|
| 23 | # yeah, i know we can os.path.walk, but this runs faster ;-) |
21 | # yeah, i know we can os.path.walk, but this runs faster ;-) |
| 24 | pipe = os.popen("find %s -name '*.ebuild'" % config.PORTAGE_DIR) |
22 | pipe = os.popen("find %s -name '*.ebuild'" % config.PORTAGE_DIR) |
| 25 | s = pipe.read() |
23 | s = pipe.read() |
| 26 | pipe.close() |
24 | pipe.close() |
| 27 | return s.split() |
25 | return s.split() |
| 28 | |
26 | |
| 29 | def parse_ebuild(s): |
27 | def parse_ebuild(s, pkgsplit): |
| 30 | """Parse ebuild info based on path name""" |
28 | """Parse ebuild info based on path name""" |
| 31 | parsed = {} |
29 | parsed = {} |
| 32 | s=s.split('/') |
30 | s=s.split('/') |
| 33 | parsed['category'] = s[-3] |
31 | parsed['category'] = s[-3] |
| 34 | package = s[-1].split('.ebuild')[0] |
32 | package = s[-1].split('.ebuild')[0] |
| 35 | pos=FINDVER.search(package).start() |
33 | pieces = pkgsplit(package) |
|
|
34 | if not pieces: |
|
|
35 | return None |
| 36 | parsed['name'] = package[:pos] |
36 | parsed['name'] = pieces[0] |
|
|
37 | if pieces[2] == 'r0': |
| 37 | parsed['version'] = package[pos+1:] |
38 | parsed['version'] = pieces[1] |
|
|
39 | else: |
|
|
40 | parsed['version'] = '-'.join(pieces[1:]) |
| 38 | |
41 | |
| 39 | return parsed |
42 | return parsed |
| 40 | |
43 | |
| 41 | def get_ebuild_record(db,ebinfo): |
44 | def get_ebuild_record(db,ebinfo): |
| 42 | c = db.cursor() |
45 | c = db.cursor() |
| 43 | query = ('SELECT * FROM ebuild WHERE category="%s" AND name="%s" ' |
46 | query = ('SELECT * FROM ebuild WHERE category="%s" AND name="%s" ' |
| 44 | 'AND version="%s" LIMIT 1' % (ebinfo['category'], ebinfo['name'], |
47 | 'AND version="%s" LIMIT 1' % (ebinfo['category'], ebinfo['name'], |
| 45 | ebinfo['version'])) |
48 | ebinfo['version'])) |
| 46 | c.execute(query) |
49 | c.execute(query) |
| 47 | result = c.fetchone() |
50 | result = c.fetchone() |
| 48 | return result |
51 | return result |
| … | |
… | |
| 51 | c = db.cursor() |
54 | c = db.cursor() |
| 52 | d = db.cursor() |
55 | d = db.cursor() |
| 53 | # update the package table |
56 | # update the package table |
| 54 | |
57 | |
| 55 | # this is a really ugly dict comprehension |
58 | # this is a really ugly dict comprehension |
| 56 | escaped = dict([(x,MySQLdb.escape_string(y)) for (x,y) in ebinfo.items()]) |
59 | escaped = {} |
| 57 | query="""REPLACE INTO package VALUES ("%(category)s","%(name)s",\ |
60 | for item in ebinfo.items(): |
| 58 | "%(homepage)s","%(description)s","%(license)s");""" % escaped |
61 | x, y = item |
|
|
62 | if type(y) is str: |
|
|
63 | y = MySQLdb.escape_string(y) |
|
|
64 | escaped[x] = y |
|
|
65 | |
|
|
66 | query=('INSERT INTO package SET category="%(category)s",name="%(name)s",' |
|
|
67 | 'homepage="%(homepage)s",description="%(description)s",' |
|
|
68 | 'license="%(license)s"' % escaped) |
|
|
69 | try: |
| 59 | c.execute(query) |
70 | c.execute(query) |
|
|
71 | except MySQLdb.cursors.IntegrityError: |
|
|
72 | # duplicate key (we hope) |
|
|
73 | query = ('REPLACE INTO package VALUES ("%(category)s","%(name)s",' |
|
|
74 | '"%(homepage)s","%(description)s","%(license)s",0)' % escaped) |
|
|
75 | c.execute(query) |
| 60 | |
76 | |
| 61 | # then add particular ebuild |
77 | # then add particular ebuild |
| 62 | query = ('INSERT INTO ebuild VALUES ("%(category)s","%(name)s",' |
78 | query = ('INSERT INTO ebuild VALUES ("%(category)s","%(name)s",' |
| 63 | '"%(version)s",%(time)s,"%(archs)s","%(changelog)s","")' |
79 | '"%(version)s",%(time)s,"%(archs)s","%(changelog)s","",%(masked)d)' |
| 64 | % escaped) |
80 | % escaped) |
| 65 | d.execute(query) |
81 | d.execute(query) |
| 66 | |
82 | |
| 67 | def update_ebuild_record(db,ebinfo): |
83 | def update_ebuild_record(db,ebinfo): |
| 68 | c = db.cursor() |
84 | c = db.cursor() |
| 69 | escaped = dict([(x,MySQLdb.escape_string(y)) for (x,y) in ebinfo.items()]) |
85 | escaped = {} |
|
|
86 | for item in ebinfo.items(): |
|
|
87 | x, y = item |
|
|
88 | if type(y) is str: |
|
|
89 | y = MySQLdb.escape_string(y) |
|
|
90 | escaped[x] = y |
|
|
91 | |
|
|
92 | query="""REPLACE INTO package VALUES ("%(category)s","%(name)s",\ |
|
|
93 | "%(homepage)s","%(description)s","%(license)s",0);""" % escaped |
|
|
94 | c.execute(query) |
|
|
95 | |
| 70 | query = ('UPDATE ebuild ' |
96 | query = ('UPDATE ebuild ' |
| 71 | 'SET when_found="%(time)s",' |
97 | 'SET when_found="%(time)s",' |
| 72 | 'arch="%(archs)s",' |
98 | 'arch="%(archs)s",' |
| 73 | 'changelog="%(changelog)s",' |
99 | 'changelog="%(changelog)s",' |
| 74 | 'prevarch="%(prevarch)s" ' |
100 | 'prevarch="%(prevarch)s", ' |
|
|
101 | 'is_masked=%(masked)d ' |
| 75 | 'WHERE category="%(category)s" ' |
102 | 'WHERE category="%(category)s" ' |
| 76 | 'AND name="%(name)s" ' |
103 | 'AND name="%(name)s" ' |
| 77 | 'AND version="%(version)s" ' % escaped) |
104 | 'AND version="%(version)s" ' % escaped) |
|
|
105 | try: |
| 78 | c.execute(query) |
106 | c.execute(query) |
|
|
107 | except MySQLdb.MySQLError, data: |
|
|
108 | print 'error occurred: ' |
|
|
109 | print 'query: %s' % query |
|
|
110 | print 'error: %s' % data |
|
|
111 | |
| 79 | |
112 | |
| 80 | def get_extended_info(ebuild): |
113 | def get_extended_info(ebuild): |
| 81 | filename = os.path.join(config.PORTAGE_DIR,'metadata/cache', |
114 | filename = os.path.join(config.PORTAGE_DIR,'metadata/cache', |
| 82 | ebuild['category'],'%s-%s' % (ebuild['name'],ebuild['version'])) |
115 | ebuild['category'],'%s-%s' % (ebuild['name'],ebuild['version'])) |
| 83 | try: |
116 | try: |
| 84 | lines = open(filename,'r').readlines() |
117 | lines = open(filename,'r').readlines() |
| 85 | except IOError: |
118 | except IOError: |
|
|
119 | print 'Error opening %s' % filename |
| 86 | lines = [] |
120 | lines = [] |
| 87 | lines = [ s.strip() for s in lines ] |
121 | lines = [ s.strip() for s in lines ] |
| 88 | try: |
122 | try: |
| 89 | ebuild['archs'] = lines[8] |
123 | ebuild['archs'] = ','.join(lines[8].split()) |
| 90 | except IndexError: |
124 | except IndexError: |
| 91 | ebuild['archs'] = '' |
125 | ebuild['archs'] = '' |
| 92 | try: |
126 | try: |
| 93 | ebuild['homepage'] = lines[5] |
127 | ebuild['homepage'] = lines[5] |
| 94 | except IndexError: |
128 | except IndexError: |
| … | |
… | |
| 104 | return ebuild |
138 | return ebuild |
| 105 | |
139 | |
| 106 | def get_mtime(s): |
140 | def get_mtime(s): |
| 107 | """Get mtime of file, return in format that MySQL would like""" |
141 | """Get mtime of file, return in format that MySQL would like""" |
| 108 | try: |
142 | try: |
| 109 | t = os.path.getmtime(s) |
143 | mtime = os.path.getmtime(s) |
| 110 | except: |
144 | except OSError: |
| 111 | return 'NULL' |
145 | return 'NULL' |
| 112 | str = time.strftime("%Y%m%d%H%M%S",time.localtime(t)) |
146 | strftime = time.strftime("%Y%m%d%H%M%S",time.localtime(mtime)) |
| 113 | return str |
147 | return strftime |
| 114 | |
148 | |
| 115 | def main(): |
149 | def is_masked(tree, ebuild): |
|
|
150 | """Return true if packages is masked in tree""" |
|
|
151 | return (not tree.visible(['%(category)s/%(name)s-%(version)s' % ebuild])) |
|
|
152 | |
|
|
153 | def main(argv = []): |
|
|
154 | """Main program entry point""" |
|
|
155 | # We need to "fake" as repoman so portage will ignore local system |
|
|
156 | # settings |
|
|
157 | os.environ['PORTAGE_CALLER'] = 'repoman' |
|
|
158 | |
| 116 | ebuilds = find_ebuilds() |
159 | ebuilds = find_ebuilds() |
| 117 | db = db_connect() |
160 | db = db_connect() |
| 118 | |
161 | |
|
|
162 | sys.path = ["/usr/lib/portage/pym"]+sys.path |
|
|
163 | import portage |
|
|
164 | # ... and then wait like a f**king hour |
|
|
165 | sys.path = sys.path[1:] |
|
|
166 | |
|
|
167 | # We want to use the base profile, not any system-specific one |
|
|
168 | p_config = portage.config(config_profile_path = '/usr/portage/profiles/base') |
|
|
169 | |
|
|
170 | tree = portage.portdbapi('/usr/portage', p_config) |
|
|
171 | |
|
|
172 | # are we updating the db or just rebuilding it? |
|
|
173 | rebuild = len(argv) == 2 and argv[1] == 'rebuild' |
| 119 | for s in ebuilds: |
174 | for s in ebuilds: |
| 120 | try: |
175 | fields = parse_ebuild(s, portage.pkgsplit) |
| 121 | fields = parse_ebuild(s) |
176 | if not fields: |
| 122 | except: |
|
|
| 123 | continue |
177 | continue |
| 124 | result = get_ebuild_record(db,fields) |
178 | result = get_ebuild_record(db,fields) |
| 125 | fields = get_extended_info(fields) |
179 | fields = get_extended_info(fields) |
| 126 | fields['changelog'] = changelogs.changelog('%s/ChangeLog' |
180 | fields['changelog'] = changelogs.changelog('%s/ChangeLog' |
| 127 | % os.path.dirname(s)) |
181 | % os.path.dirname(s)) |
| 128 | fields['time'] = get_mtime(s) |
182 | fields['time'] = get_mtime(s) |
|
|
183 | fields['masked'] = int(is_masked(tree, fields)) |
|
|
184 | |
| 129 | if not result: |
185 | if not (result or rebuild): |
| 130 | create_ebuild_record(db,fields) |
186 | create_ebuild_record(db,fields) |
|
|
187 | elif result and rebuild: |
|
|
188 | fields['prevarch'] = result[6] |
|
|
189 | if ' ' in fields['prevarch']: |
|
|
190 | # old db layout |
|
|
191 | fields['prevarch'] = ','.join(fields['prevarch'].split()) |
|
|
192 | fields['arch'] = [4] |
|
|
193 | update_ebuild_record(db, fields) |
|
|
194 | elif rebuild: |
|
|
195 | pass |
| 131 | elif result[4] != fields['archs']: |
196 | elif result[4].split(',') != fields['archs'].split(','): |
| 132 | #print 'ebuild archs=',fields['archs'] |
197 | #print 'ebuild archs=',fields['archs'] |
| 133 | #print 'db archs=',result[4] |
198 | #print 'db archs=',result[4] |
| 134 | #print |
199 | #print |
| 135 | # keywords change, update db |
200 | # keywords change, update db |
| 136 | fields['prevarch'] = result[4] |
201 | fields['prevarch'] = result[4] |
| 137 | update_ebuild_record(db,fields) |
202 | update_ebuild_record(db,fields) |
|
|
203 | elif result[7] != fields['masked']: |
|
|
204 | #print 'mask changed for %s-%s' % (fields['name'], fields['version']) |
|
|
205 | #print fields['masked'] |
|
|
206 | fields['prevarch'] = result[4] |
|
|
207 | update_ebuild_record(db,fields) |
| 138 | |
208 | |
| 139 | |
209 | db.commit() |
| 140 | if __name__ == '__main__': |
210 | if __name__ == '__main__': |
| 141 | main() |
211 | sys.exit(main(sys.argv)) |