11#! /usr/bin/env python3
2- import argparse , base64 , functools , glob , hashlib , itertools , json , os , pathlib , platform , random , re , shutil , subprocess , tempfile , time , urllib .request , zipfile
2+ import argparse , base64 , collections , functools , glob , hashlib , itertools , json , os , pathlib , platform , random , re , shutil , subprocess , sys , tempfile , time , urllib .request , zipfile
33from typing import List , Tuple
44
55def get_arg (name ):
@@ -14,6 +14,7 @@ def get_arg(name):
1414system = get_arg ("system" ) or {'Darwin' : 'macos' , 'Linux' : 'linux' , 'Windows' : 'windows' }[platform .system ()]
1515classpath_separator = ';' if platform .system () == 'Windows' else ':'
1616mvn = "mvn.cmd" if platform .system () == "Windows" else "mvn"
17+ lombok_version = '1.18.42'
1718
1819def classpath_join (entries ):
1920 return classpath_separator .join (entries )
@@ -28,6 +29,35 @@ def parse_sha() -> str:
2829 if sha :
2930 return sha [:10 ]
3031
32+ def release_notes (version : str ):
33+ with open ('CHANGELOG.md' , 'r' ) as f :
34+ lines = f .readlines ()
35+
36+ # Find the header that starts with "# {version}"
37+ start_idx = None
38+ for i , line in enumerate (lines ):
39+ if line .startswith (f'# { version } ' ):
40+ start_idx = i
41+ break
42+
43+ if start_idx is None :
44+ raise Exception (f"Version { version } not found in CHANGELOG.md" )
45+
46+ # Extract lines after the header until the next header (line starting with #) or end of file
47+ content_lines = []
48+ for i in range (start_idx + 1 , len (lines )):
49+ line = lines [i ]
50+ if line .startswith ('#' ):
51+ break
52+ content_lines .append (line )
53+
54+ # Write to RELEASE_NOTES.md
55+ content = '' .join (content_lines ).strip () + '\n '
56+ with open ('RELEASE_NOTES.md' , 'w' ) as f :
57+ f .write (content )
58+
59+ print (f"Wrote release notes for { version } to RELEASE_NOTES.md" , flush = True )
60+
3161def makedirs (path ):
3262 os .makedirs (path , exist_ok = True )
3363
@@ -88,7 +118,7 @@ def ninja(dir):
88118 total_errors = 0
89119
90120 process = subprocess .Popen (
91- ['ninja' ],
121+ ['ninja' , '-k' , '0' ],
92122 cwd = dir ,
93123 stdout = subprocess .PIPE ,
94124 stderr = subprocess .STDOUT ,
@@ -132,19 +162,62 @@ def fetch_maven(group, name, version, classifier=None, repo='https://repo1.maven
132162def fetch_all_maven (deps , repo = 'https://repo1.maven.org/maven2' ):
133163 return [fetch_maven (dep ['group' ], dep ['name' ], dep ['version' ], repo = dep .get ('repo' , repo )) for dep in deps ]
134164
165+ @functools .lru_cache (maxsize = 1 )
166+ def jdk_version () -> Tuple [int , int , int ]:
167+ output = subprocess .run (['java' , '-version' ], capture_output = True , text = True ).stderr
168+ match = re .search (r'"([^"]+)"' , output )
169+ if not match :
170+ raise Exception (f"Could not parse java version from: { output } " )
171+ version_str = match .group (1 )
172+ if version_str .startswith ('1.' ):
173+ # Old format: 1.8.0_181 -> (8, 0, 181)
174+ parts = version_str .split ('.' )
175+ major = int (parts [1 ])
176+ if len (parts ) > 2 :
177+ minor_patch = parts [2 ].split ('_' )
178+ minor = int (minor_patch [0 ])
179+ patch = int (minor_patch [1 ]) if len (minor_patch ) > 1 else 0
180+ else :
181+ minor = 0
182+ patch = 0
183+ else :
184+ # New format: 11.0.2 -> (11, 0, 2), 17.0.1+12 -> (17, 0, 1)
185+ parts = version_str .split ('.' )
186+ major = int (parts [0 ])
187+ minor = int (parts [1 ]) if len (parts ) > 1 else 0
188+ if len (parts ) > 2 :
189+ patch_str = re .split (r'[+\-]' , parts [2 ])[0 ]
190+ patch = int (patch_str ) if patch_str else 0
191+ else :
192+ patch = 0
193+ return (major , minor , patch )
194+
195+ def javac_sources (sources ):
196+ groups = collections .defaultdict (list )
197+ for path in sources :
198+ groups [os .path .dirname (path )].append (os .path .basename (path ))
199+ sorted_keys = sorted (groups .keys (), key = str .lower )
200+ lines = []
201+ for key in sorted_keys :
202+ sorted_values = sorted (groups [key ], key = str .lower )
203+ lines .append (' ' + key + '/ ' + ' ' .join (sorted_values ))
204+
205+ return '\n ' .join (lines )
206+
135207def javac (sources , target , classpath = [], modulepath = [], add_modules = [], release = '11' , opts = []):
136208 makedirs (target )
137209 classes = {path .stem : path .stat ().st_mtime for path in pathlib .Path (target ).rglob ('*.class' ) if '$' not in path .stem }
138210 newer = lambda path : path .stem not in classes or path .stat ().st_mtime > classes .get (path .stem )
139- new_sources = [path for path in sources if newer (pathlib .Path (path ))]
211+ new_sources = sorted ( [path for path in sources if newer (pathlib .Path (path ))], key = str . lower )
140212 if new_sources :
141- print ('Compiling' , len (new_sources ), 'java files to' , target + ':\n ' , ' \n ' . join (new_sources ), flush = True )
213+ print ('Compiling' , len (new_sources ), 'java files to' , target + ':\n ' + javac_sources (new_sources ), flush = True )
142214 subprocess .check_call ([
143215 'javac' ,
144216 '-encoding' , 'UTF8' ,
145217 '-Xlint:-options' ,
146- * opts ,
147218 '-Xlint:deprecation' ,
219+ * (['-proc:full' , '-J--sun-misc-unsafe-memory-access=allow' ] if jdk_version ()[0 ] >= 23 else []),
220+ * opts ,
148221 '--release' , release ,
149222 * (['--class-path' , classpath_join (classpath + [target ])] if classpath else []),
150223 * (['--module-path' , classpath_join (modulepath )] if modulepath else []),
@@ -164,14 +237,16 @@ def jar(target: str, *content: List[Tuple[str, str]], opts=[]) -> str:
164237
165238@functools .lru_cache (maxsize = 1 )
166239def lombok ():
167- return fetch_maven ('org.projectlombok' , 'lombok' , '1.18.30' )
240+ return fetch_maven ('org.projectlombok' , 'lombok' , lombok_version )
168241
169242def delombok (dirs : List [str ], target : str , classpath : List [str ] = [], modulepath : List [str ] = []):
170243 sources = files (* [dir + "/**/*.java" for dir in dirs ])
171244 if has_newer (sources , files (target + "/**" )):
172245 print ("Delomboking" , * dirs , "to" , target , flush = True )
173- subprocess .check_call (["java" ,
246+ subprocess .check_call ([
247+ "java" ,
174248 "-Dfile.encoding=UTF8" ,
249+ * (['--sun-misc-unsafe-memory-access=allow' ] if jdk_version ()[0 ] >= 23 else []),
175250 "-jar" , lombok (),
176251 "delombok" ,
177252 * dirs ,
0 commit comments