comparison mxtool/mx.py @ 21976:36e37644f91e

mx: improve first usage experience: Create mx.ask_persist_env to handle env file modifications, make it deal with files missing final newline Use mx.ask_persist_env to persist the DEFAULT_VM Make mx_graal specify its version restrictions when asking for the default JDK When selecting versions manually or automatically, use JDKs from JAVA_HOME first, then from EXTRA_JAVA_HOMES, then from standard locations, then sort by version. Even if EXTRA_JAVA_HOMES is already defained, let the user decide which JAVA_HOME to use
author Gilles Duboscq <gilles.m.duboscq@oracle.com>
date Fri, 12 Jun 2015 16:51:32 +0200
parents 290a87b718e1
children a6425aa8f70c
comparison
equal deleted inserted replaced
21975:290a87b718e1 21976:36e37644f91e
1785 msg += ' {0:<20} {1}\n'.format(cmd, doc.split('\n', 1)[0]) 1785 msg += ' {0:<20} {1}\n'.format(cmd, doc.split('\n', 1)[0])
1786 return msg + '\n' 1786 return msg + '\n'
1787 1787
1788 _canceled_java_requests = set() 1788 _canceled_java_requests = set()
1789 1789
1790 def java(requiredCompliance=None, purpose=None, cancel=None): 1790 def java(versionCheck=None, purpose=None, cancel=None, versionDescription=None, defaultJdk=None):
1791 """ 1791 """
1792 Get a JavaConfig object containing Java commands launch details. 1792 Get a JavaConfig object containing Java commands launch details.
1793 If requiredCompliance is None, the compliance level specified by --java-home/JAVA_HOME 1793 """
1794 is returned. Otherwise, the JavaConfig exactly matching requiredCompliance is returned 1794
1795 or None if there is no exact match. 1795 if defaultJdk is None:
1796 """ 1796 defaultJdk = versionCheck is None and not purpose
1797 1797
1798 global _default_java_home 1798 # interpret string and compliance as compliance check
1799 if cancel and (requiredCompliance, purpose) in _canceled_java_requests: 1799 if isinstance(versionCheck, types.StringTypes):
1800 requiredCompliance = JavaCompliance(versionCheck)
1801 versionCheck, versionDescription = _convert_complicance_to_version_check(requiredCompliance)
1802 elif isinstance(versionCheck, JavaCompliance):
1803 versionCheck, versionDescription = _convert_complicance_to_version_check(versionCheck)
1804
1805 global _default_java_home, _extra_java_homes
1806 if cancel and (versionDescription, purpose) in _canceled_java_requests:
1800 return None 1807 return None
1801 1808
1802 if not requiredCompliance: 1809 if defaultJdk:
1803 if not _default_java_home: 1810 if not _default_java_home:
1804 _default_java_home = _find_jdk(purpose=purpose, cancel=cancel) 1811 _default_java_home = _find_jdk(versionCheck=versionCheck, versionDescription=versionDescription, purpose=purpose, cancel=cancel, isDefaultJdk=True)
1805 if not _default_java_home: 1812 if not _default_java_home:
1806 assert cancel 1813 assert cancel and (versionDescription or purpose)
1807 _canceled_java_requests.add((requiredCompliance, purpose)) 1814 _canceled_java_requests.add((versionDescription, purpose))
1808 return _default_java_home 1815 return _default_java_home
1809 1816
1810 if _opts.strict_compliance:
1811 complianceCheck = requiredCompliance.exactMatch
1812 desc = str(requiredCompliance)
1813 else:
1814 compVersion = VersionSpec(str(requiredCompliance))
1815 complianceCheck = lambda version: version >= compVersion
1816 desc = '>=' + str(requiredCompliance)
1817
1818 for java in _extra_java_homes: 1817 for java in _extra_java_homes:
1819 if complianceCheck(java.version): 1818 if not versionCheck or versionCheck(java.version):
1820 return java 1819 return java
1821 1820
1822 jdk = _find_jdk(versionCheck=complianceCheck, versionDescription=desc, purpose=purpose, cancel=cancel) 1821 jdk = _find_jdk(versionCheck=versionCheck, versionDescription=versionDescription, purpose=purpose, cancel=cancel, isDefaultJdk=False)
1823 if jdk: 1822 if jdk:
1824 assert jdk not in _extra_java_homes 1823 assert jdk not in _extra_java_homes
1825 _extra_java_homes.append(jdk) 1824 _extra_java_homes = _sorted_unique_jdk_configs(_extra_java_homes + [jdk])
1826 else: 1825 else:
1827 assert cancel 1826 assert cancel and (versionDescription or purpose)
1828 _canceled_java_requests.add((requiredCompliance, purpose)) 1827 _canceled_java_requests.add((versionDescription, purpose))
1829 return jdk 1828 return jdk
1830 1829
1831 def java_version(versionCheck, versionDescription=None, purpose=None): 1830 def _convert_complicance_to_version_check(requiredCompliance):
1832 if _default_java_home and versionCheck(_default_java_home.version): 1831 if _opts.strict_compliance:
1833 return _default_java_home 1832 versionDesc = str(requiredCompliance)
1834 for java in _extra_java_homes: 1833 versionCheck = requiredCompliance.exactMatch
1835 if versionCheck(java.version):
1836 return java
1837 jdk = _find_jdk(versionCheck, versionDescription, purpose)
1838 assert jdk not in _extra_java_homes
1839 _extra_java_homes.append(jdk)
1840 return jdk
1841
1842 def _find_jdk(versionCheck=None, versionDescription=None, purpose=None, cancel=None):
1843 assert not versionDescription or versionCheck
1844 if not versionCheck and not purpose:
1845 isDefaultJdk = True
1846 else: 1834 else:
1847 isDefaultJdk = False 1835 versionDesc = '>=' + str(requiredCompliance)
1836 compVersion = VersionSpec(str(requiredCompliance))
1837 versionCheck = lambda version: version >= compVersion
1838 return (versionCheck, versionDesc)
1839
1840 def _find_jdk(versionCheck=None, versionDescription=None, purpose=None, cancel=None, isDefaultJdk=False):
1841 assert (versionDescription and versionCheck) or (not versionDescription and not versionCheck)
1848 if not versionCheck: 1842 if not versionCheck:
1849 versionCheck = lambda v: True 1843 versionCheck = lambda v: True
1850 1844
1851 candidateJdks = [] 1845 candidateJdks = []
1852 source = '' 1846 source = ''
1870 candidateJdks += os.environ.get('EXTRA_JAVA_HOMES').split(os.pathsep) 1864 candidateJdks += os.environ.get('EXTRA_JAVA_HOMES').split(os.pathsep)
1871 source = 'EXTRA_JAVA_HOMES' 1865 source = 'EXTRA_JAVA_HOMES'
1872 1866
1873 result = _find_jdk_in_candidates(candidateJdks, versionCheck, warn=True, source=source) 1867 result = _find_jdk_in_candidates(candidateJdks, versionCheck, warn=True, source=source)
1874 if not result: 1868 if not result:
1875 candidateJdks = [] 1869 configs = _find_available_jdks(versionCheck)
1876 source = '' 1870 elif isDefaultJdk: # we found something in EXTRA_JAVA_HOMES but we want to set JAVA_HOME, look for further options
1877 1871 configs = [result] + _find_available_jdks(versionCheck)
1878 if get_os() == 'darwin':
1879 base = '/Library/Java/JavaVirtualMachines'
1880 if exists(base):
1881 candidateJdks = [join(base, n, 'Contents/Home') for n in os.listdir(base)]
1882 elif get_os() == 'linux':
1883 base = '/usr/lib/jvm'
1884 if exists(base):
1885 candidateJdks = [join(base, n) for n in os.listdir(base)]
1886 base = '/usr/java'
1887 if exists(base):
1888 candidateJdks += [join(base, n) for n in os.listdir(base)]
1889 elif get_os() == 'solaris':
1890 base = '/usr/jdk/instances'
1891 if exists(base):
1892 candidateJdks = [join(base, n) for n in os.listdir(base)]
1893 elif get_os() == 'windows':
1894 base = r'C:\Program Files\Java'
1895 if exists(base):
1896 candidateJdks = [join(base, n) for n in os.listdir(base)]
1897
1898 configs = _filtered_jdk_configs(candidateJdks, versionCheck)
1899 else: 1872 else:
1900 if not isDefaultJdk: 1873 if not isDefaultJdk:
1901 return result 1874 return result
1902 configs = [result] 1875 configs = [result]
1876
1877 configs = _sorted_unique_jdk_configs(configs)
1903 1878
1904 if len(configs) > 1: 1879 if len(configs) > 1:
1905 if not is_interactive(): 1880 if not is_interactive():
1906 msg = "Multiple possible choices for a JDK" 1881 msg = "Multiple possible choices for a JDK"
1907 if purpose: 1882 if purpose:
1924 msg += '(version ' + versionDescription + ')' 1899 msg += '(version ' + versionDescription + ')'
1925 log(msg) 1900 log(msg)
1926 choices = configs + ['<other>'] 1901 choices = configs + ['<other>']
1927 if cancel: 1902 if cancel:
1928 choices.append('Cancel (' + cancel + ')') 1903 choices.append('Cancel (' + cancel + ')')
1904
1929 selected = select_items(choices, allowMultiple=False) 1905 selected = select_items(choices, allowMultiple=False)
1930 if isinstance(selected, types.StringTypes) and selected == '<other>': 1906 if isinstance(selected, types.StringTypes) and selected == '<other>':
1931 selected = None 1907 selected = None
1932 if isinstance(selected, types.StringTypes) and selected == 'Cancel (' + cancel + ')': 1908 if isinstance(selected, types.StringTypes) and selected == 'Cancel (' + cancel + ')':
1933 return None 1909 return None
1953 selected = None 1929 selected = None
1954 1930
1955 while not selected: 1931 while not selected:
1956 jdkLocation = raw_input('Enter path of JDK: ') 1932 jdkLocation = raw_input('Enter path of JDK: ')
1957 selected = _find_jdk_in_candidates([jdkLocation], versionCheck, warn=True) 1933 selected = _find_jdk_in_candidates([jdkLocation], versionCheck, warn=True)
1934 if not selected:
1935 assert versionDescription
1936 log("Error: JDK at '" + jdkLocation + "' is not compatible with version " + versionDescription)
1958 1937
1959 varName = 'JAVA_HOME' if isDefaultJdk else 'EXTRA_JAVA_HOMES' 1938 varName = 'JAVA_HOME' if isDefaultJdk else 'EXTRA_JAVA_HOMES'
1960 allowMultiple = not isDefaultJdk 1939 allowMultiple = not isDefaultJdk
1940 valueSeparator = os.pathsep if allowMultiple else None
1941 ask_persist_env(varName, selected.jdk, valueSeparator)
1942
1943 os.environ[varName] = selected.jdk
1944
1945 return selected
1946
1947 def ask_persist_env(varName, value, valueSeparator=None):
1961 envPath = join(_primary_suite.mxDir, 'env') 1948 envPath = join(_primary_suite.mxDir, 'env')
1962 if is_interactive() and ask_yes_no('Persist this setting by adding "{0}={1}" to {2}'.format(varName, selected.jdk, envPath), 'y'): 1949 if is_interactive() and ask_yes_no('Persist this setting by adding "{0}={1}" to {2}'.format(varName, value, envPath), 'y'):
1963 envLines = [] 1950 envLines = []
1964 if exists(envPath): 1951 if exists(envPath):
1965 with open(envPath) as fp: 1952 with open(envPath) as fp:
1966 append = True 1953 append = True
1967 for line in fp: 1954 for line in fp:
1968 if line.rstrip().startswith(varName): 1955 if line.rstrip().startswith(varName):
1969 _, currentValue = line.split('=', 1) 1956 _, currentValue = line.split('=', 1)
1970 currentValue = currentValue.strip() 1957 currentValue = currentValue.strip()
1971 if not allowMultiple and currentValue: 1958 if not valueSeparator and currentValue:
1972 if not ask_yes_no('{0} is already set to {1}, overwrite with {2}?'.format(varName, currentValue, selected.jdk), 'n'): 1959 if not ask_yes_no('{0} is already set to {1}, overwrite with {2}?'.format(varName, currentValue, value), 'n'):
1973 return selected 1960 return
1974 else: 1961 else:
1975 line = varName + '=' + selected.jdk + os.linesep 1962 line = varName + '=' + value + os.linesep
1976 else: 1963 else:
1977 line = line.rstrip() 1964 line = line.rstrip()
1978 if currentValue: 1965 if currentValue:
1979 line += os.pathsep 1966 line += valueSeparator
1980 line += selected.jdk + os.linesep 1967 line += value + os.linesep
1981 append = False 1968 append = False
1969 if not line.endswith(os.linesep):
1970 line += os.linesep
1982 envLines.append(line) 1971 envLines.append(line)
1983 else: 1972 else:
1984 append = True 1973 append = True
1985 1974
1986 if append: 1975 if append:
1987 envLines.append(varName + '=' + selected.jdk + os.linesep) 1976 envLines.append(varName + '=' + value + os.linesep)
1988 1977
1989 with open(envPath, 'w') as fp: 1978 with open(envPath, 'w') as fp:
1990 for line in envLines: 1979 for line in envLines:
1991 fp.write(line) 1980 fp.write(line)
1992 1981
1993 if varName == 'JAVA_HOME': 1982 _os_jdk_locations = {
1994 os.environ['JAVA_HOME'] = selected.jdk 1983 'darwin': {
1995 1984 'bases': ['/Library/Java/JavaVirtualMachines'],
1996 return selected 1985 'suffix': 'Contents/Home'
1986 },
1987 'linux': {
1988 'bases': [
1989 '/usr/lib/jvm',
1990 '/usr/java'
1991 ]
1992 },
1993 'solaris': {
1994 'bases': ['/usr/jdk/instances']
1995 },
1996 'windows': {
1997 'bases': [r'C:\Program Files\Java']
1998 },
1999 }
2000
2001 def _find_available_jdks(versionCheck):
2002 candidateJdks = []
2003 os_name = get_os()
2004 if os_name in _os_jdk_locations:
2005 jdkLocations = _os_jdk_locations[os_name]
2006 for base in jdkLocations['bases']:
2007 if exists(base):
2008 if 'suffix' in jdkLocations:
2009 suffix = jdkLocations['suffix']
2010 candidateJdks += [join(base, n, suffix) for n in os.listdir(base)]
2011 else:
2012 candidateJdks += [join(base, n) for n in os.listdir(base)]
2013
2014 return _filtered_jdk_configs(candidateJdks, versionCheck)
2015
2016 def _sorted_unique_jdk_configs(configs):
2017 path_seen = set()
2018 unique_configs = [c for c in configs if c.jdk not in path_seen and not path_seen.add(c.jdk)]
2019
2020 def _compare_configs(c1, c2):
2021 if c1 == _default_java_home:
2022 if c2 != _default_java_home:
2023 return 1
2024 elif c2 == _default_java_home:
2025 return -1
2026 if c1 in _extra_java_homes:
2027 if c2 not in _extra_java_homes:
2028 return 1
2029 elif c2 in _extra_java_homes:
2030 return -1
2031 return VersionSpec.__cmp__(c1.version, c2.version)
2032 return sorted(unique_configs, cmp=_compare_configs, reverse=True)
1997 2033
1998 def is_interactive(): 2034 def is_interactive():
1999 return sys.__stdin__.isatty() 2035 return sys.__stdin__.isatty()
2000 2036
2001 def _filtered_jdk_configs(candidates, versionCheck, warn=False, source=None): 2037 def _filtered_jdk_configs(candidates, versionCheck, warn=False, source=None):
2391 2427
2392 def __hash__(self): 2428 def __hash__(self):
2393 return hash(self.jdk) 2429 return hash(self.jdk)
2394 2430
2395 def __cmp__(self, other): 2431 def __cmp__(self, other):
2432 if other is None:
2433 return False
2396 if isinstance(other, JavaConfig): 2434 if isinstance(other, JavaConfig):
2397 compilanceCmp = cmp(self.javaCompliance, other.javaCompliance) 2435 compilanceCmp = cmp(self.javaCompliance, other.javaCompliance)
2398 if compilanceCmp: 2436 if compilanceCmp:
2399 return compilanceCmp 2437 return compilanceCmp
2400 versionCmp = cmp(self.version, other.version) 2438 versionCmp = cmp(self.version, other.version)