Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(493)

Side by Side Diff: cros_extract_deps

Issue 6682007: This cros_extract_deps is broken and superceded by chromite/bin/cros_extract_deps (Closed) Base URL: ssh://git@gitrw.chromium.org:9222/crosutils.git@master
Patch Set: Created 9 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 #!/usr/bin/python
2 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
5
6 """Extract dependency tree out of emerge and make it accessible and useful."""
7
8 import json
9 import optparse
10 import re
11 import shutil
12 import subprocess
13 import sys
14 import tempfile
15 import time
16
17 class ParseException(Exception):
18 def __init__(self, reason):
19 Exception.__init__(self)
20 self.reason = reason
21
22 def __str__(self):
23 return self.reason
24
25
26 class SetEncoder(json.JSONEncoder):
27 """Custom json encoder class, doesn't hate set types."""
28 def default(self, o):
29 if isinstance(o, set):
30 return list(o)
31 return json.JSONEncoder.default(self, o)
32
33
34 def GetDepLinesFromPortage(options, packages):
35 """Get dependency lines out of emerge.
36
37 This calls emerge -p --debug and extracts the 'digraph' lines which detail
38 the dependencies."
39 """
40 # Use a temporary directory for $ROOT, so that emerge will consider all
41 # packages regardless of current build status.
42 temp_dir = tempfile.mkdtemp()
43
44 emerge = 'emerge'
45 if options.board:
46 emerge += '-' + options.board
47 cmdline = [emerge, '-p', '--debug', '--root=' + temp_dir]
48 if not options.build_time:
49 cmdline.append('--root-deps=rdeps')
50 cmdline += packages
51
52 # Store output in a temp file as it is too big for a unix pipe.
53 stderr_buffer = tempfile.TemporaryFile()
54
55 depsproc = subprocess.Popen(cmdline, stderr=stderr_buffer,
56 stdout=open('/dev/null', 'w'), bufsize=64*1024)
57 depsproc.wait()
58
59 subprocess.check_call(['sudo', 'rm', '-rf', temp_dir])
60
61 assert(depsproc.returncode==0)
62
63 stderr_buffer.seek(0)
64 lines = []
65 output = False
66 for line in stderr_buffer:
67 stripped = line.rstrip()
68 if output:
69 lines.append(stripped)
70 if stripped == 'digraph:':
71 output = True
72
73 if not output:
74 raise ParseException('Could not find digraph in output from emerge.')
75
76 return lines
77
78
79 def ParseDepLines(lines):
80 """Parse the dependency lines into a dependency tree.
81
82 This parses the digraph lines, extract the information and builds the
83 dependency tree (doubly-linked)."
84 """
85 # The digraph output looks like this:
86
87 # hard-host-depends depends on
88 # ('ebuild', '/tmp/root', 'dev-lang/swig-1.3.36', 'merge') depends on
89 # ('ebuild', '/tmp/root', 'dev-lang/perl-5.8.8-r8', 'merge') (buildtime)
90 # ('binary', '/tmp/root', 'sys-auth/policykit-0.9-r1', 'merge') depends on
91 # ('binary', '/tmp/root', 'x11-misc/xbitmaps-1.1.0', 'merge') (no children)
92
93 re_deps = re.compile(r'(?P<indent>\W*)\(\'(?P<package_type>\w+)\','
94 r' \'(?P<destination>[\w/\.-]+)\','
95 r' \'(?P<category>[\w\+-]+)/(?P<package_name>[\w\+-]+)-'
96 r'(?P<version>\d+[\w\.-]*)\', \'(?P<action>\w+)\'\)'
97 r' (?P<dep_type>(depends on|\(.*\)))')
98 re_seed_deps = re.compile(r'(?P<package_name>[\w\+/-]+) depends on')
99 # Packages that fail the previous regex should match this one and be noted as
100 # failure.
101 re_failed = re.compile(r'.*depends on.*')
102
103 deps_map = {}
104
105 current_package = None
106 for line in lines:
107 deps_match = re_deps.match(line)
108 if deps_match:
109 package_name = deps_match.group('package_name')
110 category = deps_match.group('category')
111 indent = deps_match.group('indent')
112 action = deps_match.group('action')
113 dep_type = deps_match.group('dep_type')
114 version = deps_match.group('version')
115
116 # Pretty print what we've captured.
117 full_package_name = '%s/%s-%s' % (category, package_name, version)
118
119 try:
120 package_info = deps_map[full_package_name]
121 except KeyError:
122 package_info = {
123 'deps': set(),
124 'rev_deps': set(),
125 'name': package_name,
126 'category': category,
127 'version': version,
128 'full_name': full_package_name,
129 'action': action,
130 }
131 deps_map[full_package_name] = package_info
132
133 if not indent:
134 if dep_type == 'depends on':
135 current_package = package_info
136 else:
137 current_package = None
138 else:
139 if not current_package:
140 raise ParseException('Found a dependency without parent:\n' + line)
141 if dep_type == 'depend on':
142 raise ParseException('Found extra levels of dependencies:\n' + line)
143 current_package['deps'].add(full_package_name)
144 package_info['rev_deps'].add(current_package['full_name'])
145
146 else:
147 seed_match = re_seed_deps.match(line)
148 if seed_match:
149 package_name = seed_match.group('package_name')
150
151 try:
152 current_package = deps_map[package_name]
153 except KeyError:
154 current_package = {
155 'deps': set(),
156 'rev_deps': set(),
157 'name': package_name,
158 'category': '',
159 'version': '',
160 'full_name': package_name,
161 'action': 'seed',
162 }
163 deps_map[package_name] = current_package
164
165 else:
166 # Is this a package that failed to match our huge regex?
167 failed_match = re_failed.match(line)
168 if failed_match:
169 raise ParseException('Couldn\'t understand line:\n' + line)
170
171 return deps_map
172
173
174 def main():
175 parser = optparse.OptionParser(usage='usage: %prog [options] package1 ...')
176 parser.add_option('-b', '--board',
177 help='The board to extract dependencies from.')
178 parser.add_option('-B', '--build-time', action='store_true',
179 dest='build_time',
180 help='Also extract build-time dependencies.')
181 parser.add_option('-o', '--output', default=None,
182 help='Output file.')
183 (options, packages) = parser.parse_args()
184 if not packages:
185 parser.print_usage()
186 sys.exit(1)
187
188 lines = GetDepLinesFromPortage(options, packages)
189 deps_map = ParseDepLines(lines)
190 output = json.dumps(deps_map, sort_keys=True, indent=2, cls=SetEncoder)
191 if options.output:
192 output_file = open(options.output, 'w')
193 output_file.write(output)
194 output_file.close()
195 else:
196 print output
197
198
199 if __name__ == '__main__':
200 main()
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698