comparison mxtool/mx.py @ 21180:c2f5dc4418d0

Merge
author Tom Rodriguez <tom.rodriguez@oracle.com>
date Sat, 02 May 2015 14:40:49 -0700
parents f383ff4c9af8
children fbe449ca9707
comparison
equal deleted inserted replaced
21179:fab864299d96 21180:c2f5dc4418d0
45 from collections import Callable 45 from collections import Callable
46 from threading import Thread 46 from threading import Thread
47 from argparse import ArgumentParser, REMAINDER 47 from argparse import ArgumentParser, REMAINDER
48 from os.path import join, basename, dirname, exists, getmtime, isabs, expandvars, isdir, isfile 48 from os.path import join, basename, dirname, exists, getmtime, isabs, expandvars, isdir, isfile
49 49
50 # needed to work around https://bugs.python.org/issue1927
51 import readline
52 #then make pylint happy..
53 readline.get_line_buffer()
54
50 # Support for Python 2.6 55 # Support for Python 2.6
51 def check_output(*popenargs, **kwargs): 56 def check_output(*popenargs, **kwargs):
52 process = subprocess.Popen(stdout=subprocess.PIPE, *popenargs, **kwargs) 57 process = subprocess.Popen(stdout=subprocess.PIPE, *popenargs, **kwargs)
53 output, _ = process.communicate() 58 output, _ = process.communicate()
54 retcode = process.poll() 59 retcode = process.poll()
92 _suites = dict() 97 _suites = dict()
93 _annotationProcessors = None 98 _annotationProcessors = None
94 _primary_suite_path = None 99 _primary_suite_path = None
95 _primary_suite = None 100 _primary_suite = None
96 _opts = None 101 _opts = None
97 _java_homes = None 102 _extra_java_homes = []
103 _default_java_home = None
98 _warn = False 104 _warn = False
99 105
100 """ 106 """
101 A distribution is a jar or zip file containing the output from one or more Java projects. 107 A distribution is a jar or zip file containing the output from one or more Java projects.
102 """ 108 """
210 p = dep 216 p = dep
211 217
212 if self.javaCompliance: 218 if self.javaCompliance:
213 if p.javaCompliance > self.javaCompliance: 219 if p.javaCompliance > self.javaCompliance:
214 abort("Compliance level doesn't match: Distribution {0} requires {1}, but {2} is {3}.".format(self.name, self.javaCompliance, p.name, p.javaCompliance)) 220 abort("Compliance level doesn't match: Distribution {0} requires {1}, but {2} is {3}.".format(self.name, self.javaCompliance, p.name, p.javaCompliance))
215
216 # skip a Java project if its Java compliance level is "higher" than the configured JDK
217 jdk = java(p.javaCompliance)
218 assert jdk
219 221
220 logv('[' + self.path + ': adding project ' + p.name + ']') 222 logv('[' + self.path + ': adding project ' + p.name + ']')
221 outputDir = p.output_dir() 223 outputDir = p.output_dir()
222 for root, _, files in os.walk(outputDir): 224 for root, _, files in os.walk(outputDir):
223 relpath = root[len(outputDir) + 1:] 225 relpath = root[len(outputDir) + 1:]
304 306
305 # The annotation processors defined by this project 307 # The annotation processors defined by this project
306 self.definedAnnotationProcessors = None 308 self.definedAnnotationProcessors = None
307 self.definedAnnotationProcessorsDist = None 309 self.definedAnnotationProcessorsDist = None
308 310
309
310 # Verify that a JDK exists for this project if its compliance level is
311 # less than the compliance level of the default JDK
312 jdk = java(self.javaCompliance)
313 if jdk is None and self.javaCompliance < java().javaCompliance:
314 abort('Cannot find ' + str(self.javaCompliance) + ' JDK required by ' + name + '. ' +
315 'Specify it with --extra-java-homes option or EXTRA_JAVA_HOMES environment variable.')
316
317 # Create directories for projects that don't yet exist 311 # Create directories for projects that don't yet exist
318 if not exists(d): 312 if not exists(d):
319 os.mkdir(d) 313 os.mkdir(d)
320 for s in self.source_dirs(): 314 for s in self.source_dirs():
321 if not exists(s): 315 if not exists(s):
753 def get_path(self, resolve): 747 def get_path(self, resolve):
754 path = _make_absolute(self.path, self.suite.dir) 748 path = _make_absolute(self.path, self.suite.dir)
755 sha1path = path + '.sha1' 749 sha1path = path + '.sha1'
756 750
757 includedInJDK = getattr(self, 'includedInJDK', None) 751 includedInJDK = getattr(self, 'includedInJDK', None)
752 # TODO since we don't know which JDK will be used, this check is dubious
758 if includedInJDK and java().javaCompliance >= JavaCompliance(includedInJDK): 753 if includedInJDK and java().javaCompliance >= JavaCompliance(includedInJDK):
759 return None 754 return None
760 755
761 bootClassPathAgent = getattr(self, 'bootClassPathAgent').lower() == 'true' if hasattr(self, 'bootClassPathAgent') else False 756 bootClassPathAgent = getattr(self, 'bootClassPathAgent').lower() == 'true' if hasattr(self, 'bootClassPathAgent') else False
762 757
1228 if not path: 1223 if not path:
1229 logv('[omitting optional library {0} as {1} does not exist]'.format(d, d.path)) 1224 logv('[omitting optional library {0} as {1} does not exist]'.format(d, d.path))
1230 del _libs[d.name] 1225 del _libs[d.name]
1231 self.libs.remove(d) 1226 self.libs.remove(d)
1232 elif d.isProject(): 1227 elif d.isProject():
1233 if java(d.javaCompliance) is None: 1228 if java(d.javaCompliance, cancel='some projects will be omitted which may result in errrors') is None:
1234 logv('[omitting project {0} as Java compliance {1} cannot be satisfied by configured JDKs]'.format(d, d.javaCompliance)) 1229 logv('[omitting project {0} as Java compliance {1} cannot be satisfied by configured JDKs]'.format(d, d.javaCompliance))
1235 del _projects[d.name] 1230 del _projects[d.name]
1236 self.projects.remove(d) 1231 self.projects.remove(d)
1237 else: 1232 else:
1238 for name in list(d.deps): 1233 for name in list(d.deps):
1654 deps = [] 1649 deps = []
1655 for p in projects: 1650 for p in projects:
1656 p.all_deps(deps, includeLibs=includeLibs, includeJreLibs=includeJreLibs, includeAnnotationProcessors=includeAnnotationProcessors) 1651 p.all_deps(deps, includeLibs=includeLibs, includeJreLibs=includeJreLibs, includeAnnotationProcessors=includeAnnotationProcessors)
1657 return deps 1652 return deps
1658 1653
1659 def _handle_lookup_java_home(jdk):
1660 return _handle_lookup_jdk(jdk, 'JAVA_HOME', '--java-home', False)
1661
1662 def _handle_lookup_extra_java_homes(jdk):
1663 return _handle_lookup_jdk(jdk, 'EXTRA_JAVA_HOMES', '--extra-java-homes', True)
1664
1665 def _handle_lookup_jdk(jdk, varName, flagName, allowMultiple):
1666 if jdk != None and jdk != '':
1667 return jdk
1668 jdk = os.environ.get(varName)
1669 if jdk != None and jdk != '':
1670 return jdk
1671
1672 if not sys.stdout.isatty():
1673 abort('Could not find bootstrap {0}. Use {1} option or ensure {2} environment variable is set.'.format(varName, flagName, varName))
1674
1675 candidateJdks = []
1676 if get_os() == 'darwin':
1677 base = '/Library/Java/JavaVirtualMachines'
1678 if exists(base):
1679 candidateJdks = [join(base, n, 'Contents/Home') for n in os.listdir(base) if exists(join(base, n, 'Contents/Home'))]
1680 elif get_os() == 'linux':
1681 base = '/usr/lib/jvm'
1682 if exists(base):
1683 candidateJdks = [join(base, n) for n in os.listdir(base) if exists(join(base, n, 'jre/lib/rt.jar'))]
1684 base = '/usr/java'
1685 if exists(base):
1686 candidateJdks += [join(base, n) for n in os.listdir(base) if exists(join(base, n, 'jre/lib/rt.jar'))]
1687 elif get_os() == 'solaris':
1688 base = '/usr/jdk/instances'
1689 if exists(base):
1690 candidateJdks = [join(base, n) for n in os.listdir(base) if exists(join(base, n, 'jre/lib/rt.jar'))]
1691 elif get_os() == 'windows':
1692 base = r'C:\Program Files\Java'
1693 if exists(base):
1694 candidateJdks = [join(base, n) for n in os.listdir(base) if exists(join(base, n, r'jre\lib\rt.jar'))]
1695
1696 javaHome = None
1697 if len(candidateJdks) != 0:
1698 log('Missing value for {0}.'.format(varName))
1699 javaHome = select_items(candidateJdks + ['<other>'], allowMultiple=allowMultiple)
1700 if javaHome == '<other>':
1701 javaHome = None
1702 if javaHome != None and allowMultiple:
1703 javaHome = os.pathsep.join(javaHome)
1704
1705 while javaHome is None:
1706 javaHome = raw_input('Enter path of JDK for {0}: '.format(varName))
1707 rtJarPath = join(javaHome, 'jre', 'lib', 'rt.jar')
1708 if not exists(rtJarPath):
1709 log('Does not appear to be a valid JDK as ' + rtJarPath + ' does not exist')
1710 javaHome = None
1711 else:
1712 break
1713
1714 envPath = join(_primary_suite.mxDir, 'env')
1715 if ask_yes_no('Persist this setting by adding "{0}={1}" to {2}'.format(varName, javaHome, envPath), 'y'):
1716 with open(envPath, 'a') as fp:
1717 print >> fp, varName + '=' + javaHome
1718
1719 return javaHome
1720
1721 class ArgParser(ArgumentParser): 1654 class ArgParser(ArgumentParser):
1722 # Override parent to append the list of available commands 1655 # Override parent to append the list of available commands
1723 def format_help(self): 1656 def format_help(self):
1724 return ArgumentParser.format_help(self) + _format_commands() 1657 return ArgumentParser.format_help(self) + _format_commands()
1725 1658
1742 self.add_argument('--Jp', action='append', dest='java_args_pfx', help='prefix Java VM arguments (e.g. --Jp @-dsa)', metavar='@<args>', default=[]) 1675 self.add_argument('--Jp', action='append', dest='java_args_pfx', help='prefix Java VM arguments (e.g. --Jp @-dsa)', metavar='@<args>', default=[])
1743 self.add_argument('--Ja', action='append', dest='java_args_sfx', help='suffix Java VM arguments (e.g. --Ja @-dsa)', metavar='@<args>', default=[]) 1676 self.add_argument('--Ja', action='append', dest='java_args_sfx', help='suffix Java VM arguments (e.g. --Ja @-dsa)', metavar='@<args>', default=[])
1744 self.add_argument('--user-home', help='users home directory', metavar='<path>', default=os.path.expanduser('~')) 1677 self.add_argument('--user-home', help='users home directory', metavar='<path>', default=os.path.expanduser('~'))
1745 self.add_argument('--java-home', help='primary JDK directory (must be JDK 7 or later)', metavar='<path>') 1678 self.add_argument('--java-home', help='primary JDK directory (must be JDK 7 or later)', metavar='<path>')
1746 self.add_argument('--extra-java-homes', help='secondary JDK directories separated by "' + os.pathsep + '"', metavar='<path>') 1679 self.add_argument('--extra-java-homes', help='secondary JDK directories separated by "' + os.pathsep + '"', metavar='<path>')
1680 self.add_argument('--strict-compliance', action='store_true', dest='strict_compliance', help='Projects of a certain compliance will only be built with a JDK of this exact compliance', default=False)
1747 self.add_argument('--ignore-project', action='append', dest='ignored_projects', help='name of project to ignore', metavar='<name>', default=[]) 1681 self.add_argument('--ignore-project', action='append', dest='ignored_projects', help='name of project to ignore', metavar='<name>', default=[])
1748 self.add_argument('--kill-with-sigquit', action='store_true', dest='killwithsigquit', help='send sigquit first before killing child processes') 1682 self.add_argument('--kill-with-sigquit', action='store_true', dest='killwithsigquit', help='send sigquit first before killing child processes')
1749 if get_os() != 'windows': 1683 if get_os() != 'windows':
1750 # Time outs are (currently) implemented with Unix specific functionality 1684 # Time outs are (currently) implemented with Unix specific functionality
1751 self.add_argument('--timeout', help='timeout (in seconds) for command', type=int, default=0, metavar='<secs>') 1685 self.add_argument('--timeout', help='timeout (in seconds) for command', type=int, default=0, metavar='<secs>')
1767 opts.__dict__.setdefault('ptimeout', 0) 1701 opts.__dict__.setdefault('ptimeout', 0)
1768 1702
1769 if opts.very_verbose: 1703 if opts.very_verbose:
1770 opts.verbose = True 1704 opts.verbose = True
1771 1705
1772 opts.java_home = _handle_lookup_java_home(opts.java_home)
1773 opts.extra_java_homes = _handle_lookup_extra_java_homes(opts.extra_java_homes)
1774
1775 if opts.user_home is None or opts.user_home == '': 1706 if opts.user_home is None or opts.user_home == '':
1776 abort('Could not find user home. Use --user-home option or ensure HOME environment variable is set.') 1707 abort('Could not find user home. Use --user-home option or ensure HOME environment variable is set.')
1777 1708
1778 os.environ['JAVA_HOME'] = opts.java_home 1709 if opts.java_home:
1710 os.environ['JAVA_HOME'] = opts.java_home
1779 os.environ['HOME'] = opts.user_home 1711 os.environ['HOME'] = opts.user_home
1712
1713 if os.environ.get('STRICT_COMPLIANCE'):
1714 _opts.strict_compliance = True
1780 1715
1781 opts.ignored_projects = opts.ignored_projects + os.environ.get('IGNORED_PROJECTS', '').split(',') 1716 opts.ignored_projects = opts.ignored_projects + os.environ.get('IGNORED_PROJECTS', '').split(',')
1782 1717
1783 commandAndArgs = opts.__dict__.pop('commandAndArgs') 1718 commandAndArgs = opts.__dict__.pop('commandAndArgs')
1784 return opts, commandAndArgs 1719 return opts, commandAndArgs
1794 if doc is None: 1729 if doc is None:
1795 doc = '' 1730 doc = ''
1796 msg += ' {0:<20} {1}\n'.format(cmd, doc.split('\n', 1)[0]) 1731 msg += ' {0:<20} {1}\n'.format(cmd, doc.split('\n', 1)[0])
1797 return msg + '\n' 1732 return msg + '\n'
1798 1733
1799 def java(requiredCompliance=None): 1734 _canceled_java_requests = set()
1735
1736 def java(requiredCompliance=None, purpose=None, cancel=None):
1800 """ 1737 """
1801 Get a JavaConfig object containing Java commands launch details. 1738 Get a JavaConfig object containing Java commands launch details.
1802 If requiredCompliance is None, the compliance level specified by --java-home/JAVA_HOME 1739 If requiredCompliance is None, the compliance level specified by --java-home/JAVA_HOME
1803 is returned. Otherwise, the JavaConfig exactly matching requiredCompliance is returned 1740 is returned. Otherwise, the JavaConfig exactly matching requiredCompliance is returned
1804 or None if there is no exact match. 1741 or None if there is no exact match.
1805 """ 1742 """
1806 assert _java_homes 1743
1744 global _default_java_home
1745 if cancel and (requiredCompliance, purpose) in _canceled_java_requests:
1746 return None
1747
1807 if not requiredCompliance: 1748 if not requiredCompliance:
1808 return _java_homes[0] 1749 if not _default_java_home:
1809 for java in _java_homes: 1750 _default_java_home = _find_jdk(purpose=purpose, cancel=cancel)
1810 if java.javaCompliance == requiredCompliance: 1751 if not _default_java_home:
1752 assert cancel
1753 _canceled_java_requests.add((requiredCompliance, purpose))
1754 return _default_java_home
1755
1756 if _opts.strict_compliance:
1757 complianceCheck = requiredCompliance.exactMatch
1758 desc = str(requiredCompliance)
1759 else:
1760 compVersion = VersionSpec(str(requiredCompliance))
1761 complianceCheck = lambda version: version >= compVersion
1762 desc = '>=' + str(requiredCompliance)
1763
1764 for java in _extra_java_homes:
1765 if complianceCheck(java.version):
1811 return java 1766 return java
1767
1768 jdk = _find_jdk(versionCheck=complianceCheck, versionDescription=desc, purpose=purpose, cancel=cancel)
1769 if jdk:
1770 assert jdk not in _extra_java_homes
1771 _extra_java_homes.append(jdk)
1772 else:
1773 assert cancel
1774 _canceled_java_requests.add((requiredCompliance, purpose))
1775 return jdk
1776
1777 def java_version(versionCheck, versionDescription=None, purpose=None):
1778 if _default_java_home and versionCheck(_default_java_home.version):
1779 return _default_java_home
1780 for java in _extra_java_homes:
1781 if versionCheck(java.version):
1782 return java
1783 jdk = _find_jdk(versionCheck, versionDescription, purpose)
1784 assert jdk not in _extra_java_homes
1785 _extra_java_homes.append(jdk)
1786 return jdk
1787
1788 def _find_jdk(versionCheck=None, versionDescription=None, purpose=None, cancel=None):
1789 if not versionCheck:
1790 versionCheck = lambda v: True
1791 assert not versionDescription or versionCheck
1792 if not versionCheck and not purpose:
1793 isDefaultJdk = True
1794 else:
1795 isDefaultJdk = False
1796
1797 candidateJdks = []
1798 source = ''
1799 if _opts.java_home:
1800 candidateJdks.append(_opts.java_home)
1801 source = '--java-home'
1802 elif os.environ.get('JAVA_HOME'):
1803 candidateJdks.append(os.environ.get('JAVA_HOME'))
1804 source = 'JAVA_HOME'
1805
1806 result = _find_jdk_in_candidates(candidateJdks, versionCheck, warn=True, source=source)
1807 if result:
1808 return result
1809
1810 candidateJdks = []
1811
1812 if _opts.extra_java_homes:
1813 candidateJdks += _opts.extra_java_homes.split(os.pathsep)
1814 source = '--extra-java-homes'
1815 elif os.environ.get('EXTRA_JAVA_HOMES'):
1816 candidateJdks += os.environ.get('EXTRA_JAVA_HOMES').split(os.pathsep)
1817 source = 'EXTRA_JAVA_HOMES'
1818
1819 result = _find_jdk_in_candidates(candidateJdks, versionCheck, warn=True, source=source)
1820 if not result:
1821 candidateJdks = []
1822 source = ''
1823
1824 if get_os() == 'darwin':
1825 base = '/Library/Java/JavaVirtualMachines'
1826 if exists(base):
1827 candidateJdks = [join(base, n, 'Contents/Home') for n in os.listdir(base)]
1828 elif get_os() == 'linux':
1829 base = '/usr/lib/jvm'
1830 if exists(base):
1831 candidateJdks = [join(base, n) for n in os.listdir(base)]
1832 base = '/usr/java'
1833 if exists(base):
1834 candidateJdks += [join(base, n) for n in os.listdir(base)]
1835 elif get_os() == 'solaris':
1836 base = '/usr/jdk/instances'
1837 if exists(base):
1838 candidateJdks = [join(base, n) for n in os.listdir(base)]
1839 elif get_os() == 'windows':
1840 base = r'C:\Program Files\Java'
1841 if exists(base):
1842 candidateJdks = [join(base, n) for n in os.listdir(base)]
1843
1844 configs = _filtered_jdk_configs(candidateJdks, versionCheck)
1845 else:
1846 if not isDefaultJdk:
1847 return result
1848 configs = [result]
1849
1850 if len(configs) > 1:
1851 if not is_interactive():
1852 msg = "Multiple possible choices for a JDK"
1853 if purpose:
1854 msg += ' for' + purpose
1855 msg += ': '
1856 if versionDescription:
1857 msg += '(' + versionDescription + ')'
1858 selected = configs[0]
1859 msg += ". Selecting " + str(selected)
1860 log(msg)
1861 else:
1862 msg = 'Please select a '
1863 if isDefaultJdk:
1864 msg += 'default '
1865 msg += 'JDK'
1866 if purpose:
1867 msg += ' for' + purpose
1868 msg += ': '
1869 if versionDescription:
1870 msg += '(' + versionDescription + ')'
1871 log(msg)
1872 choices = configs + ['<other>']
1873 if cancel:
1874 choices.append('Cancel (' + cancel + ')')
1875 selected = select_items(choices, allowMultiple=False)
1876 if isinstance(selected, types.StringTypes) and selected == '<other>':
1877 selected = None
1878 if isinstance(selected, types.StringTypes) and selected == 'Cancel (' + cancel + ')':
1879 return None
1880 elif len(configs) == 1:
1881 selected = configs[0]
1882 msg = 'Selected ' + str(selected) + ' as '
1883 if isDefaultJdk:
1884 msg += 'default'
1885 msg += 'JDK'
1886 if versionDescription:
1887 msg = msg + ' ' + versionDescription
1888 if purpose:
1889 msg += ' for' + purpose
1890 log(msg)
1891 else:
1892 msg = 'Could not find any JDK'
1893 if purpose:
1894 msg += ' for' + purpose
1895 msg += ' '
1896 if versionDescription:
1897 msg = msg + '(' + versionDescription + ')'
1898 log(msg)
1899 selected = None
1900
1901 while not selected:
1902 jdkLocation = raw_input('Enter path of JDK: ')
1903 selected = _find_jdk_in_candidates([jdkLocation], versionCheck, warn=True)
1904
1905 varName = 'JAVA_HOME' if isDefaultJdk else 'EXTRA_JAVA_HOMES'
1906 allowMultiple = not isDefaultJdk
1907 envPath = join(_primary_suite.mxDir, 'env')
1908 if is_interactive() and ask_yes_no('Persist this setting by adding "{0}={1}" to {2}'.format(varName, selected.jdk, envPath), 'y'):
1909 envLines = []
1910 with open(envPath) as fp:
1911 append = True
1912 for line in fp:
1913 if line.rstrip().startswith(varName):
1914 _, currentValue = line.split('=', 1)
1915 currentValue = currentValue.strip()
1916 if not allowMultiple and currentValue:
1917 if not ask_yes_no('{0} is already set to {1}, overwrite with {2}?'.format(varName, currentValue, selected.jdk), 'n'):
1918 return selected
1919 else:
1920 line = varName + '=' + selected.jdk + os.linesep
1921 else:
1922 line = line.rstrip()
1923 if currentValue:
1924 line += os.pathsep
1925 line += selected.jdk + os.linesep
1926 append = False
1927 envLines.append(line)
1928 if append:
1929 envLines.append(varName + '=' + selected.jdk)
1930
1931 with open(envPath, 'w') as fp:
1932 for line in envLines:
1933 fp.write(line)
1934
1935 if varName == 'JAVA_HOME':
1936 os.environ['JAVA_HOME'] = selected.jdk
1937
1938 return selected
1939
1940 def is_interactive():
1941 return sys.__stdin__.isatty()
1942
1943 def _filtered_jdk_configs(candidates, versionCheck, warn=False, source=None):
1944 filtered = []
1945 for candidate in candidates:
1946 try:
1947 config = JavaConfig(candidate)
1948 if versionCheck(config.version):
1949 filtered.append(config)
1950 except JavaConfigException as e:
1951 if warn:
1952 log('Path in ' + source + "' is not pointing to a JDK (" + e.message + ")")
1953 return filtered
1954
1955 def _find_jdk_in_candidates(candidates, versionCheck, warn=False, source=None):
1956 filtered = _filtered_jdk_configs(candidates, versionCheck, warn, source)
1957 if filtered:
1958 return filtered[0]
1812 return None 1959 return None
1813 1960
1814 1961
1815 def run_java(args, nonZeroIsFatal=True, out=None, err=None, cwd=None, addDefaultArgs=True, javaConfig=None): 1962 def run_java(args, nonZeroIsFatal=True, out=None, err=None, cwd=None, addDefaultArgs=True, javaConfig=None):
1816 if not javaConfig: 1963 if not javaConfig:
2077 return cmp(self.value, other.value) 2224 return cmp(self.value, other.value)
2078 2225
2079 def __hash__(self): 2226 def __hash__(self):
2080 return self.value.__hash__() 2227 return self.value.__hash__()
2081 2228
2229 def exactMatch(self, version):
2230 assert isinstance(version, VersionSpec)
2231 return len(version.parts) > 1 and version.parts[0] == 1 and version.parts[1] == self.value
2232
2082 """ 2233 """
2083 A version specification as defined in JSR-56 2234 A version specification as defined in JSR-56
2084 """ 2235 """
2085 class VersionSpec: 2236 class VersionSpec:
2086 def __init__(self, versionString): 2237 def __init__(self, versionString):
2100 def _filter_non_existant_paths(paths): 2251 def _filter_non_existant_paths(paths):
2101 if paths: 2252 if paths:
2102 return os.pathsep.join([path for path in _separatedCygpathW2U(paths).split(os.pathsep) if exists(path)]) 2253 return os.pathsep.join([path for path in _separatedCygpathW2U(paths).split(os.pathsep) if exists(path)])
2103 return None 2254 return None
2104 2255
2256 class JavaConfigException(Exception):
2257 def __init__(self, value):
2258 Exception.__init__(self, value)
2259
2105 """ 2260 """
2106 A JavaConfig object encapsulates info on how Java commands are run. 2261 A JavaConfig object encapsulates info on how Java commands are run.
2107 """ 2262 """
2108 class JavaConfig: 2263 class JavaConfig:
2109 def __init__(self, java_home, java_dbg_port): 2264 def __init__(self, java_home):
2110 self.jdk = java_home 2265 self.jdk = java_home
2111 self.debug_port = java_dbg_port
2112 self.jar = exe_suffix(join(self.jdk, 'bin', 'jar')) 2266 self.jar = exe_suffix(join(self.jdk, 'bin', 'jar'))
2113 self.java = exe_suffix(join(self.jdk, 'bin', 'java')) 2267 self.java = exe_suffix(join(self.jdk, 'bin', 'java'))
2114 self.javac = exe_suffix(join(self.jdk, 'bin', 'javac')) 2268 self.javac = exe_suffix(join(self.jdk, 'bin', 'javac'))
2115 self.javap = exe_suffix(join(self.jdk, 'bin', 'javap')) 2269 self.javap = exe_suffix(join(self.jdk, 'bin', 'javap'))
2116 self.javadoc = exe_suffix(join(self.jdk, 'bin', 'javadoc')) 2270 self.javadoc = exe_suffix(join(self.jdk, 'bin', 'javadoc'))
2120 self._bootclasspath = None 2274 self._bootclasspath = None
2121 self._extdirs = None 2275 self._extdirs = None
2122 self._endorseddirs = None 2276 self._endorseddirs = None
2123 2277
2124 if not exists(self.java): 2278 if not exists(self.java):
2125 abort('Java launcher does not exist: ' + self.java) 2279 raise JavaConfigException('Java launcher does not exist: ' + self.java)
2126 2280
2127 def delAtAndSplit(s): 2281 def delAtAndSplit(s):
2128 return shlex.split(s.lstrip('@')) 2282 return shlex.split(s.lstrip('@'))
2129 2283
2130 self.java_args = delAtAndSplit(_opts.java_args) if _opts.java_args else [] 2284 self.java_args = delAtAndSplit(_opts.java_args) if _opts.java_args else []
2137 self.java_args = ['-d64'] + self.java_args 2291 self.java_args = ['-d64'] + self.java_args
2138 except subprocess.CalledProcessError as e: 2292 except subprocess.CalledProcessError as e:
2139 try: 2293 try:
2140 output = subprocess.check_output([self.java, '-version'], stderr=subprocess.STDOUT) 2294 output = subprocess.check_output([self.java, '-version'], stderr=subprocess.STDOUT)
2141 except subprocess.CalledProcessError as e: 2295 except subprocess.CalledProcessError as e:
2142 print e.output 2296 raise JavaConfigException(e.returncode + " :" + e.output)
2143 abort(e.returncode)
2144 2297
2145 def _checkOutput(out): 2298 def _checkOutput(out):
2146 return 'version' in out 2299 return 'version' in out
2147 2300
2148 # hotspot can print a warning, e.g. if there's a .hotspot_compiler file in the cwd 2301 # hotspot can print a warning, e.g. if there's a .hotspot_compiler file in the cwd
2154 version = o 2307 version = o
2155 2308
2156 self.version = VersionSpec(version.split()[2].strip('"')) 2309 self.version = VersionSpec(version.split()[2].strip('"'))
2157 self.javaCompliance = JavaCompliance(self.version.versionString) 2310 self.javaCompliance = JavaCompliance(self.version.versionString)
2158 2311
2159 if self.debug_port is not None: 2312 if _opts.java_dbg_port is not None:
2160 self.java_args += ['-Xdebug', '-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=' + str(self.debug_port)] 2313 self.java_args += ['-Xdebug', '-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=' + str(_opts.java_dbg_port)]
2161 2314
2162 def _init_classpaths(self): 2315 def _init_classpaths(self):
2163 if not self._classpaths_initialized: 2316 if not self._classpaths_initialized:
2164 myDir = dirname(__file__) 2317 myDir = dirname(__file__)
2165 outDir = join(dirname(__file__), '.jdk' + str(self.version)) 2318 outDir = join(dirname(__file__), '.jdk' + str(self.version))
2178 self._extdirs = _filter_non_existant_paths(self._extdirs) 2331 self._extdirs = _filter_non_existant_paths(self._extdirs)
2179 self._endorseddirs = _filter_non_existant_paths(self._endorseddirs) 2332 self._endorseddirs = _filter_non_existant_paths(self._endorseddirs)
2180 self._classpaths_initialized = True 2333 self._classpaths_initialized = True
2181 2334
2182 def __repr__(self): 2335 def __repr__(self):
2183 return "JavaConfig(" + str(self.jdk) + ", " + str(self.debug_port) + ")" 2336 return "JavaConfig(" + str(self.jdk) + ")"
2184 2337
2185 def __str__(self): 2338 def __str__(self):
2186 return "Java " + str(self.version) + " (" + str(self.javaCompliance) + ") from " + str(self.jdk) 2339 return "Java " + str(self.version) + " (" + str(self.javaCompliance) + ") from " + str(self.jdk)
2187 2340
2188 def __hash__(self): 2341 def __hash__(self):
2473 if not args.error_prone: 2626 if not args.error_prone:
2474 javac = args.alt_javac if args.alt_javac else mainJava.javac 2627 javac = args.alt_javac if args.alt_javac else mainJava.javac
2475 self.logCompilation('javac' if not args.alt_javac else args.alt_javac) 2628 self.logCompilation('javac' if not args.alt_javac else args.alt_javac)
2476 javacCmd = [javac, '-g', '-J-Xmx1g', '-source', compliance, '-target', compliance, '-classpath', cp, '-d', outputDir] 2629 javacCmd = [javac, '-g', '-J-Xmx1g', '-source', compliance, '-target', compliance, '-classpath', cp, '-d', outputDir]
2477 jdk.javacLibOptions(javacCmd) 2630 jdk.javacLibOptions(javacCmd)
2478 if jdk.debug_port is not None: 2631 if _opts.java_dbg_port is not None:
2479 javacCmd += ['-J-Xdebug', '-J-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=' + str(jdk.debug_port)] 2632 javacCmd += ['-J-Xdebug', '-J-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=' + str(_opts.java_dbg_port)]
2480 javacCmd += processorArgs 2633 javacCmd += processorArgs
2481 javacCmd += ['@' + _cygpathU2W(argfile.name)] 2634 javacCmd += ['@' + _cygpathU2W(argfile.name)]
2482 2635
2483 if not args.warnAPI: 2636 if not args.warnAPI:
2484 javacCmd.append('-XDignore.symbol.file') 2637 javacCmd.append('-XDignore.symbol.file')
2634 continue 2787 continue
2635 2788
2636 # skip building this Java project if its Java compliance level is "higher" than the configured JDK 2789 # skip building this Java project if its Java compliance level is "higher" than the configured JDK
2637 requiredCompliance = p.javaCompliance if p.javaCompliance else JavaCompliance(args.compliance) if args.compliance else None 2790 requiredCompliance = p.javaCompliance if p.javaCompliance else JavaCompliance(args.compliance) if args.compliance else None
2638 jdk = java(requiredCompliance) 2791 jdk = java(requiredCompliance)
2639 assert jdk
2640 2792
2641 outputDir = p.output_dir() 2793 outputDir = p.output_dir()
2642 2794
2643 sourceDirs = p.source_dirs() 2795 sourceDirs = p.source_dirs()
2644 buildReason = None 2796 buildReason = None
2938 3090
2939 class Batch: 3091 class Batch:
2940 def __init__(self, settingsDir, javaCompliance): 3092 def __init__(self, settingsDir, javaCompliance):
2941 self.path = join(settingsDir, 'org.eclipse.jdt.core.prefs') 3093 self.path = join(settingsDir, 'org.eclipse.jdt.core.prefs')
2942 self.javaCompliance = javaCompliance 3094 self.javaCompliance = javaCompliance
2943 self.javafiles = list()
2944 with open(join(settingsDir, 'org.eclipse.jdt.ui.prefs')) as fp: 3095 with open(join(settingsDir, 'org.eclipse.jdt.ui.prefs')) as fp:
2945 jdtUiPrefs = fp.read() 3096 jdtUiPrefs = fp.read()
2946 self.removeTrailingWhitespace = 'sp_cleanup.remove_trailing_whitespaces_all=true' in jdtUiPrefs 3097 self.removeTrailingWhitespace = 'sp_cleanup.remove_trailing_whitespaces_all=true' in jdtUiPrefs
2947 if self.removeTrailingWhitespace: 3098 if self.removeTrailingWhitespace:
2948 assert 'sp_cleanup.remove_trailing_whitespaces=true' in jdtUiPrefs and 'sp_cleanup.remove_trailing_whitespaces_ignore_empty=false' in jdtUiPrefs 3099 assert 'sp_cleanup.remove_trailing_whitespaces=true' in jdtUiPrefs and 'sp_cleanup.remove_trailing_whitespaces_ignore_empty=false' in jdtUiPrefs
2949 3100 self.cachedHash = None
2950 def settings(self): 3101
3102 def __hash__(self):
3103 if not self.cachedHash:
3104 with open(self.path) as fp:
3105 self.cachedHash = (fp.read(), self.javaCompliance, self.removeTrailingWhitespace).__hash__()
3106 return self.cachedHash
3107
3108 def __eq__(self, other):
3109 if not isinstance(other, Batch):
3110 return False
3111 if self.removeTrailingWhitespace != other.removeTrailingWhitespace:
3112 return False
3113 if self.javaCompliance != other.javaCompliance:
3114 return False
3115 if self.path == other.path:
3116 return True
2951 with open(self.path) as fp: 3117 with open(self.path) as fp:
2952 return fp.read() + java(self.javaCompliance).java + str(self.removeTrailingWhitespace) 3118 with open(other.path) as ofp:
3119 if fp.read() != ofp.read():
3120 return False
3121 return True
2953 3122
2954 class FileInfo: 3123 class FileInfo:
2955 def __init__(self, path): 3124 def __init__(self, path):
2956 self.path = path 3125 self.path = path
2957 with open(path) as fp: 3126 with open(path) as fp:
2990 3159
2991 if not exists(batch.path): 3160 if not exists(batch.path):
2992 if _opts.verbose: 3161 if _opts.verbose:
2993 log('[no Eclipse Code Formatter preferences at {0} - skipping]'.format(batch.path)) 3162 log('[no Eclipse Code Formatter preferences at {0} - skipping]'.format(batch.path))
2994 continue 3163 continue
2995 3164 javafiles = []
2996 for sourceDir in sourceDirs: 3165 for sourceDir in sourceDirs:
2997 for root, _, files in os.walk(sourceDir): 3166 for root, _, files in os.walk(sourceDir):
2998 for f in [join(root, name) for name in files if name.endswith('.java')]: 3167 for f in [join(root, name) for name in files if name.endswith('.java')]:
2999 batch.javafiles.append(FileInfo(f)) 3168 javafiles.append(FileInfo(f))
3000 if len(batch.javafiles) == 0: 3169 if len(javafiles) == 0:
3001 logv('[no Java sources in {0} - skipping]'.format(p.name)) 3170 logv('[no Java sources in {0} - skipping]'.format(p.name))
3002 continue 3171 continue
3003 3172
3004 res = batches.setdefault(batch.settings(), batch) 3173 res = batches.setdefault(batch, javafiles)
3005 if res is not batch: 3174 if res is not javafiles:
3006 res.javafiles = res.javafiles + batch.javafiles 3175 res.extend(javafiles)
3007 3176
3008 log("we have: " + str(len(batches)) + " batches") 3177 log("we have: " + str(len(batches)) + " batches")
3009 for batch in batches.itervalues(): 3178 for batch, javafiles in batches.iteritems():
3010 for chunk in _chunk_files_for_command_line(batch.javafiles, pathFunction=lambda f: f.path): 3179 for chunk in _chunk_files_for_command_line(javafiles, pathFunction=lambda f: f.path):
3011 run([args.eclipse_exe, 3180 run([args.eclipse_exe,
3012 '-nosplash', 3181 '-nosplash',
3013 '-application', 3182 '-application',
3014 'org.eclipse.jdt.core.JavaCodeFormatter', 3183 'org.eclipse.jdt.core.JavaCodeFormatter',
3015 '-vm', java(batch.javaCompliance).java, 3184 '-vm', java(batch.javaCompliance).java,
4719 if not refreshOnly: 4888 if not refreshOnly:
4720 fsckprojects([]) 4889 fsckprojects([])
4721 4890
4722 def fsckprojects(args): 4891 def fsckprojects(args):
4723 """find directories corresponding to deleted Java projects and delete them""" 4892 """find directories corresponding to deleted Java projects and delete them"""
4724 if not sys.stdout.isatty(): 4893 if not is_interactive():
4725 log('fsckprojects command must be run in an interactive shell') 4894 log('fsckprojects command must be run in an interactive shell')
4726 return 4895 return
4727 hg = HgConfig() 4896 hg = HgConfig()
4728 for suite in suites(True): 4897 for suite in suites(True):
4729 projectDirs = [p.dir for p in suite.projects] 4898 projectDirs = [p.dir for p in suite.projects]
4744 if len(indicators) != 0: 4913 if len(indicators) != 0:
4745 indicators = [os.path.relpath(join(dirpath, i), suite.dir) for i in indicators] 4914 indicators = [os.path.relpath(join(dirpath, i), suite.dir) for i in indicators]
4746 indicatorsInHg = hg.locate(suite.dir, indicators) 4915 indicatorsInHg = hg.locate(suite.dir, indicators)
4747 # Only proceed if there are indicator files that are not under HG 4916 # Only proceed if there are indicator files that are not under HG
4748 if len(indicators) > len(indicatorsInHg): 4917 if len(indicators) > len(indicatorsInHg):
4749 if not sys.stdout.isatty() or ask_yes_no(dirpath + ' looks like a removed project -- delete it', 'n'): 4918 if not is_interactive() or ask_yes_no(dirpath + ' looks like a removed project -- delete it', 'n'):
4750 shutil.rmtree(dirpath) 4919 shutil.rmtree(dirpath)
4751 log('Deleted ' + dirpath) 4920 log('Deleted ' + dirpath)
4752 4921
4753 def javadoc(args, parser=None, docDir='javadoc', includeDeps=True, stdDoclet=True): 4922 def javadoc(args, parser=None, docDir='javadoc', includeDeps=True, stdDoclet=True):
4754 """generate javadoc for some/all Java projects""" 4923 """generate javadoc for some/all Java projects"""
4863 projectJava = java(p.javaCompliance) 5032 projectJava = java(p.javaCompliance)
4864 5033
4865 # Once https://bugs.openjdk.java.net/browse/JDK-8041628 is fixed, 5034 # Once https://bugs.openjdk.java.net/browse/JDK-8041628 is fixed,
4866 # this should be reverted to: 5035 # this should be reverted to:
4867 # javadocExe = java().javadoc 5036 # javadocExe = java().javadoc
5037 # we can then also respect _opts.relatex_compliance
4868 javadocExe = projectJava.javadoc 5038 javadocExe = projectJava.javadoc
4869 5039
4870 run([javadocExe, memory, 5040 run([javadocExe, memory,
4871 '-XDignore.symbol.file', 5041 '-XDignore.symbol.file',
4872 '-classpath', cp, 5042 '-classpath', cp,
5083 5253
5084 """ 5254 """
5085 if len(items) <= 1: 5255 if len(items) <= 1:
5086 return items 5256 return items
5087 else: 5257 else:
5258 assert is_interactive()
5259 numlen = str(len(str(len(items))))
5088 if allowMultiple: 5260 if allowMultiple:
5089 log('[0] <all>') 5261 log(('[{0:>' + numlen + '}] <all>').format(0))
5090 for i in range(0, len(items)): 5262 for i in range(0, len(items)):
5091 if descriptions is None: 5263 if descriptions is None:
5092 log('[{0}] {1}'.format(i + 1, items[i])) 5264 log(('[{0:>' + numlen + '}] {1}').format(i + 1, items[i]))
5093 else: 5265 else:
5094 assert len(items) == len(descriptions) 5266 assert len(items) == len(descriptions)
5095 wrapper = textwrap.TextWrapper(subsequent_indent=' ') 5267 wrapper = textwrap.TextWrapper(subsequent_indent=' ')
5096 log('\n'.join(wrapper.wrap('[{0}] {1} - {2}'.format(i + 1, items[i], descriptions[i])))) 5268 log('\n'.join(wrapper.wrap(('[{0:>' + numlen + '}] {1} - {2}').format(i + 1, items[i], descriptions[i]))))
5097 while True: 5269 while True:
5098 if allowMultiple: 5270 if allowMultiple:
5099 s = raw_input('Enter number(s) of selection (separate multiple choices with spaces): ').split() 5271 s = raw_input('Enter number(s) of selection (separate multiple choices with spaces): ').split()
5100 else: 5272 else:
5101 s = [raw_input('Enter number of selection: ')] 5273 s = [raw_input('Enter number of selection: ')]
5263 _show_section('distributions', s.dists) 5435 _show_section('distributions', s.dists)
5264 5436
5265 def ask_yes_no(question, default=None): 5437 def ask_yes_no(question, default=None):
5266 """""" 5438 """"""
5267 assert not default or default == 'y' or default == 'n' 5439 assert not default or default == 'y' or default == 'n'
5268 if not sys.stdout.isatty(): 5440 if not is_interactive():
5269 if default: 5441 if default:
5270 return default 5442 return default
5271 else: 5443 else:
5272 abort("Can not answer '" + question + "?' if stdout is not a tty") 5444 abort("Can not answer '" + question + "?' if stdout is not a tty")
5273 questionMark = '? [yn]: ' 5445 questionMark = '? [yn]: '
5393 abort('no primary suite found') 5565 abort('no primary suite found')
5394 5566
5395 opts, commandAndArgs = _argParser._parse_cmd_line() 5567 opts, commandAndArgs = _argParser._parse_cmd_line()
5396 assert _opts == opts 5568 assert _opts == opts
5397 5569
5398 global _java_homes
5399 defaultJdk = JavaConfig(opts.java_home, opts.java_dbg_port)
5400 _java_homes = [defaultJdk]
5401 if opts.extra_java_homes:
5402 for java_home in opts.extra_java_homes.split(os.pathsep):
5403 extraJdk = JavaConfig(java_home, opts.java_dbg_port)
5404 if extraJdk.javaCompliance > defaultJdk.javaCompliance:
5405 abort('Secondary JDK ' + extraJdk.jdk + ' has higher compliance level than default JDK ' + defaultJdk.jdk)
5406 _java_homes.append(extraJdk)
5407
5408 for s in suites(): 5570 for s in suites():
5409 s._post_init(opts) 5571 s._post_init(opts)
5410 5572
5411 if len(commandAndArgs) == 0: 5573 if len(commandAndArgs) == 0:
5412 _argParser.print_help() 5574 _argParser.print_help()