Skip to content

Instantly share code, notes, and snippets.

@mcgivrer
Last active August 2, 2023 23:52
Show Gist options
  • Save mcgivrer/a31510019029eba73edf5721a93c3dec to your computer and use it in GitHub Desktop.
Save mcgivrer/a31510019029eba73edf5721a93c3dec to your computer and use it in GitHub Desktop.
Java build script v4.2: an optimized version with javadoc generation, unit tests execution from /src/test (need Junit5 standalone CLI) and an epub generation (need pandoc) from markdown files in /docs.
# build v4.2
# Copyright 2023 Frederic Delorme (McGivrer) fredericDOTdelormeATgmailDOTcom
.settings/
target/
.idea/
*.iml
.project
.classpath

Build v4.2 README

See corresponding gist

License: MIT

After a basic build.sh v1 script, and an enhance v2, and an optimized v3 build.sh script, Here is the 4.x series providing more features and ease of use. Already allowing a java project build with the maven inspired file structure, particularly adapted to very light machine : ARM architecture based ones a.k.a. RaspberryPi, OrangePi, BananaPi, etc ... or any simple projects. It offers now the integration of last git commit id and the detected java version into the JAR MANIFEST generated file.

It also propose with the 4.X version the JUnit test execution with help of the java library junit-platform-console-standalone-1.10.0.jar to be copied into /lib directory.

It is using only bash, javac, java,jar and git command line instructions. For this created executable .run file run... just be sure that a Java JDK is installed and a correct JAVA_HOME is set.

Project Structure

${projectfolder}/
 |_ docs
 |  |_ images
 |  |_ index.md
 |  |_ preface.md
 |  |_ chapter-01-introduction.md
 |  |_ chapter-02-first-step.md
 |  |_ chapter-99-xxxx-xxx-xx.md
 |_ scripts
 |  |_ build.sh
 |_ lib
 |  |_ test
 |  |  |_ junit-platform-console-standalone-x.y.z.jar
 |  |_ stub.sh
 |_ src
 |  |_ main
 |  |  |_ java
 |  |  |  |_ my
 |  |  |     |_ program
 |  |  |        |_ package
 |  |  |           |_ MyMainClass.java
 |  |  |_ resources
 |  |     |_ i18n
 |  |     |  |_ messages.properties
 |  |     |  |_ messages_en_EN.properties
 |  |     |_ res
 |  |     |  |_ images
 |  |     |  |  |_ mylogo.png
 |  |     |_ app.properties
 |  |_ test
 |  |  |_ java
 |  |  |     |_ program
 |  |  |        |_ package
 |  |  |           |_ MyMainClassTest.java
 |  |  |_ resources
 |  |     |_ i18n
 |  |     |  |_ messages.properties
 |  |     |  |_ messages_en_EN.properties
 |  |     |_ app-test.properties
 |_ .gitignore
 |_ build.properties
 |_ LICENSE
 |_ README.md
 (|_ pom.xml <= if any need to go back to more serious things :P )

Configuration

All the required variables are now defined into the build.properties file:

project.name=[project_name]
project.title=[project_manifest_name]
project.version=[project_version:1.0.0]
project.main.class=my.package.to.my.MainClass
project.author.name='FirstName LastName'
project.author.email=author@email.com
project.build.jdk.version=[JAVA_VERSION:20]
project.build.encoding=UTF-8
project.javadoc.classpath=-group "My package" list.of  package.of my.javadoc -group "Demo" of.my.java.demo

Note! Do not forget to replace the [placeholder] by the real values for your project.

The manifest is generated by the build.sh script.

Then just do a

$> scripts/build.sh a

And a few seconds later, you'll got some beautiful

  • target/build/$PROGRAM_NAME-$PROGRAM_VERSION.run as an autorun executable,
  • and target/$PROGRAM_NAME-$PROGRAM_VERSION.jar as standard java archive program.

Execute the .run file to start your well packaged jar file in an autorun format.

New properties

Some new variables has been added to bring new features to perform javadoc generation :

Tools and Sources versions

THe 2 following variables are now automatically intialized, according to the existing JDK and the current latest commit id:

  • GIT_COMMIT_ID the latest commit id in the current repository,
  • JAVA_BUILD the DK build version.

Compilation Options

Some options can be pass to the javac compiler and the jar builder:

  • COMPILATION_OPTS = "--enable-preview -Xlint:preview -Xlint:unchecked -Xlint:preview"
  • JAR_OPTS= "--enable-preview"

You can also define the jar name with the JAR_NAME vairable:

  • JAR_NAME = $PROGRAM_NAME-$PROGRAM_VERSION.jar

Some help on usage

To get some simple entry point, just do :

$> build.sh -h
build2 command line usage :
---------------------------
$> build [options]
where:
  - a|A|all     : perform all following operations
  - c|C|compile : compile all sources project
  - d|D|doc     : generate javadoc for project
  - e|E|epub    : generate an ebook from docs .md files
  - t|T|test    : execute JUnit tests
  - j|J|jar     : build JAR with all resources
  - w|W|wrap    : Build and wrap jar as a shell script
  - s|S|sign    : Build and wrap signed jar as a shell script
  - r|R|run     : execute (and build if needed) the created JAR

 (c)2022 MIT License Frederic Delorme (@McGivrer) fredericDOTdelormeATgmailDOTcom
 --

2 new entries in the options list:

  • d|D|doc generate javadoc for project identified Packages (see JAVADOC_CLASSPATH variable)
  • t|T|test execute JUnit tests (use the lib/test/junit-platform-console-standalone-x.y.z.jar, defined by the LIB_TEST variable)

McG.

Thanks to https://github.com/maynooth/CS210/wiki/Convert-Java-Executable-to-Linux-Executable for creating a linux executable with concatenated sh and jar file.

# build v4.2
# Copyright 2023 Frederic Delorme (McGivrer) fredericDOTdelormeATgmailDOTcom
project.name=[project_name]
project.title=[project_manifest_name]
project.version=1.0.0
project.main.class=my.package.to.my.MainClass
project.author.name='FirstName LastName'
project.author.email=author@email.com
project.build.jdk.version=[JAVA_VERSION:20]
project.build.encoding=UTF-8
project.javadoc.classpath=-group "My package" list.of package.of my.javadoc -group "Demo" of.my.java.demo
#!/bin/bash
#inspired f<rom build script at https://gist.github.com/mcgivrer/a31510019029eba73edf5721a93c3dec
# build v4.2
# Copyright 2023 Frederic Delorme (McGivrer) fredericDOTdelormeATgmailDOTcom
#
# Your program build definition is now in the build.properties file.
# You can change the build properties file at your convenience.
ENV=build
BUILDPROPS="./$ENV.properties"
function getPropertyValue {
grep "${1}" ${BUILDPROPS} | cut -d'=' -f2
}
export PROGRAM_NAME=$(getPropertyValue project.name)
export PROGRAM_VERSION=$(getPropertyValue project.version)
export PROGRAM_TITLE=$(getPropertyValue project.title)
export MAIN_CLASS=$(getPropertyValue project.main.class)
export PACKAGES_LIST=$(getPropertyValue project.javadoc.packages)
export VENDOR_NAME=$(getPropertyValue project.author.name)
export AUTHOR_NAME=$(getPropertyValue project.author.email)
export SOURCE_VERSION=$(getPropertyValue project.build.jdk.version)
export SRC_ENCODING=$(getPropertyValue project.build.encoding)
export JAVADOC_CLASSPATH=$(getPropertyValue project.javadoc.classpath)
# the tools and sources versions
export GIT_COMMIT_ID=$(git rev-parse HEAD)
export JAVA_BUILD=$(java --version | head -1 | cut -f2 -d' ')
export JUNIT_VERSION=1.9.1
#
# Paths
export SRC=src
export LIBS=lib
export LIB_TEST="./lib/test/junit-platform-console-standalone-${JUNIT_VERSION}.jar"
export TARGET=target
export BUILD=${TARGET}/build
export CLASSES=${TARGET}/classes
export RESOURCES=${SRC}/main/resources
export TESTRESOURCES=${SRC}/test/resources
export COMPILATION_OPTS="--enable-preview -Xlint:preview -Xlint:unchecked -g:source,lines,vars"
export JAR_NAME=${PROGRAM_NAME}-${PROGRAM_VERSION}.jar
# -Xlint:unchecked -Xlint:preview"
export JAR_OPTS=--enable-preview
#
function manifest() {
mkdir ${TARGET}
echo "|_ 0. clear build directory"
rm -Rf ${TARGET}/*
touch ${TARGET}/manifest.mf
# build manifest
echo "|_ 1. Create Manifest file '${TARGET}/manifest.mf'"
echo 'Manifest-Version: 1.0' >${TARGET}/manifest.mf
echo "Created-By: ${JAVA_BUILD} (${VENDOR_NAME})" >>${TARGET}/manifest.mf
echo "Main-Class: ${MAIN_CLASS}" >>${TARGET}/manifest.mf
echo "Implementation-Title: ${PROGRAM_TITLE}" >>${TARGET}/manifest.mf
echo "Implementation-Version: ${PROGRAM_VERSION}-build_${GIT_COMMIT_ID:0:8}" >>${TARGET}/manifest.mf
echo "Implementation-Vendor: ${VENDOR_NAME}" >>${TARGET}/manifest.mf
echo "Implementation-Author: ${AUTHOR_NAME}" >>${TARGET}/manifest.mf
echo " |_ done"
}
#
function compile() {
echo "compile sources "
echo "> from : ${SRC}"
echo "> to : ${CLASSES}"
# prepare target
mkdir -p ${CLASSES}
# Compile class files
rm -Rf ${CLASSES}/*
echo "|_ 2. compile sources from '${SRC}/main' ..."
find ${SRC}/main -name '*.java' >${TARGET}/sources.lst
javac -source ${SOURCE_VERSION} \
-target ${SOURCE_VERSION} \
-encoding ${SRC_ENCODING} \
${COMPILATION_OPTS} \
-classpath "${CLASSES};." \
-d ${TARGET}/classes \
@${TARGET}/sources.lst \
-sourcepath src/main/java/,src/main/resources
echo " done."
}
#
function generatedoc() {
echo "generate Javadoc "
echo "> from : ${SRC}"
echo "> to : ${TARGET}/javadoc"
# prepare target
mkdir -p ${TARGET}/javadoc
# Compile class files
rm -Rf ${TARGET}/javadoc/*
echo "|_ 2-5. generate javadoc from '${JAVADOC_CLASSPATH}' ..."
java -jar ./lib/tools/markdown2html-0.3.1.jar <README.md >${TARGET}/javadoc/overview.html
javadoc ${JAR_OPTS} -source ${SOURCE_VERSION} \
\
-quiet -author -use -version \
-doctitle "<h1>${PROGRAM_TITLE}</h1>" \
-d ${TARGET}/javadoc \
-sourcepath ${SRC}/main/java ${JAVADOC_CLASSPATH} \
-overview ${TARGET}/javadoc/overview.html
echo " done." >>target/build.log #
}
#
function executeTests() {
echo "execute tests"
echo "> from : ${SRC}/test"
echo "> to : ${TARGET}/test-classes"
mkdir -p ${TARGET}/test-classes
rm -Rf ${TARGET}/test-classes/*
echo "copy test resources"
cp -r ./src/test/resources/* ${TARGET}/test-classes
cp -r ${TARGET}/classes/* ${TARGET}/test-classes
echo "compile test classes"
#list test sources
find ./src/test -name '*.java' >${TARGET}/test-sources.lst
javac -source ${SOURCE_VERSION} \
-target ${SOURCE_VERSION} \
-encoding ${SRC_ENCODING} \
${COMPILATION_OPTS} \
-g:source,lines,vars \
-classpath "$LIB_TEST;${CLASSES};." \
-d ${TARGET}/test-classes @${TARGET}/test-sources.lst \
-sourcepath src/main/java/,src/test/java/,src/test/resources
echo "execute tests through JUnit"
java ${JAR_OPTS} -jar "$LIB_TEST" --class-path "${CLASSES};${TARGET}/test-classes;${SRC}/test/resources;" --scan-class-path
echo "done."
}
#
function createJar() {
echo "|_ 3. package jar file '${TARGET}/${JAR_NAME}'..."
if ([ $(ls ${CLASSES} | wc -l | grep -w "0") ]); then
echo 'No compiled class files'
else
# Build JAR
jar -cfmv ${TARGET}/${JAR_NAME} ${TARGET}/manifest.mf -C ${CLASSES} . -C ${RESOURCES} .
fi
echo " |_ done."
}
#
function wrapJar() {
# create runnable program
echo "|_ 4. create run file '${BUILD}/${PROGRAM_NAME}-${PROGRAM_VERSION}.run'..."
mkdir -p ${BUILD}
cat ${LIBS}/stub.sh ${TARGET}/${PROGRAM_NAME}-${PROGRAM_VERSION}.jar >${BUILD}/${PROGRAM_NAME}-${PROGRAM_VERSION}.run
chmod +x ${BUILD}/${PROGRAM_NAME}-${PROGRAM_VERSION}.run
echo " |_ done."
}
#
function executeJar() {
manifest
compile
createJar
echo "|_ 5.Execute just created JAR ${TARGET}/${PROGRAM_NAME}-${PROGRAM_VERSION}.jar"
java ${JAR_OPTS} -jar ${TARGET}/${PROGRAM_NAME}-${PROGRAM_VERSION}.jar "$@"
}
#
function sign() {
# must see here: https://docs.oracle.com/javase/tutorial/security/toolsign/signer.html
echo "not already implemented... sorry"
}
#
function generateEpub() {
rm -Rf $TARGET/book/
mkdir $TARGET/book
cat docs/*.yml >$TARGET/book/book.mdo
cat docs/chapter-*.md >>$TARGET/book/book.mdo
mv $TARGET/book/book.mdo $TARGET/book/book.md
pandoc $TARGET/book/book.md --resource-path=./docs -o $TARGET/book/book-$PROGRAM_NAME-$PROGRAM_VERSION.epub
echo "|_ 6. generate ebook to $TARGET/book/book-$PROGRAM_NAME-$PROGRAM_VERSION.epub"
}
#
function help() {
echo "build2 command line usage :"
echo "---------------------------"
echo "NOTE: Do not forget to provide a 'build.properties' file containing required key=value."
echo "$> build2 [options]"
echo "where:"
echo " - a|A|all : perform all following operations"
echo " - c|C|compile : compile all sources project"
echo " - d|D|doc : generate javadoc for project"
echo " - e|E|epub : generate epub as docs for project"
echo " - j|J|jar : build JAR with all resources"
echo " - s|S|sign : Build and wrap signed jar as a shell script"
echo " - t|T|test : execute JUnit tests"
echo " - r|R|run : execute (and build if needed) the created JAR"
echo " - w|W|wrap : Build and wrap jar as a shell script"
echo ""
echo " (c)2022 MIT License Frederic Delorme (@McGivrer) fredericDOTdelormeATgmailDOTcom"
echo " --"
}
#
function run() {
echo "Build of program '${PROGRAM_NAME}-${PROGRAM_VERSION}' ..."
echo "-----------"
case $1 in
a | A | all)
manifest
compile
executeTests
generatedoc
createJar
wrapJar
;;
c | C | compile)
manifest
compile
;;
d | D | doc)
manifest
compile
generatedoc
;;
e | E | epub)
generateEpub
;;
t | T | test)
manifest
compile
executeTests
;;
j | J | jar)
createJar
;;
w | W | wrap)
wrapJar
;;
s | S | sign)
sign $2
;;
r | R | run)
executeJar
;;
h | H | ? | *)
help
;;
esac
echo "-----------"
echo "... done".
}
#
run "$1"
Copyright 2023 Frederic Delorme (McGivrer) fredericDOTdelormeATgmailDOTcom
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#!/bin/sh
# see https://github.com/maynooth/CS210/wiki/Convert-Java-Executable-to-Linux-Executable
# build v4.2
# Copyright 2023 Frederic Delorme (McGivrer) fredericDOTdelormeATgmailDOTcom
MYSELF=`which "$0" 2>/dev/null`
# to adapt java_args according to your owwn needs (preview mode or anything else)
export java_args='--enable-preview'
[ $? -gt 0 -a -f "$0" ] && MYSELF="./$0"
java=java
if test -n "$JAVA_HOME"; then
java="$JAVA_HOME/bin/java"
fi
exec "$java" $java_args -jar $MYSELF "$@"
exit 1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment