comparison mxtool/mx.py @ 6527:3c5b19e8f2a3

modified canonicalizeprojects to detect imprecise dependencies (e.g., A specifies that it depends on B but only imports packages from B's dependencies)
author Doug Simon <doug.simon@oracle.com>
date Mon, 08 Oct 2012 17:18:00 +0200
parents 534c45127aad
children 250babea75d5
comparison
equal deleted inserted replaced
6526:ee651c726397 6527:3c5b19e8f2a3
310 classes.append(pkg + '.' + e[:-len('.class')]) 310 classes.append(pkg + '.' + e[:-len('.class')])
311 elif e == basename + '.class': 311 elif e == basename + '.class':
312 classes.append(pkg + '.' + basename) 312 classes.append(pkg + '.' + basename)
313 return classes 313 return classes
314 314
315 def _init_packages_and_imports(self):
316 if not hasattr(self, '_defined_java_packages'):
317 packages = set()
318 depPackages = set()
319 for d in self.all_deps([], includeLibs=False, includeSelf=False):
320 depPackages.update(d.defined_java_packages())
321 imports = set()
322 importRe = re.compile(r'import\s+(?:static\s+)?([^;]+);')
323 for sourceDir in self.source_dirs():
324 for root, _, files in os.walk(sourceDir):
325 javaSources = [name for name in files if name.endswith('.java')]
326 if len(javaSources) != 0:
327 pkg = root[len(sourceDir) + 1:].replace(os.sep,'.')
328 if not pkg in depPackages:
329 packages.add(pkg)
330 else:
331 # A project imports a package already defined by one of it dependencies
332 imports.add(pkg)
333
334 for n in javaSources:
335 with open(join(root, n)) as fp:
336 content = fp.read()
337 imports.update(importRe.findall(content))
338 self._defined_java_packages = frozenset(packages)
339
340 importedPackages = set()
341 for imp in imports:
342 name = imp
343 while not name in depPackages and len(name) > 0:
344 lastDot = name.rfind('.')
345 if lastDot == -1:
346 name = None
347 break
348 name = name[0:lastDot]
349 if name is not None:
350 importedPackages.add(name)
351 self._imported_java_packages = frozenset(importedPackages)
352
353 def defined_java_packages(self):
354 """Get the immutable set of Java packages defined by the Java sources of this project"""
355 self._init_packages_and_imports()
356 return self._defined_java_packages
357
358 def imported_java_packages(self):
359 """Get the immutable set of Java packages defined by other Java projects that are
360 imported by the Java sources of this project."""
361 self._init_packages_and_imports()
362 return self._imported_java_packages
363
315 364
316 class Library(Dependency): 365 class Library(Dependency):
317 def __init__(self, suite, name, path, mustExist, urls, sourcePath, sourceUrls): 366 def __init__(self, suite, name, path, mustExist, urls, sourcePath, sourceUrls):
318 Dependency.__init__(self, suite, name) 367 Dependency.__init__(self, suite, name)
319 self.path = path.replace('/', os.sep) 368 self.path = path.replace('/', os.sep)
1438 if not exists(projectsFile): 1487 if not exists(projectsFile):
1439 continue 1488 continue
1440 with open(projectsFile) as f: 1489 with open(projectsFile) as f:
1441 out = StringIO.StringIO() 1490 out = StringIO.StringIO()
1442 pattern = re.compile('project@([^@]+)@dependencies=.*') 1491 pattern = re.compile('project@([^@]+)@dependencies=.*')
1492 lineNo = 1
1443 for line in f: 1493 for line in f:
1444 line = line.strip() 1494 line = line.strip()
1445 m = pattern.match(line) 1495 m = pattern.match(line)
1446 if m is None: 1496 if m is None:
1447 out.write(line + '\n') 1497 out.write(line + '\n')
1448 else: 1498 else:
1449 p = project(m.group(1)) 1499 p = project(m.group(1))
1500 ignoredDeps = set([name for name in p.deps if project(name, False) is not None])
1501 for pkg in p.imported_java_packages():
1502 for name in p.deps:
1503 dep = project(name, False)
1504 if dep is None:
1505 ignoredDeps.discard(name)
1506 else:
1507 if pkg in dep.defined_java_packages():
1508 ignoredDeps.discard(name)
1509 if len(ignoredDeps) != 0:
1510 candidates = set();
1511 # Compute dependencies based on projects required by p
1512 for d in sorted_deps():
1513 if not d.defined_java_packages().isdisjoint(p.imported_java_packages()):
1514 candidates.add(d)
1515 # Remove non-canonical candidates
1516 for c in list(candidates):
1517 candidates.difference_update(c.all_deps([], False, False))
1518 candidates = [d.name for d in candidates]
1519
1520 abort('{0}:{1}: {2} does not use any packages defined in these projects: {3}\nComputed project dependencies: {4}'.format(
1521 projectsFile, lineNo, p, ', '.join(ignoredDeps), ','.join(candidates)))
1522
1450 out.write('project@' + m.group(1) + '@dependencies=' + ','.join(p.canonical_deps()) + '\n') 1523 out.write('project@' + m.group(1) + '@dependencies=' + ','.join(p.canonical_deps()) + '\n')
1524 lineNo = lineNo + 1
1451 content = out.getvalue() 1525 content = out.getvalue()
1452 if update_file(projectsFile, content): 1526 if update_file(projectsFile, content):
1453 changedFiles += 1 1527 changedFiles += 1
1454 return changedFiles; 1528 return changedFiles;
1455 1529
2390 2464
2391 else: 2465 else:
2392 # no package description given 2466 # no package description given
2393 pass 2467 pass
2394 2468
2395 def packageinfo(args):
2396 """show Java packages defined by each project"""
2397
2398 parser = ArgumentParser(prog='packageinfo')
2399 parser.add_argument('-l', action='store_true', help='show packages one per line')
2400 parser.add_argument('filters', nargs=REMAINDER, metavar='filters...', help='substrings filtering the projects processed')
2401
2402 args = parser.parse_args(args)
2403 filters = args.filters
2404
2405 projects = sorted_deps()
2406
2407 projToPkgs = dict()
2408 pkgToProjs = dict()
2409 for p in projects:
2410 if len(filters) == 0 or len([f for f in filters if f in p.name]) != 0:
2411 pkgs = set()
2412 projToPkgs[p.name] = pkgs
2413 for sourceDir in p.source_dirs():
2414 for root, _, files in os.walk(sourceDir):
2415 if len([name for name in files if name.endswith('.java')]) != 0:
2416 pkg = root[len(sourceDir) + 1:].replace(os.sep,'.')
2417 pkgs.add(pkg)
2418 pkgToProjs.setdefault(pkg, set()).add(p.name)
2419
2420 for key,value in projToPkgs.iteritems():
2421 if args.l:
2422 print key, 'defines packages:'
2423 for v in value:
2424 print ' ', v
2425 else:
2426 print key, 'defines packages:', ', '.join(value)
2427
2428 for key,value in pkgToProjs.iteritems():
2429 if len(value) > 1:
2430 print 'package', key, 'is defined by multiple projects:', ', '.join(value)
2431
2432 def site(args): 2469 def site(args):
2433 """creates a website containing javadoc and the project dependency graph""" 2470 """creates a website containing javadoc and the project dependency graph"""
2434 2471
2435 parser = ArgumentParser(prog='site') 2472 parser = ArgumentParser(prog='site')
2436 parser.add_argument('-d', '--base', action='store', help='directory for generated site', required=True, metavar='<dir>') 2473 parser.add_argument('-d', '--base', action='store', help='directory for generated site', required=True, metavar='<dir>')
2634 'javap': [javap, ''], 2671 'javap': [javap, ''],
2635 'javadoc': [javadoc, '[options]'], 2672 'javadoc': [javadoc, '[options]'],
2636 'site': [site, '[options]'], 2673 'site': [site, '[options]'],
2637 'netbeansinit': [netbeansinit, ''], 2674 'netbeansinit': [netbeansinit, ''],
2638 'projects': [show_projects, ''], 2675 'projects': [show_projects, ''],
2639 'packageinfo': [packageinfo, '[options]'],
2640 } 2676 }
2641 2677
2642 _argParser = ArgParser() 2678 _argParser = ArgParser()
2643 2679
2644 def _findPrimarySuite(): 2680 def _findPrimarySuite():