Skip to content

Instantly share code, notes, and snippets.

@DrPlantabyte
Last active December 14, 2021 02:41
Show Gist options
  • Save DrPlantabyte/5d72ba879efc78a9c572cb62a7b20e33 to your computer and use it in GitHub Desktop.
Save DrPlantabyte/5d72ba879efc78a9c572cb62a7b20e33 to your computer and use it in GitHub Desktop.
Python script to create a JPMS project without fancy build tools
#!/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