comparison mxtool/mx.py @ 12522:5ccee20550ea

mxtool: fixes (GRAAL-557) and code cleanups
author Mick Jordan <mick.jordan@oracle.com>
date Tue, 22 Oct 2013 15:48:45 -0700
parents ef0de9485627
children 2583afcd26ee
comparison
equal deleted inserted replaced
12521:ef0de9485627 12522:5ccee20550ea
154 _projects = dict() 154 _projects = dict()
155 _libs = dict() 155 _libs = dict()
156 _dists = dict() 156 _dists = dict()
157 _suites = dict() 157 _suites = dict()
158 _annotationProcessors = None 158 _annotationProcessors = None
159 _mainSuite = None 159 _primary_suite_path = None
160 _primary_suite = None
160 _src_suitemodel = None 161 _src_suitemodel = None
161 _dst_suitemodel = None 162 _dst_suitemodel = None
162 _opts = None 163 _opts = None
163 _java = None 164 _java = None
164 _check_global_structures = True # can be set False to allow suites with duplicate definitions to load without aborting 165 _check_global_structures = True # can be set False to allow suites with duplicate definitions to load without aborting
512 subprocess.check_output(['hg']) 513 subprocess.check_output(['hg'])
513 self.has_hg = True 514 self.has_hg = True
514 except OSError: 515 except OSError:
515 self.has_hg = False 516 self.has_hg = False
516 warn(self.missing) 517 warn(self.missing)
517 518
518 if not self.has_hg: 519 if not self.has_hg:
519 if abortOnFail: 520 if abortOnFail:
520 abort(self.missing) 521 abort(self.missing)
521 else: 522 else:
522 warn(self.missing) 523 warn(self.missing)
523 524
524 def tip(self, s, abortOnError=True): 525 def tip(self, sDir, abortOnError=True):
525 try: 526 try:
526 version = subprocess.check_output(['hg', 'tip', '-R', s.dir, '--template', '{node}']) 527 return subprocess.check_output(['hg', 'tip', '-R', sDir, '--template', '{node}'])
527 if s.version is not None and s.version != version:
528 abort('version of suite ' + s.name +' has changed during run')
529 return version
530 except OSError: 528 except OSError:
531 warn(self.missing) 529 warn(self.missing)
532 except subprocess.CalledProcessError: 530 except subprocess.CalledProcessError:
533 if abortOnError: 531 if abortOnError:
534 abort('failed to get tip revision id') 532 abort('failed to get tip revision id')
562 """ 560 """
563 def __init__(self): 561 def __init__(self):
564 self.primaryDir = None 562 self.primaryDir = None
565 self.suitenamemap = {} 563 self.suitenamemap = {}
566 564
567 def _find_suite_dir(self, suitename): 565 def find_suite_dir(self, suitename):
568 """locates the URL/path for suitename or None if not found""" 566 """locates the URL/path for suitename or None if not found"""
569 abort('_find_suite_dir not implemented') 567 abort('find_suite_dir not implemented')
570 568
571 def _set_primary_dir(self, d): 569 def set_primary_dir(self, d):
572 """informs that d is the primary suite directory""" 570 """informs that d is the primary suite directory"""
573 self._primaryDir = d 571 self._primaryDir = d
574 572
575 def _importee_dir(self, importer_dir, suitename): 573 def importee_dir(self, importer_dir, suitename):
576 """returns the directory path for an import of suitename, given importer_dir""" 574 """returns the directory path for an import of suitename, given importer_dir"""
577 abort('_importee_dir not implemented') 575 abort('importee_dir not implemented')
578 576
579 def _nestedsuites_dirname(self): 577 def nestedsuites_dirname(self):
580 """Returns the dirname that contains any nested suites if the model supports that""" 578 """Returns the dirname that contains any nested suites if the model supports that"""
581 return None 579 return None
582 580
583 def _mxDirName(self, name): 581 def _mxDirName(self, name):
584 # temporary workaround until mx.graal exists 582 # temporary workaround until mx.graal exists
611 for pair in pairs: 609 for pair in pairs:
612 mappair = pair.split('=') 610 mappair = pair.split('=')
613 self.suitenamemap[mappair[0]] = mappair[1] 611 self.suitenamemap[mappair[0]] = mappair[1]
614 612
615 @staticmethod 613 @staticmethod
616 def _set_suitemodel(option, suitemap): 614 def set_suitemodel(option, suitemap):
617 if option.startswith('sibling'): 615 if option.startswith('sibling'):
618 return SiblingSuiteModel(os.getcwd(), option, suitemap) 616 return SiblingSuiteModel(os.getcwd(), option, suitemap)
619 elif option.startswith('nested'): 617 elif option.startswith('nested'):
620 return NestedImportsSuiteModel(os.getcwd(), option, suitemap) 618 return NestedImportsSuiteModel(os.getcwd(), option, suitemap)
621 elif option.startswith('path'): 619 elif option.startswith('path'):
622 return PathSuiteModel(option[len('path:'):]) 620 return PathSuiteModel(option[len('path:'):])
623 else: 621 else:
624 abort('unknown suitemodel type: ' + option) 622 abort('unknown suitemodel type: ' + option)
625 623
626 @staticmethod 624 @staticmethod
627 def _parse_options(): 625 def parse_options():
628 # suite-specific args may match the known args so there is no way at this early stage 626 # suite-specific args may match the known args so there is no way at this early stage
629 # to use ArgParser to handle the suite model global arguments, so we just do it manually. 627 # to use ArgParser to handle the suite model global arguments, so we just do it manually.
630 def _get_argvalue(arg, args, i): 628 def _get_argvalue(arg, args, i):
631 if i < len(args): 629 if i < len(args):
632 return args[i] 630 return args[i]
648 suitemap_arg = _get_argvalue(arg, args, i + 1) 646 suitemap_arg = _get_argvalue(arg, args, i + 1)
649 elif arg == '-w': 647 elif arg == '-w':
650 # to get warnings on suite loading issues before command line is parsed 648 # to get warnings on suite loading issues before command line is parsed
651 global _warn 649 global _warn
652 _warn = True 650 _warn = True
653 651 elif arg == '-p' or arg == '--primary-suite-path':
652 global _primary_suite_path
653 _primary_suite_path = os.path.abspath(_get_argvalue(arg, args, i + 1))
654 i = i + 1 654 i = i + 1
655 655
656 global _src_suitemodel 656 global _src_suitemodel
657 _src_suitemodel = SuiteModel._set_suitemodel(src_suitemodel_arg, suitemap_arg) 657 _src_suitemodel = SuiteModel.set_suitemodel(src_suitemodel_arg, suitemap_arg)
658 global _dst_suitemodel 658 global _dst_suitemodel
659 _dst_suitemodel = SuiteModel._set_suitemodel(dst_suitemodel_arg, suitemap_arg) 659 _dst_suitemodel = SuiteModel.set_suitemodel(dst_suitemodel_arg, suitemap_arg)
660 660
661 661
662 class SiblingSuiteModel(SuiteModel): 662 class SiblingSuiteModel(SuiteModel):
663 """All suites are siblings in the same parent directory, recorded as _suiteRootDir""" 663 """All suites are siblings in the same parent directory, recorded as _suiteRootDir"""
664 def __init__(self, suiteRootDir, option, suitemap): 664 def __init__(self, suiteRootDir, option, suitemap):
665 SuiteModel.__init__(self) 665 SuiteModel.__init__(self)
666 self._suiteRootDir = suiteRootDir 666 self._suiteRootDir = suiteRootDir
667 self._create_suitenamemap(option[len('sibling:'):], suitemap) 667 self._create_suitenamemap(option[len('sibling:'):], suitemap)
668 668
669 def _find_suite_dir(self, name): 669 def find_suite_dir(self, name):
670 return self._search_dir(self._suiteRootDir, self._mxDirName(name)) 670 return self._search_dir(self._suiteRootDir, self._mxDirName(name))
671 671
672 def _set_primary_dir(self, d): 672 def set_primary_dir(self, d):
673 SuiteModel._set_primary_dir(self, d) 673 SuiteModel.set_primary_dir(self, d)
674 self._suiteRootDir = dirname(d) 674 self._suiteRootDir = dirname(d)
675 675
676 def _importee_dir(self, importer_dir, suitename): 676 def importee_dir(self, importer_dir, suitename):
677 if self.suitenamemap.has_key(suitename): 677 if self.suitenamemap.has_key(suitename):
678 suitename = self.suitenamemap[suitename] 678 suitename = self.suitenamemap[suitename]
679 return join(dirname(importer_dir), suitename) 679 return join(dirname(importer_dir), suitename)
680 680
681 class NestedImportsSuiteModel(SuiteModel): 681 class NestedImportsSuiteModel(SuiteModel):
686 def __init__(self, primaryDir, option, suitemap): 686 def __init__(self, primaryDir, option, suitemap):
687 SuiteModel.__init__(self) 687 SuiteModel.__init__(self)
688 self._primaryDir = primaryDir 688 self._primaryDir = primaryDir
689 self._create_suitenamemap(option[len('nested:'):], suitemap) 689 self._create_suitenamemap(option[len('nested:'):], suitemap)
690 690
691 def _find_suite_dir(self, name): 691 def find_suite_dir(self, name):
692 return self._search_dir(join(self._primaryDir, self._imported_suites_dirname()), self._mxDirName(name)) 692 return self._search_dir(join(self._primaryDir, self._imported_suites_dirname()), self._mxDirName(name))
693 693
694 def _importee_dir(self, importer_dir, suitename): 694 def importee_dir(self, importer_dir, suitename):
695 if self.suitenamemap.has_key(suitename): 695 if self.suitenamemap.has_key(suitename):
696 suitename = self.suitenamemap[suitename] 696 suitename = self.suitenamemap[suitename]
697 if basename(importer_dir) == basename(self._primaryDir): 697 if basename(importer_dir) == basename(self._primaryDir):
698 # primary is importer 698 # primary is importer
699 this_imported_suites_dirname = join(importer_dir, self._imported_suites_dirname()) 699 this_imported_suites_dirname = join(importer_dir, self._imported_suites_dirname())
701 os.mkdir(this_imported_suites_dirname) 701 os.mkdir(this_imported_suites_dirname)
702 return join(this_imported_suites_dirname, suitename) 702 return join(this_imported_suites_dirname, suitename)
703 else: 703 else:
704 return join(dirname(importer_dir), suitename) 704 return join(dirname(importer_dir), suitename)
705 705
706 def _nestedsuites_dirname(self): 706 def nestedsuites_dirname(self):
707 return self._imported_suites_dirname() 707 return self._imported_suites_dirname()
708 708
709 class PathSuiteModel(SuiteModel): 709 class PathSuiteModel(SuiteModel):
710 """The most general model. Uses a map from suitename to URL/path provided by the user""" 710 """The most general model. Uses a map from suitename to URL/path provided by the user"""
711 def __init__(self, path): 711 def __init__(self, path):
720 else: 720 else:
721 suitename = basename(pair[0]) 721 suitename = basename(pair[0])
722 suiteurl = pair[0] 722 suiteurl = pair[0]
723 self.suit_to_url[suitename] = suiteurl 723 self.suit_to_url[suitename] = suiteurl
724 724
725 def _find_suite_dir(self, suitename): 725 def find_suite_dir(self, suitename):
726 if self.suit_to_url.has_key(suitename): 726 if self.suit_to_url.has_key(suitename):
727 return self.suit_to_url[suitename] 727 return self.suit_to_url[suitename]
728 else: 728 else:
729 return None 729 return None
730 730
731 def _importee_dir(self, importer_dir, suitename): 731 def importee_dir(self, importer_dir, suitename):
732 if suitename in self.suit_to_url: 732 if suitename in self.suit_to_url:
733 return self.suit_to_url[suitename] 733 return self.suit_to_url[suitename]
734 else: 734 else:
735 abort('suite ' + suitename + ' not found') 735 abort('suite ' + suitename + ' not found')
736 736
738 def __init__(self, name, version): 738 def __init__(self, name, version):
739 self.name = name 739 self.name = name
740 self.version = version 740 self.version = version
741 741
742 @staticmethod 742 @staticmethod
743 def _parse_specification(specification): 743 def parse_specification(specification):
744 pair = specification.split(',') 744 pair = specification.split(',')
745 name = pair[0] 745 name = pair[0]
746 if len(pair) > 1: 746 if len(pair) > 1:
747 version = pair[1] 747 version = pair[1]
748 else: 748 else:
749 version = None 749 version = None
750 return SuiteImport(name, version) 750 return SuiteImport(name, version)
751 751
752 @staticmethod 752 @staticmethod
753 def _tostring(name, version): 753 def tostring(name, version):
754 return name + ',' + version 754 return name + ',' + version
755 755
756 def __str__(self): 756 def __str__(self):
757 return self.name + ',' + self.version 757 return self.name + ',' + self.version
758 758
765 self.dists = [] 765 self.dists = []
766 self.imports = [] 766 self.imports = []
767 self.commands = None 767 self.commands = None
768 self.primary = primary 768 self.primary = primary
769 self.name = _suitename(mxDir) # validated in _load_projects 769 self.name = _suitename(mxDir) # validated in _load_projects
770 self.version = None # _hg.tip checks current version if not None
771 # TODO this forces hg to be run every time mx is run
772 #self.version = _hg.tip(self, False)
773 if load: 770 if load:
774 # load suites bottom up to make sure command overriding works properly 771 # load suites bottom up to make sure command overriding works properly
775 self._load_imports() 772 self._load_imports()
776 self._load_env() 773 self._load_env()
777 self._load_commands() 774 self._load_commands()
778 _suites[self.name] = self 775 _suites[self.name] = self
779 776
780 def __str__(self): 777 def __str__(self):
781 return self.name 778 return self.name
779
780 def version(self, abortOnError=True):
781 # we do not cache the version
782 return _hg.tip(self.dir, abortOnError)
782 783
783 def _load_projects(self): 784 def _load_projects(self):
784 libsMap = dict() 785 libsMap = dict()
785 projsMap = dict() 786 projsMap = dict()
786 distsMap = dict() 787 distsMap = dict()
875 876
876 if self.name is None: 877 if self.name is None:
877 abort('Missing "suite=<name>" in ' + projectsFile) 878 abort('Missing "suite=<name>" in ' + projectsFile)
878 879
879 def _commands_name(self): 880 def _commands_name(self):
880 return 'mx_' + self.name 881 return 'mx_' + self.name.replace('-','_')
881 882
882 def _find_commands(self, name): 883 def _find_commands(self, name):
883 commandsPath = join(self.mxDir, name + '.py') 884 commandsPath = join(self.mxDir, name + '.py')
884 if exists(commandsPath): 885 if exists(commandsPath):
885 return name 886 return name
910 self.mx_post_parse_cmd_line = mod.mx_post_parse_cmd_line 911 self.mx_post_parse_cmd_line = mod.mx_post_parse_cmd_line
911 912
912 mod.mx_init(self) 913 mod.mx_init(self)
913 self.commands = mod 914 self.commands = mod
914 915
915 def _visit_imports(self, visitor, **extra_args): 916 def visit_imports(self, visitor, **extra_args):
916 """ 917 """
917 Visitor support for the imports file. 918 Visitor support for the imports file.
918 For each line of the imports file that specifies an import, the visitor function is 919 For each line of the imports file that specifies an import, the visitor function is
919 called with this suite, a SuiteImport instance created from the line and any extra args 920 called with this suite, a SuiteImport instance created from the line and any extra args
920 passed to this call. In addition, if extra_args contains a key 'update_versions' that is True, 921 passed to this call. In addition, if extra_args contains a key 'update_versions' that is True,
921 a StringIO value is added to extra_args with key 'updated_imports', and the visitor is responsible 922 a StringIO value is added to extra_args with key 'updated_imports', and the visitor is responsible
922 for writing a (possibly) updated import line to the file, and the file is (possibly) updated after 923 for writing a (possibly) updated import line to the file, and the file is (possibly) updated after
923 all imports are processed. 924 all imports are processed.
924 N.B. There is no built-in support for avoiding visiting the same suite multiple times, 925 N.B. There is no built-in support for avoiding visiting the same suite multiple times,
925 as this function only visits the imports of a singkle suite. If a (recursive) visitor function 926 as this function only visits the imports of a single suite. If a (recursive) visitor function
926 wishes to visit a suite exactly once, it must manage that through extra_args. 927 wishes to visit a suite exactly once, it must manage that through extra_args.
927 """ 928 """
928 importsFile = join(self.mxDir, 'imports') 929 importsFile = join(self.mxDir, 'imports')
929 if exists(importsFile): 930 if exists(importsFile):
930 update_versions = extra_args.has_key('update_versions') and extra_args['update_versions'] 931 update_versions = extra_args.has_key('update_versions') and extra_args['update_versions']
935 sline = line.strip() 936 sline = line.strip()
936 if len(sline) == 0 or sline.startswith('#'): 937 if len(sline) == 0 or sline.startswith('#'):
937 if out is not None: 938 if out is not None:
938 out.write(sline + '\n') 939 out.write(sline + '\n')
939 continue 940 continue
940 suite_import = SuiteImport._parse_specification(line.strip()) 941 suite_import = SuiteImport.parse_specification(line.strip())
941 visitor(self, suite_import, **extra_args) 942 visitor(self, suite_import, **extra_args)
942 943
943 if out is not None: 944 if out is not None:
944 update_file(importsFile, out.getvalue()) 945 update_file(importsFile, out.getvalue())
945 946
946 @staticmethod 947 @staticmethod
947 def _find_and_loadsuite(suite, suite_import, **extra_args): 948 def _find_and_loadsuite(importing_suite, suite_import, **extra_args):
948 """visitor for the initial suite load""" 949 """visitor for the initial suite load"""
949 importMxDir = _src_suitemodel._find_suite_dir(suite_import.name) 950 importMxDir = _src_suitemodel.find_suite_dir(suite_import.name)
950 if importMxDir is None: 951 if importMxDir is None:
951 abort('import ' + suite_import.name + ' not found') 952 abort('import ' + suite_import.name + ' not found')
952 suite.imports.append(suite_import) 953 importing_suite.imports.append(suite_import)
953 imported_suite = _loadSuite(importMxDir, False) 954 _loadSuite(importMxDir, False)
954 if imported_suite.version != suite.version: 955 # we do not check at this stage whether the tip version of imported_suite
955 warn('import version of ' + imported_suite.name +' does not match tip of ' + suite.version) 956 # matches that of the import, since during development, this can and will change
956 957
957 def _load_imports(self): 958 def _load_imports(self):
958 self._visit_imports(self._find_and_loadsuite) 959 self.visit_imports(self._find_and_loadsuite)
959 960
960 def _load_env(self): 961 def _load_env(self):
961 e = join(self.mxDir, 'env') 962 e = join(self.mxDir, 'env')
962 if exists(e): 963 if exists(e):
963 with open(e) as f: 964 with open(e) as f:
1318 log('Does not appear to be a valid JDK as ' + rtJarPath + ' does not exist') 1319 log('Does not appear to be a valid JDK as ' + rtJarPath + ' does not exist')
1319 javaHome = None 1320 javaHome = None
1320 else: 1321 else:
1321 break 1322 break
1322 1323
1323 envPath = join(_mainSuite.mxDir, 'env') 1324 envPath = join(_primary_suite.mxDir, 'env')
1324 if ask_yes_no('Persist this setting by adding "JAVA_HOME=' + javaHome + '" to ' + envPath, 'y'): 1325 if ask_yes_no('Persist this setting by adding "JAVA_HOME=' + javaHome + '" to ' + envPath, 'y'):
1325 with open(envPath, 'a') as fp: 1326 with open(envPath, 'a') as fp:
1326 print >> fp, 'JAVA_HOME=' + javaHome 1327 print >> fp, 'JAVA_HOME=' + javaHome
1327 1328
1328 return javaHome 1329 return javaHome
1339 ArgumentParser.__init__(self, prog='mx', conflict_handler='resolve') 1340 ArgumentParser.__init__(self, prog='mx', conflict_handler='resolve')
1340 1341
1341 self.add_argument('-v', action='store_true', dest='verbose', help='enable verbose output') 1342 self.add_argument('-v', action='store_true', dest='verbose', help='enable verbose output')
1342 self.add_argument('-V', action='store_true', dest='very_verbose', help='enable very verbose output') 1343 self.add_argument('-V', action='store_true', dest='very_verbose', help='enable very verbose output')
1343 self.add_argument('-w', action='store_true', dest='warn', help='enable warning messages') 1344 self.add_argument('-w', action='store_true', dest='warn', help='enable warning messages')
1345 self.add_argument('-p', '--primary-suite-path', help='set the primary suite directory', metavar='<path>')
1344 self.add_argument('--dbg', type=int, dest='java_dbg_port', help='make Java processes wait on <port> for a debugger', metavar='<port>') 1346 self.add_argument('--dbg', type=int, dest='java_dbg_port', help='make Java processes wait on <port> for a debugger', metavar='<port>')
1345 self.add_argument('-d', action='store_const', const=8000, dest='java_dbg_port', help='alias for "-dbg 8000"') 1347 self.add_argument('-d', action='store_const', const=8000, dest='java_dbg_port', help='alias for "-dbg 8000"')
1346 self.add_argument('--cp-pfx', dest='cp_prefix', help='class path prefix', metavar='<arg>') 1348 self.add_argument('--cp-pfx', dest='cp_prefix', help='class path prefix', metavar='<arg>')
1347 self.add_argument('--cp-sfx', dest='cp_suffix', help='class path suffix', metavar='<arg>') 1349 self.add_argument('--cp-sfx', dest='cp_suffix', help='class path suffix', metavar='<arg>')
1348 self.add_argument('--J', dest='java_args', help='Java VM arguments (e.g. --J @-dsa)', metavar='@<args>', default='-ea -Xss2m -Xmx1g') 1350 self.add_argument('--J', dest='java_args', help='Java VM arguments (e.g. --J @-dsa)', metavar='@<args>', default='-ea -Xss2m -Xmx1g')
1907 if not suppliedParser: 1909 if not suppliedParser:
1908 parser = ArgumentParser(prog='mx build') 1910 parser = ArgumentParser(prog='mx build')
1909 1911
1910 javaCompliance = java().javaCompliance 1912 javaCompliance = java().javaCompliance
1911 1913
1912 defaultEcjPath = join(_mainSuite.mxDir, 'ecj.jar') 1914 defaultEcjPath = join(_primary_suite.mxDir, 'ecj.jar')
1913 1915
1914 parser = parser if parser is not None else ArgumentParser(prog='mx build') 1916 parser = parser if parser is not None else ArgumentParser(prog='mx build')
1915 parser.add_argument('-f', action='store_true', dest='force', help='force build (disables timestamp checking)') 1917 parser.add_argument('-f', action='store_true', dest='force', help='force build (disables timestamp checking)')
1916 parser.add_argument('-c', action='store_true', dest='clean', help='removes existing build output') 1918 parser.add_argument('-c', action='store_true', dest='clean', help='removes existing build output')
1917 parser.add_argument('--source', dest='compliance', help='Java compliance level for projects without an explicit one', default=str(javaCompliance)) 1919 parser.add_argument('--source', dest='compliance', help='Java compliance level for projects without an explicit one', default=str(javaCompliance))
2226 2228
2227 log('{0} files were modified'.format(len(modified))) 2229 log('{0} files were modified'.format(len(modified)))
2228 if len(modified) != 0: 2230 if len(modified) != 0:
2229 if args.backup: 2231 if args.backup:
2230 backup = os.path.abspath('eclipseformat.backup.zip') 2232 backup = os.path.abspath('eclipseformat.backup.zip')
2231 arcbase = _mainSuite.dir 2233 arcbase = _primary_suite.dir
2232 zf = zipfile.ZipFile(backup, 'w', zipfile.ZIP_DEFLATED) 2234 zf = zipfile.ZipFile(backup, 'w', zipfile.ZIP_DEFLATED)
2233 for fi in modified: 2235 for fi in modified:
2234 arcname = os.path.relpath(fi.path, arcbase).replace(os.sep, '/') 2236 arcname = os.path.relpath(fi.path, arcbase).replace(os.sep, '/')
2235 zf.writestr(arcname, fi.content) 2237 zf.writestr(arcname, fi.content)
2236 zf.close() 2238 zf.close()
3123 wsfilename = 'workingsets.xml' 3125 wsfilename = 'workingsets.xml'
3124 wsloc = '.metadata/.plugins/org.eclipse.ui.workbench' 3126 wsloc = '.metadata/.plugins/org.eclipse.ui.workbench'
3125 if os.environ.has_key('WORKSPACE'): 3127 if os.environ.has_key('WORKSPACE'):
3126 expected_wsroot = os.environ['WORKSPACE'] 3128 expected_wsroot = os.environ['WORKSPACE']
3127 else: 3129 else:
3128 expected_wsroot = _mainSuite.dir 3130 expected_wsroot = _primary_suite.dir
3129 3131
3130 wsroot = _find_eclipse_wsroot(expected_wsroot) 3132 wsroot = _find_eclipse_wsroot(expected_wsroot)
3131 if wsroot is None: 3133 if wsroot is None:
3132 # failed to find it 3134 # failed to find it
3133 wsroot = expected_wsroot 3135 wsroot = expected_wsroot
3527 if dirpath == suite.dir: 3529 if dirpath == suite.dir:
3528 # no point in traversing .hg 3530 # no point in traversing .hg
3529 if '.hg' in dirnames: 3531 if '.hg' in dirnames:
3530 dirnames.remove('.hg') 3532 dirnames.remove('.hg')
3531 # if there are nested suites must not scan those now, as they are not in projectDirs 3533 # if there are nested suites must not scan those now, as they are not in projectDirs
3532 if _src_suitemodel._nestedsuites_dirname() in dirnames: 3534 if _src_suitemodel.nestedsuites_dirname() in dirnames:
3533 dirnames.remove(_src_suitemodel._nestedsuites_dirname()) 3535 dirnames.remove(_src_suitemodel.nestedsuites_dirname())
3534 elif dirpath in projectDirs: 3536 elif dirpath in projectDirs:
3535 # don't traverse subdirs of an existing project in this suite 3537 # don't traverse subdirs of an existing project in this suite
3536 dirnames[:] = [] 3538 dirnames[:] = []
3537 else: 3539 else:
3538 projectConfigFiles = frozenset(['.classpath', 'nbproject']) 3540 projectConfigFiles = frozenset(['.classpath', 'nbproject'])
3680 find_packages(p.source_dirs(), pkgs) 3682 find_packages(p.source_dirs(), pkgs)
3681 sp += p.source_dirs() 3683 sp += p.source_dirs()
3682 names.append(p.name) 3684 names.append(p.name)
3683 3685
3684 links = ['-link', 'http://docs.oracle.com/javase/' + str(_java.javaCompliance.value) + '/docs/api/'] 3686 links = ['-link', 'http://docs.oracle.com/javase/' + str(_java.javaCompliance.value) + '/docs/api/']
3685 out = join(_mainSuite.dir, docDir) 3687 out = join(_primary_suite.dir, docDir)
3686 if args.base is not None: 3688 if args.base is not None:
3687 out = join(args.base, docDir) 3689 out = join(args.base, docDir)
3688 cp = classpath() 3690 cp = classpath()
3689 sp = os.pathsep.join(sp) 3691 sp = os.pathsep.join(sp)
3690 nowarnAPI = [] 3692 nowarnAPI = []
3949 return kwargs.pop(0) 3951 return kwargs.pop(0)
3950 return None 3952 return None
3951 3953
3952 def sclone(args): 3954 def sclone(args):
3953 """clone a suite repository, and its imported suites""" 3955 """clone a suite repository, and its imported suites"""
3954 _hg.check(True) 3956 _hg.check()
3955 parser = ArgumentParser(prog='mx sclone') 3957 parser = ArgumentParser(prog='mx sclone')
3956 parser.add_argument('--source', help='url/path of repo containing suite', metavar='<url>') 3958 parser.add_argument('--source', help='url/path of repo containing suite', metavar='<url>')
3957 parser.add_argument('--dest', help='destination directory (default basename of source)', metavar='<path>') 3959 parser.add_argument('--dest', help='destination directory (default basename of source)', metavar='<path>')
3958 parser.add_argument("--no-imports", action='store_true', help='do not clone imported suites') 3960 parser.add_argument("--no-imports", action='store_true', help='do not clone imported suites')
3959 parser.add_argument('nonKWArgs', nargs=REMAINDER, metavar='source [dest]...') 3961 parser.add_argument('nonKWArgs', nargs=REMAINDER, metavar='source [dest]...')
3966 if len(args.nonKWArgs) > 0: 3968 if len(args.nonKWArgs) > 0:
3967 abort('unrecognized args: ' + ' '.join(args.nonKWArgs)) 3969 abort('unrecognized args: ' + ' '.join(args.nonKWArgs))
3968 3970
3969 if args.source is None: 3971 if args.source is None:
3970 # must be primary suite and dest is required 3972 # must be primary suite and dest is required
3971 if _mainSuite is None: 3973 if _primary_suite is None:
3972 abort('--source missing and no primary suite found') 3974 abort('--source missing and no primary suite found')
3973 if args.dest is None: 3975 if args.dest is None:
3974 abort('--dest required when --source is not given') 3976 abort('--dest required when --source is not given')
3975 source = _mainSuite.dir 3977 source = _primary_suite.dir
3976 else: 3978 else:
3977 source = args.source 3979 source = args.source
3978 3980
3979 if args.dest is not None: 3981 if args.dest is not None:
3980 dest = args.dest 3982 dest = args.dest
3981 else: 3983 else:
3982 dest = basename(source) 3984 dest = basename(source)
3983 3985
3984 dest = os.path.abspath(dest) 3986 dest = os.path.abspath(dest)
3985 # We can now set the primary dir for the src/dst suitemodel 3987 # We can now set the primary dir for the src/dst suitemodel
3986 _dst_suitemodel._set_primary_dir(dest) 3988 _dst_suitemodel.set_primary_dir(dest)
3987 _src_suitemodel._set_primary_dir(source) 3989 _src_suitemodel.set_primary_dir(source)
3988 3990
3989 _sclone(source, dest, None, args.no_imports) 3991 _sclone(source, dest, None, args.no_imports)
3990 3992
3991 def _sclone(source, dest, version, no_imports): 3993 def _sclone(source, dest, version, no_imports):
3992 cmd = ['hg', 'clone'] 3994 cmd = ['hg', 'clone']
4004 return None 4006 return None
4005 4007
4006 # create a Suite (without loading) to enable imports visitor 4008 # create a Suite (without loading) to enable imports visitor
4007 s = Suite(mxDir, False, load=False) 4009 s = Suite(mxDir, False, load=False)
4008 if not no_imports: 4010 if not no_imports:
4009 s._visit_imports(_scloneimports_visitor, source=source) 4011 s.visit_imports(_scloneimports_visitor, source=source)
4010 return s 4012 return s
4011 4013
4012 def _scloneimports_visitor(s, suite_import, source, **extra_args): 4014 def _scloneimports_visitor(s, suite_import, source, **extra_args):
4013 """ 4015 """
4014 cloneimports visitor for Suite._visit_imports. 4016 cloneimports visitor for Suite.visit_imports.
4015 The destination information is encapsulated by 's' 4017 The destination information is encapsulated by 's'
4016 """ 4018 """
4017 _scloneimports(s, suite_import, source) 4019 _scloneimports(s, suite_import, source)
4018 4020
4019 def _scloneimports_suitehelper(sdir): 4021 def _scloneimports_suitehelper(sdir):
4024 # create a Suite (without loading) to enable imports visitor 4026 # create a Suite (without loading) to enable imports visitor
4025 return Suite(mxDir, False, load=False) 4027 return Suite(mxDir, False, load=False)
4026 4028
4027 def _scloneimports(s, suite_import, source): 4029 def _scloneimports(s, suite_import, source):
4028 # clone first, then visit imports once we can locate them 4030 # clone first, then visit imports once we can locate them
4029 importee_source = _src_suitemodel._importee_dir(source, suite_import.name) 4031 importee_source = _src_suitemodel.importee_dir(source, suite_import.name)
4030 importee_dest = _dst_suitemodel._importee_dir(s.dir, suite_import.name) 4032 importee_dest = _dst_suitemodel.importee_dir(s.dir, suite_import.name)
4031 if exists(importee_dest): 4033 if exists(importee_dest):
4032 # already exists in the suite model, but may be wrong version 4034 # already exists in the suite model, but may be wrong version
4033 importee_suite = _scloneimports_suitehelper(importee_dest) 4035 importee_suite = _scloneimports_suitehelper(importee_dest)
4034 if suite_import.version is not None and importee_suite.version != suite_import.version: 4036 if suite_import.version is not None and importee_suite.version() != suite_import.version:
4035 abort("import version of " + suite_import.name + " in " + s.name + " does not match the version in already existing suite: " + importee_suite.dir) 4037 abort("imported version of " + suite_import.name + " in " + s.name + " does not match the version in already existing suite: " + importee_suite.dir)
4036 importee_suite._visit_imports(_scloneimports_visitor, source=importee_source) 4038 importee_suite.visit_imports(_scloneimports_visitor, source=importee_source)
4037 else: 4039 else:
4038 _sclone(importee_source, importee_dest, suite_import.version, False) 4040 _sclone(importee_source, importee_dest, suite_import.version, False)
4039 # _clone handles the recursive visit of the new imports 4041 # _clone handles the recursive visit of the new imports
4040 4042
4041 def scloneimports(args): 4043 def scloneimports(args):
4042 """clone the imports of an existing suite""" 4044 """clone the imports of an existing suite"""
4043 _hg.check(True) 4045 _hg.check()
4044 parser = ArgumentParser(prog='mx scloneimports') 4046 parser = ArgumentParser(prog='mx scloneimports')
4045 parser.add_argument('--source', help='url/path of repo containing suite', metavar='<url>') 4047 parser.add_argument('--source', help='url/path of repo containing suite', metavar='<url>')
4046 parser.add_argument('nonKWArgs', nargs=REMAINDER, metavar='source [dest]...') 4048 parser.add_argument('nonKWArgs', nargs=REMAINDER, metavar='source [dest]...')
4047 args = parser.parse_args(args) 4049 args = parser.parse_args(args)
4048 # check for non keyword args 4050 # check for non keyword args
4059 if default_path is None: 4061 if default_path is None:
4060 abort('no default path in ' + join(args.source, '.hg', 'hgrc')) 4062 abort('no default path in ' + join(args.source, '.hg', 'hgrc'))
4061 4063
4062 # We can now set the primary dir for the dst suitemodel 4064 # We can now set the primary dir for the dst suitemodel
4063 # N.B. source is effectively the destination and the default_path is the (original) source 4065 # N.B. source is effectively the destination and the default_path is the (original) source
4064 _dst_suitemodel._set_primary_dir(args.source) 4066 _dst_suitemodel.set_primary_dir(args.source)
4065 4067
4066 s._visit_imports(_scloneimports_visitor, source=default_path) 4068 s.visit_imports(_scloneimports_visitor, source=default_path)
4067 4069
4068 def _spush_import_visitor(s, suite_import, dest, checks, clonemissing, **extra_args): 4070 def _spush_import_visitor(s, suite_import, dest, checks, clonemissing, **extra_args):
4069 """push visitor for Suite._visit_imports""" 4071 """push visitor for Suite.visit_imports"""
4070 if dest is not None: 4072 if dest is not None:
4071 dest = _dst_suitemodel._importee_dir(dest, suite_import.name) 4073 dest = _dst_suitemodel.importee_dir(dest, suite_import.name)
4072 _spush(suite(suite_import.name), suite_import, dest, checks, clonemissing) 4074 _spush(suite(suite_import.name), suite_import, dest, checks, clonemissing)
4073 4075
4074 def _spush_check_import_visitor(s, suite_import, **extra_args): 4076 def _spush_check_import_visitor(s, suite_import, **extra_args):
4075 """push check visitor for Suite._visit_imports""" 4077 """push check visitor for Suite.visit_imports"""
4076 currentTip = _hg.tip(suite(suite_import.name)) 4078 currentTip = suite(suite_import.name).version()
4077 if currentTip != suite_import.version: 4079 if currentTip != suite_import.version:
4078 abort('import version of ' + suite_import.name + ' in suite ' + s.name + ' does not match tip') 4080 abort('imported version of ' + suite_import.name + ' in suite ' + s.name + ' does not match tip')
4079 4081
4080 def _spush(s, suite_import, dest, checks, clonemissing): 4082 def _spush(s, suite_import, dest, checks, clonemissing):
4081 if checks: 4083 if checks:
4082 if not _hg.can_push(s): 4084 if not _hg.can_push(s):
4083 abort('working directory ' + s.dir + ' contains uncommitted changes, push aborted') 4085 abort('working directory ' + s.dir + ' contains uncommitted changes, push aborted')
4084 4086
4085 # check imports first 4087 # check imports first
4086 if checks: 4088 if checks:
4087 s._visit_imports(_spush_check_import_visitor) 4089 s.visit_imports(_spush_check_import_visitor)
4088 4090
4089 # ok, push imports 4091 # ok, push imports
4090 s._visit_imports(_spush_import_visitor, dest=dest, checks=checks, clonemissing=clonemissing) 4092 s.visit_imports(_spush_import_visitor, dest=dest, checks=checks, clonemissing=clonemissing)
4091 4093
4092 dest_exists = True 4094 dest_exists = True
4093 4095
4094 if clonemissing: 4096 if clonemissing:
4095 if not os.path.exists(dest): 4097 if not os.path.exists(dest):
4117 cmd.append(dest) 4119 cmd.append(dest)
4118 run(cmd) 4120 run(cmd)
4119 4121
4120 def spush(args): 4122 def spush(args):
4121 """push primary suite and all its imports""" 4123 """push primary suite and all its imports"""
4122 _hg.check(True) 4124 _hg.check()
4123 parser = ArgumentParser(prog='mx spush') 4125 parser = ArgumentParser(prog='mx spush')
4124 parser.add_argument('--dest', help='url/path of repo to push to (default as per hg push)', metavar='<path>') 4126 parser.add_argument('--dest', help='url/path of repo to push to (default as per hg push)', metavar='<path>')
4125 parser.add_argument('--no-checks', action='store_true', help='checks on status, versions are disabled') 4127 parser.add_argument('--no-checks', action='store_true', help='checks on status, versions are disabled')
4126 parser.add_argument('--clonemissing', action='store_true', help='clone missing imported repos at destination (forces --no-checks)') 4128 parser.add_argument('--clonemissing', action='store_true', help='clone missing imported repos at destination (forces --no-checks)')
4127 parser.add_argument('nonKWArgs', nargs=REMAINDER, metavar='source [dest]...') 4129 parser.add_argument('nonKWArgs', nargs=REMAINDER, metavar='source [dest]...')
4140 if args.dest is None: 4142 if args.dest is None:
4141 abort('--dest required with --clonemissing') 4143 abort('--dest required with --clonemissing')
4142 args.nochecks = True 4144 args.nochecks = True
4143 4145
4144 if args.dest is not None: 4146 if args.dest is not None:
4145 _dst_suitemodel._set_primary_dir(args.dest) 4147 _dst_suitemodel.set_primary_dir(args.dest)
4146 4148
4147 _spush(s, None, args.dest, not args.no_checks, args.clonemissing) 4149 _spush(s, None, args.dest, not args.no_checks, args.clonemissing)
4148 4150
4149 def _supdate_import_visitor(s, suite_import, **extra_args): 4151 def _supdate_import_visitor(s, suite_import, **extra_args):
4150 _supdate(suite(suite_import.name), suite_import) 4152 _supdate(suite(suite_import.name), suite_import)
4151 4153
4152 def _supdate(s, suite_import): 4154 def _supdate(s, suite_import):
4153 s._visit_imports(_supdate_import_visitor) 4155 s.visit_imports(_supdate_import_visitor)
4154 4156
4155 run(['hg', '-R', s.dir, 'update']) 4157 run(['hg', '-R', s.dir, 'update'])
4156 4158
4157 def supdate(args): 4159 def supdate(args):
4158 """update primary suite and all its imports""" 4160 """update primary suite and all its imports"""
4159 4161
4160 _hg.check(True) 4162 _hg.check()
4161 s = _check_primary_suite() 4163 s = _check_primary_suite()
4162 4164
4163 _supdate(s, None) 4165 _supdate(s, None)
4164 4166
4165 def _scheck_imports_visitor(s, suite_import, update_versions, updated_imports): 4167 def _scheck_imports_visitor(s, suite_import, update_versions, updated_imports):
4166 """checkimportversions visitor for Suite._visit_imports""" 4168 """scheckimports visitor for Suite.visit_imports"""
4167 _scheck_imports(suite(suite_import.name), suite_import, update_versions, updated_imports) 4169 _scheck_imports(s, suite(suite_import.name), suite_import, update_versions, updated_imports)
4168 4170
4169 def _scheck_imports(s, suite_import, update_versions, updated_imports): 4171 def _scheck_imports(importing_suite, imported_suite, suite_import, update_versions, updated_imports):
4170 # check imports recursively 4172 # check imports recursively
4171 s._visit_imports(_scheck_imports_visitor, update_versions=update_versions) 4173 imported_suite.visit_imports(_scheck_imports_visitor, update_versions=update_versions)
4172 4174
4173 currentTip = _hg.tip(s) 4175 currentTip = imported_suite.version()
4174 if currentTip != suite_import.version: 4176 if currentTip != suite_import.version:
4175 print('import version of ' + s.name + ' does not match tip' + (': updating' if update_versions else '')) 4177 print('imported version of ' + imported_suite.name + ' in ' + importing_suite.name + ' does not match tip' + (': updating' if update_versions else ''))
4176 4178
4177 if update_versions: 4179 if update_versions:
4178 suite_import.version = currentTip 4180 suite_import.version = currentTip
4179 line = str(suite_import) 4181 line = str(suite_import)
4180 updated_imports.write(line + '\n') 4182 updated_imports.write(line + '\n')
4182 def scheckimports(args): 4184 def scheckimports(args):
4183 """check that suite import versions are up to date""" 4185 """check that suite import versions are up to date"""
4184 parser = ArgumentParser(prog='mx scheckimports') 4186 parser = ArgumentParser(prog='mx scheckimports')
4185 parser.add_argument('--update-versions', help='update imported version ids', action='store_true') 4187 parser.add_argument('--update-versions', help='update imported version ids', action='store_true')
4186 args = parser.parse_args(args) 4188 args = parser.parse_args(args)
4187 _check_primary_suite()._visit_imports(_scheck_imports_visitor, update_versions=args.update_versions) 4189 _check_primary_suite().visit_imports(_scheck_imports_visitor, update_versions=args.update_versions)
4188 4190
4189 def _spull_import_visitor(s, suite_import, update_versions, updated_imports): 4191 def _spull_import_visitor(s, suite_import, update_versions, updated_imports):
4190 """pull visitor for Suite._visit_imports""" 4192 """pull visitor for Suite.visit_imports"""
4191 _spull(suite(suite_import.name), update_versions, updated_imports) 4193 _spull(suite(suite_import.name), update_versions, updated_imports)
4192 4194
4193 def _spull(s, update_versions, updated_imports): 4195 def _spull(s, update_versions, updated_imports):
4194 _hg.check(True) 4196 _hg.check()
4195 # pull imports first 4197 # pull imports first
4196 s._visit_imports(_spull_import_visitor, update_versions=update_versions) 4198 s.visit_imports(_spull_import_visitor, update_versions=update_versions)
4197 4199
4198 run(['hg', '-R', s.dir, 'pull', '-u']) 4200 run(['hg', '-R', s.dir, 'pull', '-u'])
4199 if update_versions and updated_imports is not None: 4201 if update_versions and updated_imports is not None:
4200 tip = _hg.tip(s) 4202 tip = s.version()
4201 updated_imports.write(SuiteImport._tostring(s.name, tip) + '\n') 4203 updated_imports.write(SuiteImport.tostring(s.name, tip) + '\n')
4202 4204
4203 def spull(args): 4205 def spull(args):
4204 """pull primary suite and all its imports""" 4206 """pull primary suite and all its imports"""
4205 _hg.check(True) 4207 _hg.check()
4206 parser = ArgumentParser(prog='mx spull') 4208 parser = ArgumentParser(prog='mx spull')
4207 parser.add_argument('--update-versions', action='store_true', help='update version ids of imported suites') 4209 parser.add_argument('--update-versions', action='store_true', help='update version ids of imported suites')
4208 args = parser.parse_args(args) 4210 args = parser.parse_args(args)
4209 4211
4210 _spull(_check_primary_suite(), args.update_versions, None) 4212 _spull(_check_primary_suite(), args.update_versions, None)
4381 mxDir = join(d, f) 4383 mxDir = join(d, f)
4382 if exists(mxDir) and isdir(mxDir) and exists(join(mxDir, 'projects')): 4384 if exists(mxDir) and isdir(mxDir) and exists(join(mxDir, 'projects')):
4383 return mxDir 4385 return mxDir
4384 4386
4385 def _check_primary_suite(): 4387 def _check_primary_suite():
4386 if _mainSuite is None: 4388 if _primary_suite is None:
4387 abort('no primary suite found') 4389 abort('no primary suite found')
4388 else: 4390 else:
4389 return _mainSuite 4391 return _primary_suite
4390 4392
4391 def _needs_primary_suite(command): 4393 def _needs_primary_suite(command):
4392 return not command.startswith("sclone") 4394 return not command.startswith("sclone")
4393 4395
4394 def _findPrimarySuiteMxDir(): 4396 def _needs_primary_suite_cl():
4395 # try current working directory first, the look up the tree 4397 return not any("sclone" in s for s in sys.argv[1:])
4396 curdir = os.getcwd() 4398
4397 while curdir: 4399 def _findPrimarySuiteMxDirFrom(d):
4398 mxDir = _is_suite_dir(curdir) 4400 """ search for a suite directory upwards from 'd' """
4401 while d:
4402 mxDir = _is_suite_dir(d)
4399 if mxDir is not None: 4403 if mxDir is not None:
4400 return mxDir 4404 return mxDir
4401 parent = dirname(curdir) 4405 parent = dirname(d)
4402 if curdir == parent: 4406 if d == parent:
4403 return None 4407 return None
4404 curdir = parent 4408 d = parent
4405 4409
4406 return None 4410 return None
4407 4411
4412 def _findPrimarySuiteMxDir():
4413 # check for explicit setting
4414 if _primary_suite_path is not None:
4415 mxDir = _is_suite_dir(_primary_suite_path)
4416 if mxDir is not None:
4417 return mxDir
4418 else:
4419 abort(_primary_suite_path + ' does not contain an mx suite')
4420
4421 # try current working directory first
4422 mxDir = _findPrimarySuiteMxDirFrom(os.getcwd())
4423 if mxDir is not None:
4424 return mxDir
4425 # backwards compatibility: search from path of this file
4426 return _findPrimarySuiteMxDirFrom(dirname(__file__))
4427
4408 def main(): 4428 def main():
4409 SuiteModel._parse_options() 4429 SuiteModel.parse_options()
4410 4430
4411 global _hg 4431 global _hg
4412 _hg = HgConfig() 4432 _hg = HgConfig()
4413 4433
4434 primary_suite_error = 'no primary suite found'
4414 primarySuiteMxDir = _findPrimarySuiteMxDir() 4435 primarySuiteMxDir = _findPrimarySuiteMxDir()
4415 if primarySuiteMxDir: 4436 if primarySuiteMxDir:
4416 _src_suitemodel._set_primary_dir(dirname(primarySuiteMxDir)) 4437 _src_suitemodel.set_primary_dir(dirname(primarySuiteMxDir))
4417 global _mainSuite 4438 global _primary_suite
4418 _mainSuite = _loadSuite(primarySuiteMxDir, True) 4439 _primary_suite = _loadSuite(primarySuiteMxDir, True)
4440 else:
4441 # in general this is an error, except for the sclone/scloneimports commands,
4442 # and an extensions command will likely not parse in this case, as any extra arguments
4443 # will not have been added to _argParser.
4444 # If the command line does not contain a string matching one of the exceptions, we can safely abort,
4445 # but not otherwise, as we can't be sure the string isn't in a value for some other option.
4446 if _needs_primary_suite_cl():
4447 abort(primary_suite_error)
4419 4448
4420 opts, commandAndArgs = _argParser._parse_cmd_line() 4449 opts, commandAndArgs = _argParser._parse_cmd_line()
4421 4450
4422 if primarySuiteMxDir is None: 4451 if primarySuiteMxDir is None:
4423 msg = 'no primary suite found'
4424 if len(commandAndArgs) > 0 and _needs_primary_suite(commandAndArgs[0]): 4452 if len(commandAndArgs) > 0 and _needs_primary_suite(commandAndArgs[0]):
4425 abort(msg) 4453 abort(primary_suite_error)
4426 else: 4454 else:
4427 warn(msg) 4455 warn(primary_suite_error)
4428 4456
4429 global _opts, _java 4457 global _opts, _java
4430 _opts = opts 4458 _opts = opts
4431 _java = JavaConfig(opts) 4459 _java = JavaConfig(opts)
4432 4460