Last active
December 14, 2021 02:41
-
-
Save DrPlantabyte/5d72ba879efc78a9c572cb62a7b20e33 to your computer and use it in GitHub Desktop.
Python script to create a JPMS project without fancy build tools
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python3 | |
import os, sys | |
from os import path | |
def main(): | |
print("\tCreating new Java JPMS module project...") | |
project_name = input("Project name: ").strip() | |
if path.exists(project_name): | |
print("Abort: '%s' already exists. ") | |
exit(1) | |
core_name = input("Module root package name: ").strip() | |
if not validate_package_name(core_name): | |
print("'%s' is not a valid package name" % core_name) | |
exit(1) | |
modules = [core_name] | |
app_module = core_name | |
if confirm("Create integration-test module?"): | |
modules.append("%s.test" % core_name) | |
if confirm("Create application module?"): | |
app_module = "%s.app" % core_name | |
modules.append(app_module) | |
# | |
project_dir = project_name | |
build_dir = path.join(project_dir, "build") | |
libs_dir = path.join(project_dir, "dependencies") | |
icon_file = path.join(project_dir, 'icon.png') | |
modules_dir = path.join(project_dir, "modules") | |
javac_args = path.join(project_dir, 'javac-args.txt') | |
javadoc_args = path.join(project_dir, 'javadoc-args.txt') | |
jlink_args = path.join(project_dir, 'jlink-args.txt') | |
jpackage_args = path.join(project_dir, 'jpackage-args.txt') | |
compile_script = path.join(project_dir, 'compile.sh') | |
clean_script = path.join(project_dir, 'clean.sh') | |
# | |
module_sources = ['%s=modules/%s/src' % (m,m) for m in modules] | |
deps_paths = ['build/compile', path.relpath(libs_dir, project_dir)] | |
# | |
print() | |
print('\tProject Structure:') | |
print(project_dir) | |
print(build_dir) | |
print(javac_args) | |
print(javadoc_args) | |
print(jlink_args) | |
print(jpackage_args) | |
for mod in modules: | |
print(path.join(project_dir, 'jar-args_%s.txt' % mod)) | |
print(path.join(project_dir, 'java-args_%s.txt' % mod)) | |
print(libs_dir) | |
print(modules_dir) | |
for mod in modules: | |
#print(path.join(modules_dir, mod)) | |
print(path.join(modules_dir, mod, "src", 'module-info.java')) | |
print(path.join(modules_dir, mod, "src", mod.replace('.','/'), 'Main.java')) | |
print(path.join(modules_dir, mod, "resources"), mod.replace('.','/')) | |
print() | |
if not confirm('Create project?'): | |
print("\tCanceled by user") | |
exit(1) | |
# | |
os.mkdir(project_dir) | |
os.mkdir(build_dir) | |
os.mkdir(libs_dir) | |
with open(compile_script, 'a') as fout: fout.write("""#!/bin/bash | |
javac @javac-args.txt | |
""") | |
with open(clean_script, 'w') as fout: fout.write("""#!/bin/bash | |
rm -rf build/* | |
""") | |
write_to("""-d build/compile --module-source-path modules/*/src --module-path {deps} --module {modules}""".format( | |
deps=os.pathsep.join(deps_paths), modules=','.join(modules) | |
), javac_args) | |
write_to("""-d build/javadoc --module-source-path modules/*/src --module {modules}""".format( | |
modules=','.join(modules) | |
), javadoc_args) | |
for mod in modules: | |
write_to( | |
"""package {mod}; | |
public class Main {{ | |
public static void main(String[] args){{ | |
System.out.println(Main.class); | |
}} | |
}}""".format(mod=mod), | |
path.join(modules_dir, mod, "src", mod.replace('.','/'), 'Main.java') | |
) | |
os.makedirs(path.join(modules_dir, mod, "resources", mod.replace('.','/')), exist_ok=True) | |
write_to( | |
"""--module-path {deps} --module {mod}/{mod}.Main""".format(deps=os.pathsep.join(deps_paths), mod=mod), | |
path.join(project_dir, 'java-args_%s.txt' % mod) | |
) | |
jar_args = path.join(project_dir, 'jar-args_%s.txt' % mod) | |
if mod == core_name: | |
write_to( | |
"""module {mod} {{ | |
exports {mod}; | |
}}""".format(mod=mod), | |
path.join(modules_dir, mod, "src", 'module-info.java') | |
) | |
else: | |
write_to( | |
"""module {mod} {{ | |
exports {mod}; | |
requires {core}; | |
}}""".format(mod=mod, core=core_name), | |
path.join(modules_dir, mod, "src", 'module-info.java') | |
) | |
if mod == app_module: | |
write_to("""--create --file build/jar/{mod}-0.0.0.jar --module-version 0.0.0 --main-class {mod}.Main -C build/compile/{mod} .""".format( mod=mod ), jar_args) | |
write_to("""--output build/jlink/native --module-path {deps} --launcher launch={mod}/{mod}.Main --no-header-files --no-man-pages --add-modules {modules}""".format(deps=os.pathsep.join(deps_paths), mod=mod, modules=','.join(modules)), jlink_args) | |
write_to("""-d build/jpackage --type app-image --name {project} --module {mod}/{mod}.Main --app-version 0.0.0 --copyright "Copyright Me 2022, All rights reserved." --description "Java application" --vendor "Myself, Sole Proprietor" --icon icon.png --module-path {deps} --add-modules {modules}""".format(deps=os.pathsep.join(deps_paths), project=no_space(project_name), mod=mod, modules=','.join(modules)), jpackage_args) | |
else: | |
write_to("""--create --file build/jar/{mod}-0.0.0.jar --module-version 0.0.0 -C build/compile/{mod} .""".format( mod=mod ), jar_args) | |
with open(compile_script, 'a') as fout: fout.write("cp -r modules/{mod}/resources/* build/compile/{mod}\n".format(mod=mod)) | |
with open(icon_file, 'wb') as fout: | |
fout.write( b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00@\x00\x00\x00@\x02\x03\x00\x00\x00\xd7\x07\x99M\x00\x00\x01\x84iCCPICC profile\x00\x00(\x91}\x91=H\xc3P\x14\x85OS\xa5"-\x0ev\x10q\xc8P\x1d\xc4\x82\xa8\x88\xa3V\xa1\x08\x15B\xad\xd0\xaa\x83\xc9K\xff\xa0IC\x92\xe2\xe2(\xb8\x16\x1c\xfcY\xac:\xb88\xeb\xea\xe0*\x08\x82? nnN\x8a.R\xe2}I\xa1E\x8c\x0f.\xef\xe3\xbcw\x0e\xf7\xdd\x07\x08\x8d\n\xd3\xac\xaeq@\xd3m3\x9dL\x88\xd9\xdc\xaa\x18zE\x18\x11\x04\xa9Fef\x19s\x92\x94\x82\xef\xfa\xbaG\x80\xefwq\x9e\xe5\x7f\xef\xcf\x15Q\xf3\x16\x03\x02"\xf1,3L\x9bx\x83xz\xd368\xef\x13GYIV\x89\xcf\x89\xc7Lj\x90\xf8\x91\xeb\x8a\xc7o\x9c\x8b.\x0b<3jf\xd2\xf3\xc4Qb\xb1\xd8\xc1J\x07\xb3\x92\xa9\x11O\x11\xc7TM\xa7|!\xeb\xb1\xcay\x8b\xb3V\xa9\xb1V\x9f\xfc\x85\xe1\xbc\xbe\xb2\xccu\xaa!$\xb1\x88%H\x10\xa1\xa0\x862*\xb0\x11\xa7]\'\xc5B\x9a\xce\x13>\xfeA\xd7/\x91K!W\x19\x8c\x1c\x0b\xa8B\x83\xec\xfa\xc1\xff\xe0\xf7l\xad\xc2\xe4\x84\x97\x14N\x00\xdd/\x8e\xf31\x0c\x84v\x81f\xddq\xbe\x8f\x1d\xa7y\x02\x04\x9f\x81+\xbd\xed\xaf6\x80\x99O\xd2\xebm-v\x04\xf4m\x03\x17\xd7mM\xd9\x03.w\x80\x81\'C6eW\nR\t\x85\x02\xf0~F\xdf\x94\x03\xfao\x81\xde5on\xads\x9c>\x00\x19\x9aU\xea\x0688\x04F\x8a\x94\xbd\xee\xf3\xee\x9e\xce\xb9\xfd{\xa75\xbf\x1f<\x01r\x91q\xe4\xdb\xca\x00\x00\x00\tPLTE\x00\x00\x00\xff\xff\x00\xff\xff\xff\xad}\xa3\x92\x00\x00\x00\tpHYs\x00\x00.#\x00\x00.#\x01x\xa5?v\x00\x00\x00\x07tIME\x07\xe5\x0c\r\x03\x0f\x1e\xc2\x16\x8a\xb8\x00\x00\x00\x19tEXtComment\x00Created with GIMPW\x81\x0e\x17\x00\x00\x005IDAT8\xcbcX\x05\x04\x0cP\x00f\x0f\x98\x00\x03C(\x14\x80\x84\x06J\x00\xc4\x85\x08AX\x03)\x80\x00\x03+0x\xc2\x03\x99\x1e\x18\x81\xc1\x92N\x07I\xbe\x05\x00k\xf9\t\xb0\x00\x90i\xaf\x00\x00\x00\x00IEND\xaeB`\x82' | |
) | |
os.chmod(compile_script, 0o744) | |
os.chmod(clean_script, 0o744) | |
def no_space(s): | |
return s.replace(' ', '-').replace('\t','-').replace('\n','_').replace('\r','') | |
def write_to(content, filepath): | |
parent = path.dirname(path.abspath(filepath)) | |
if not path.isdir(parent): | |
os.makedirs(parent, exist_ok=True) | |
with open(filepath, 'w') as fout: | |
fout.write(content) | |
def confirm(msg="Confirm?"): | |
while True: | |
i = input("%s [y/n] " % msg) | |
if i.lower() in ['y', 'yes']: | |
return True | |
if i.lower() in ['n', 'no']: | |
return False | |
print("unrecognized input, please type 'y' or 'n' and then hit enter.") | |
def validate_package_name(name): | |
valid_chars = "_abcdefghijklmnopqrstuvwxyz.1234567890" | |
valid_first_chars = valid_chars[:-11] | |
parts = name.split('.') | |
for p in parts: | |
if len(p) == 0: return False | |
if p[0] not in valid_first_chars: return False | |
for i in range(0,len(p)): | |
if p[i] not in valid_chars: return False | |
return True | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment