comparison mxtool/mx.py @ 17163:30dda118ef3d

mx: added support for extending distributions; require list literals for list attributes in projects.py
author Doug Simon <doug.simon@oracle.com>
date Fri, 19 Sep 2014 17:46:35 +0200
parents ef5212ce8091
children a8c0553cb2e4
comparison
equal deleted inserted replaced
17162:4a955509b98a 17163:30dda118ef3d
869 def inc(self): 869 def inc(self):
870 self.prefix = ''.rjust(len(self.prefix) + self.indent) 870 self.prefix = ''.rjust(len(self.prefix) + self.indent)
871 def dec(self): 871 def dec(self):
872 self.prefix = ''.rjust(len(self.prefix) - self.indent) 872 self.prefix = ''.rjust(len(self.prefix) - self.indent)
873 873
874 list_attrs = ['urls', 'dependencies', 'sourceUrls', 'sourceDirs', 'annotationProcessors', 'exclude', 'distDependencies']
875
874 for projectsFile in args: 876 for projectsFile in args:
875 suite = _read_projects_file(projectsFile) 877 suite = _read_projects_file(projectsFile)
876 def print_attrs(p, name, attrs, listKeys, is_last=False): 878 def print_attrs(p, name, attrs, is_last=False):
877 p.println('"' + name + '" : {') 879 p.println('"' + name + '" : {')
878 p.inc() 880 p.inc()
879 for n, v in attrs.iteritems(): 881 for n, v in attrs.iteritems():
880 if n in listKeys: 882 if n in list_attrs:
881 if len(v) == 0: 883 if len(v) == 0:
882 p.println('"{}" : [],'.format(n)) 884 p.println('"{}" : [],'.format(n))
883 else: 885 else:
884 p.println('"{}" : ['.format(n)) 886 v = [e.strip() for e in v.split(',')]
885 p.inc() 887 if len(v) == 1:
886 for e in v.split(','): 888 p.println('"{}" : ["{}"],'.format(n, v[0]))
887 p.println('"' + e.strip() + '",') 889 else:
888 p.dec() 890 p.println('"{}" : ['.format(n))
889 p.println('],') 891 p.inc()
892 for e in v:
893 p.println('"' + e + '",')
894 p.dec()
895 p.println('],')
890 else: 896 else:
891 p.println('"{}" : "{}",'.format(n, v)) 897 p.println('"{}" : "{}",'.format(n, v))
892 p.dec() 898 p.dec()
893 if is_last: 899 if is_last:
894 p.println('}') 900 p.println('}')
902 p.println('"' + sname + '" : {') 908 p.println('"' + sname + '" : {')
903 p.inc() 909 p.inc()
904 i = 0 910 i = 0
905 for name, attrs in section.iteritems(): 911 for name, attrs in section.iteritems():
906 i = i + 1 912 i = i + 1
907 print_attrs(p, name, attrs, ['urls', 'dependencies', 'sourceUrls'], i == len(section)) 913 print_attrs(p, name, attrs, i == len(section))
908 914
909 p.dec() 915 p.dec()
910 if is_last: 916 if is_last:
911 p.println('}') 917 p.println('}')
912 else: 918 else:
916 existing, projectsPyFile = _load_suite_dict(dirname(projectsFile)) 922 existing, projectsPyFile = _load_suite_dict(dirname(projectsFile))
917 if existing: 923 if existing:
918 assert existing['name'] == suite.pop('name') 924 assert existing['name'] == suite.pop('name')
919 assert existing['mxversion'] == suite.pop('mxversion') 925 assert existing['mxversion'] == suite.pop('mxversion')
920 for s in ['projects', 'libraries', 'jrelibraries', 'distributions']: 926 for s in ['projects', 'libraries', 'jrelibraries', 'distributions']:
927 section = suite[s]
921 for k in existing[s].iterkeys(): 928 for k in existing[s].iterkeys():
922 suite[s].pop(k) 929 duplicate = section.pop(k)
923 if len(suite[s]) == 0: 930 if duplicate and s == 'distributions':
931 original = existing[s][k]
932 extensions = [d for d in duplicate['dependencies'].split(',') if d not in original['dependencies']]
933 if len(extensions):
934 extensions = ','.join(extensions)
935 suite.setdefault('distribution_extensions', {})[k] = {'dependencies' : extensions}
936 if len(section) == 0:
924 suite.pop(s) 937 suite.pop(s)
925 938
926 if len(suite): 939 if len(suite):
927 out = StringIO.StringIO() 940 out = StringIO.StringIO()
928 p = Printer(out, 2) 941 p = Printer(out, 2)
932 p.println('"mxversion" : "' + suite['mxversion'] + '",') 945 p.println('"mxversion" : "' + suite['mxversion'] + '",')
933 p.println('"name" : "' + suite['name'] + '",') 946 p.println('"name" : "' + suite['name'] + '",')
934 print_section(p, 'libraries', suite) 947 print_section(p, 'libraries', suite)
935 print_section(p, 'jrelibraries', suite) 948 print_section(p, 'jrelibraries', suite)
936 print_section(p, 'projects', suite) 949 print_section(p, 'projects', suite)
937 print_section(p, 'distributions', suite, is_last=True) 950 print_section(p, 'distributions', suite)
951 if existing and suite.has_key('distribution_extensions'):
952 print_section(p, 'distribution_extensions', suite, is_last=True)
953
938 p.dec() 954 p.dec()
939 p.println('}') 955 p.println('}')
940 956
941 with open(projectsPyFile, 'w') as fp: 957 with open(projectsPyFile, 'w') as fp:
942 fp.write(out.getvalue()) 958 fp.write(out.getvalue())
979 del sys.path[0] 995 del sys.path[0]
980 996
981 if not hasattr(module, dictName): 997 if not hasattr(module, dictName):
982 abort(modulePath + ' must define a variable named "' + dictName + '"') 998 abort(modulePath + ' must define a variable named "' + dictName + '"')
983 d = getattr(module, dictName) 999 d = getattr(module, dictName)
984 sections = ['projects', 'libraries', 'jrelibraries', 'distributions'] + ([] if suite else ['name', 'mxversion']) 1000 sections = ['projects', 'libraries', 'jrelibraries', 'distributions'] + (['distribution_extensions'] if suite else ['name', 'mxversion'])
985 unknown = d.viewkeys() - sections 1001 unknown = d.viewkeys() - sections
986 if unknown: 1002 if unknown:
987 abort(modulePath + ' defines unsupported suite sections: ' + ', '.join(unknown)) 1003 abort(modulePath + ' defines unsupported suite sections: ' + ', '.join(unknown))
988 1004
989 if suite is None: 1005 if suite is None:
998 else: 1014 else:
999 conflicting = additional.viewkeys() & existing.viewkeys() 1015 conflicting = additional.viewkeys() & existing.viewkeys()
1000 if conflicting: 1016 if conflicting:
1001 abort(modulePath + ' redefines: ' + ', '.join(conflicting)) 1017 abort(modulePath + ' redefines: ' + ', '.join(conflicting))
1002 existing.update(additional) 1018 existing.update(additional)
1019 distExtensions = d.get('distribution_extensions')
1020 if distExtensions:
1021 existing = suite['distributions']
1022 for n, attrs in distExtensions.iteritems():
1023 original = existing.get(n)
1024 if not original:
1025 abort('cannot extend non-existing distribution ' + n)
1026 for k, v in attrs.iteritems():
1027 if k != 'dependencies':
1028 abort('Only the dependencies of distribution ' + n + ' can be extended')
1029 if not isinstance(v, types.ListType):
1030 abort('distribution_extensions.' + n + '.dependencies must be a list')
1031 original['dependencies'] += v
1003 1032
1004 dictName = 'extra' 1033 dictName = 'extra'
1005 moduleName = 'projects' + str(suffix) 1034 moduleName = 'projects' + str(suffix)
1006 modulePath = join(mxDir, moduleName + '.py') 1035 modulePath = join(mxDir, moduleName + '.py')
1007 suffix = suffix + 1 1036 suffix = suffix + 1
1054 libsMap = suiteDict['libraries'] 1083 libsMap = suiteDict['libraries']
1055 jreLibsMap = suiteDict['jrelibraries'] 1084 jreLibsMap = suiteDict['jrelibraries']
1056 projsMap = suiteDict['projects'] 1085 projsMap = suiteDict['projects']
1057 distsMap = suiteDict['distributions'] 1086 distsMap = suiteDict['distributions']
1058 1087
1059 def pop_list(attrs, name): 1088 def pop_list(attrs, name, context):
1060 v = attrs.pop(name, None) 1089 v = attrs.pop(name, None)
1061 if isinstance(v, list): 1090 if not v:
1062 return v
1063 if v is None or len(v.strip()) == 0:
1064 return [] 1091 return []
1065 return [n.strip() for n in v.split(',')] 1092 if not isinstance(v, list):
1093 abort('Attribute "' + name + '" for ' + context + ' must be a list')
1094 return v
1066 1095
1067 for name, attrs in projsMap.iteritems(): 1096 for name, attrs in projsMap.iteritems():
1068 srcDirs = pop_list(attrs, 'sourceDirs') 1097 context = 'project ' + name
1069 deps = pop_list(attrs, 'dependencies') 1098 srcDirs = pop_list(attrs, 'sourceDirs', context)
1070 ap = pop_list(attrs, 'annotationProcessors') 1099 deps = pop_list(attrs, 'dependencies', context)
1100 ap = pop_list(attrs, 'annotationProcessors', context)
1071 javaCompliance = attrs.pop('javaCompliance', None) 1101 javaCompliance = attrs.pop('javaCompliance', None)
1072 subDir = attrs.pop('subDir', None) 1102 subDir = attrs.pop('subDir', None)
1073 if subDir is None: 1103 if subDir is None:
1074 d = join(self.dir, name) 1104 d = join(self.dir, name)
1075 else: 1105 else:
1091 optional = attrs.pop('optional', 'true') != 'false' 1121 optional = attrs.pop('optional', 'true') != 'false'
1092 l = JreLibrary(self, name, jar, optional) 1122 l = JreLibrary(self, name, jar, optional)
1093 self.jreLibs.append(l) 1123 self.jreLibs.append(l)
1094 1124
1095 for name, attrs in libsMap.iteritems(): 1125 for name, attrs in libsMap.iteritems():
1126 context = 'library ' + name
1096 if "|" in name: 1127 if "|" in name:
1097 if name.count('|') != 2: 1128 if name.count('|') != 2:
1098 abort("Format error in library name: " + name + "\nsyntax: libname|os-platform|architecture") 1129 abort("Format error in library name: " + name + "\nsyntax: libname|os-platform|architecture")
1099 name, platform, architecture = name.split("|") 1130 name, platform, architecture = name.split("|")
1100 if platform != get_os() or architecture != get_arch(): 1131 if platform != get_os() or architecture != get_arch():
1101 continue 1132 continue
1102 path = attrs.pop('path') 1133 path = attrs.pop('path')
1103 urls = pop_list(attrs, 'urls') 1134 urls = pop_list(attrs, 'urls', context)
1104 sha1 = attrs.pop('sha1', None) 1135 sha1 = attrs.pop('sha1', None)
1105 sourcePath = attrs.pop('sourcePath', None) 1136 sourcePath = attrs.pop('sourcePath', None)
1106 sourceUrls = pop_list(attrs, 'sourceUrls') 1137 sourceUrls = pop_list(attrs, 'sourceUrls', context)
1107 sourceSha1 = attrs.pop('sourceSha1', None) 1138 sourceSha1 = attrs.pop('sourceSha1', None)
1108 deps = pop_list(attrs, 'dependencies') 1139 deps = pop_list(attrs, 'dependencies', context)
1109 # Add support optional libraries once we have a good use case 1140 # Add support optional libraries once we have a good use case
1110 optional = False 1141 optional = False
1111 l = Library(self, name, path, optional, urls, sha1, sourcePath, sourceUrls, sourceSha1, deps) 1142 l = Library(self, name, path, optional, urls, sha1, sourcePath, sourceUrls, sourceSha1, deps)
1112 l.__dict__.update(attrs) 1143 l.__dict__.update(attrs)
1113 self.libs.append(l) 1144 self.libs.append(l)
1114 1145
1115 for name, attrs in distsMap.iteritems(): 1146 for name, attrs in distsMap.iteritems():
1147 context = 'distribution ' + name
1116 path = attrs.pop('path') 1148 path = attrs.pop('path')
1117 sourcesPath = attrs.pop('sourcesPath', None) 1149 sourcesPath = attrs.pop('sourcesPath', None)
1118 deps = pop_list(attrs, 'dependencies') 1150 deps = pop_list(attrs, 'dependencies', context)
1119 mainClass = attrs.pop('mainClass', None) 1151 mainClass = attrs.pop('mainClass', None)
1120 exclDeps = pop_list(attrs, 'exclude') 1152 exclDeps = pop_list(attrs, 'exclude', context)
1121 distDeps = pop_list(attrs, 'distDependencies') 1153 distDeps = pop_list(attrs, 'distDependencies', context)
1122 javaCompliance = attrs.pop('javaCompliance', None) 1154 javaCompliance = attrs.pop('javaCompliance', None)
1123 d = Distribution(self, name, path, sourcesPath, deps, mainClass, exclDeps, distDeps, javaCompliance) 1155 d = Distribution(self, name, path, sourcesPath, deps, mainClass, exclDeps, distDeps, javaCompliance)
1124 d.__dict__.update(attrs) 1156 d.__dict__.update(attrs)
1125 self.dists.append(d) 1157 self.dists.append(d)
1126 1158
1170 arc.zf.writestr(arcname, lp.read(arcname)) 1202 arc.zf.writestr(arcname, lp.read(arcname))
1171 d.add_update_listener(_refineAnnotationProcessorServiceConfig) 1203 d.add_update_listener(_refineAnnotationProcessorServiceConfig)
1172 self.dists.append(d) 1204 self.dists.append(d)
1173 1205
1174 if self.name is None: 1206 if self.name is None:
1175 abort('Missing "suite=<name>" in ' + projectsFile) 1207 abort('Missing "suite=<name>" in ' + projectsPyFile)
1176 1208
1177 def _commands_name(self): 1209 def _commands_name(self):
1178 return 'mx_' + self.name.replace('-', '_') 1210 return 'mx_' + self.name.replace('-', '_')
1179 1211
1180 def _find_commands(self, name): 1212 def _find_commands(self, name):
3054 3086
3055 The exit code of this command reflects how many projects have non-canonical dependencies.""" 3087 The exit code of this command reflects how many projects have non-canonical dependencies."""
3056 3088
3057 nonCanonical = [] 3089 nonCanonical = []
3058 for s in suites(True): 3090 for s in suites(True):
3059 projectsPyFile = join(s.mxDir, 'projects')
3060 if not exists(projectsPyFile):
3061 continue
3062
3063 for p in s.projects: 3091 for p in s.projects:
3064 for pkg in p.defined_java_packages(): 3092 for pkg in p.defined_java_packages():
3065 if not pkg.startswith(p.name): 3093 if not pkg.startswith(p.name):
3066 abort('package in {0} does not have prefix matching project name: {1}'.format(p, pkg)) 3094 abort('package in {0} does not have prefix matching project name: {1}'.format(p, pkg))
3067 3095
3541 3569
3542 generate_eclipse_workingsets() 3570 generate_eclipse_workingsets()
3543 3571
3544 def _check_ide_timestamp(suite, configZip, ide): 3572 def _check_ide_timestamp(suite, configZip, ide):
3545 """return True if and only if the projects file, eclipse-settings files, and mx itself are all older than configZip""" 3573 """return True if and only if the projects file, eclipse-settings files, and mx itself are all older than configZip"""
3546 projectsFile = join(suite.mxDir, 'projects') 3574 projectsPyFiles = [join(suite.mxDir, e) for e in os.listdir(suite.mxDir) if e.startswith('projects') and e.endswith('.py')]
3547 if configZip.isOlderThan(projectsFile): 3575 if configZip.isOlderThan(projectsPyFiles):
3548 return False 3576 return False
3549 # Assume that any mx change might imply changes to the generated IDE files 3577 # Assume that any mx change might imply changes to the generated IDE files
3550 if configZip.isOlderThan(__file__): 3578 if configZip.isOlderThan(__file__):
3551 return False 3579 return False
3552 3580
5085 run([javapExe, '-private', '-verbose', '-classpath', classpath()] + selection) 5113 run([javapExe, '-private', '-verbose', '-classpath', classpath()] + selection)
5086 5114
5087 def show_projects(args): 5115 def show_projects(args):
5088 """show all loaded projects""" 5116 """show all loaded projects"""
5089 for s in suites(): 5117 for s in suites():
5090 projectsFile = join(s.mxDir, 'projects') 5118 if len(s.projects) != 0:
5091 if exists(projectsFile): 5119 log(join(s.mxDir, 'projects*.py'))
5092 log(projectsFile)
5093 for p in s.projects: 5120 for p in s.projects:
5094 log('\t' + p.name) 5121 log('\t' + p.name)
5095 5122
5096 def ask_yes_no(question, default=None): 5123 def ask_yes_no(question, default=None):
5097 """""" 5124 """"""
5175 """ 5202 """
5176 if os.path.isdir(d): 5203 if os.path.isdir(d):
5177 for f in os.listdir(d): 5204 for f in os.listdir(d):
5178 if (mxDirName == None and (f == 'mx' or fnmatch.fnmatch(f, 'mx.*'))) or f == mxDirName: 5205 if (mxDirName == None and (f == 'mx' or fnmatch.fnmatch(f, 'mx.*'))) or f == mxDirName:
5179 mxDir = join(d, f) 5206 mxDir = join(d, f)
5180 if exists(mxDir) and isdir(mxDir) and exists(join(mxDir, 'projects')): 5207 if exists(mxDir) and isdir(mxDir) and (exists(join(mxDir, 'projects.py')) or exists(join(mxDir, 'projects'))):
5181 return mxDir 5208 return mxDir
5182 5209
5183 def _check_primary_suite(): 5210 def _check_primary_suite():
5184 if _primary_suite is None: 5211 if _primary_suite is None:
5185 abort('no primary suite found') 5212 abort('no primary suite found')