diff options
author | Sven Gothel <[email protected]> | 2019-04-03 06:04:52 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2019-04-03 06:04:52 +0200 |
commit | 00ad70b3bd7f8859c710039857aa7da17a29b3d7 (patch) | |
tree | 6f3652dff1a1db7272b4f3e83ec98eeecf86ad87 | |
parent | 1157b913a068167062c853b4b525954b223a5509 (diff) |
Bug 1369: Source Certification Contract (SCC): Initial SHA256 fingerprint & runtime validation
This change implements a strong SHA256 signature over:
1) source tree inclusive make recipe (SHA256-Source)
2) all class files (SHA256-Classes)
3) all native libraries (SHA256-Natives)
4) the class files as deployed in the jar (SHA256-Classes-this)
5) the native libraries as deployed in the jar (SHA256-Natives-this)
and drops all of these in the deployed Jar file.
This allows SHA256 validation of (4) + (5) at runtime
and further complete validation (1), (2) and (3) offline.
Full SCC would now required (1) - (3) to be placed on a server for further validation.
Optionally we may use GPG <https://gnupg.org/> or PGP to validate the build entity to implement the chain of trust <https://en.wikipedia.org/wiki/Chain_of_trust>
The SHA256 runtime validation is tested via: com.jogamp.common.util.TestVersionInfo
-rwxr-xr-x | make/Manifest | 5 | ||||
-rwxr-xr-x | make/Manifest-android-launcher | 5 | ||||
-rwxr-xr-x | make/Manifest-rt | 5 | ||||
-rwxr-xr-x | make/Manifest-rt-alt | 5 | ||||
-rwxr-xr-x | make/Manifest-rt-android | 5 | ||||
-rwxr-xr-x | make/Manifest-rt-natives | 5 | ||||
-rwxr-xr-x | make/Manifest-rt.cdc | 5 | ||||
-rw-r--r-- | make/build.xml | 268 | ||||
-rwxr-xr-x | make/scripts/runtest.sh | 2 | ||||
-rw-r--r-- | src/java/com/jogamp/common/GlueGenVersion.java | 43 | ||||
-rw-r--r-- | src/java/com/jogamp/common/util/IOUtil.java | 73 | ||||
-rw-r--r-- | src/java/com/jogamp/common/util/JogampVersion.java | 50 | ||||
-rw-r--r-- | src/java/com/jogamp/common/util/SHASum.java | 330 | ||||
-rw-r--r-- | src/java/com/jogamp/common/util/cache/TempJarCache.java | 6 | ||||
-rw-r--r-- | src/junit/com/jogamp/common/util/TestVersionInfo.java | 22 |
15 files changed, 772 insertions, 57 deletions
diff --git a/make/Manifest b/make/Manifest index cab8805..27a9acc 100755 --- a/make/Manifest +++ b/make/Manifest @@ -8,6 +8,11 @@ Implementation-Version: @VERSION@ Implementation-Build: @BUILD_VERSION@ Implementation-Branch: @SCM_BRANCH@ Implementation-Commit: @SCM_COMMIT@ +Implementation-SHA256-Sources: @SHA256_SOURCES@ +Implementation-SHA256-Classes: @SHA256_CLASSES@ +Implementation-SHA256-Classes-this: @SHA256_CLASSES_THIS@ +Implementation-SHA256-Natives: @SHA256_NATIVES@ +Implementation-SHA256-Natives-this: @SHA256_NATIVES_THIS@ Implementation-Vendor: JogAmp Community Implementation-Vendor-Id: com.jogamp Implementation-URL: http://jogamp.org/ diff --git a/make/Manifest-android-launcher b/make/Manifest-android-launcher index 0da49d3..4754474 100755 --- a/make/Manifest-android-launcher +++ b/make/Manifest-android-launcher @@ -8,6 +8,11 @@ Implementation-Version: @VERSION@ Implementation-Build: @BUILD_VERSION@ Implementation-Branch: @SCM_BRANCH@ Implementation-Commit: @SCM_COMMIT@ +Implementation-SHA256-Sources: @SHA256_SOURCES@ +Implementation-SHA256-Classes: @SHA256_CLASSES@ +Implementation-SHA256-Classes-this: @SHA256_CLASSES_THIS@ +Implementation-SHA256-Natives: @SHA256_NATIVES@ +Implementation-SHA256-Natives-this: @SHA256_NATIVES_THIS@ Implementation-Vendor: JogAmp Community Implementation-Vendor-Id: com.jogamp Implementation-URL: http://jogamp.org/ diff --git a/make/Manifest-rt b/make/Manifest-rt index 4a76c0c..98f0e3f 100755 --- a/make/Manifest-rt +++ b/make/Manifest-rt @@ -8,6 +8,11 @@ Implementation-Version: @VERSION@ Implementation-Build: @BUILD_VERSION@ Implementation-Branch: @SCM_BRANCH@ Implementation-Commit: @SCM_COMMIT@ +Implementation-SHA256-Sources: @SHA256_SOURCES@ +Implementation-SHA256-Classes: @SHA256_CLASSES@ +Implementation-SHA256-Classes-this: @SHA256_CLASSES_THIS@ +Implementation-SHA256-Natives: @SHA256_NATIVES@ +Implementation-SHA256-Natives-this: @SHA256_NATIVES_THIS@ Implementation-Vendor: JogAmp Community Implementation-Vendor-Id: com.jogamp Implementation-URL: http://jogamp.org/ diff --git a/make/Manifest-rt-alt b/make/Manifest-rt-alt index d95830e..f577950 100755 --- a/make/Manifest-rt-alt +++ b/make/Manifest-rt-alt @@ -8,6 +8,11 @@ Implementation-Version: @VERSION@ Implementation-Build: @BUILD_VERSION@ Implementation-Branch: @SCM_BRANCH@ Implementation-Commit: @SCM_COMMIT@ +Implementation-SHA256-Sources: @SHA256_SOURCES@ +Implementation-SHA256-Classes: @SHA256_CLASSES@ +Implementation-SHA256-Classes-this: @SHA256_CLASSES_THIS@ +Implementation-SHA256-Natives: @SHA256_NATIVES@ +Implementation-SHA256-Natives-this: @SHA256_NATIVES_THIS@ Implementation-Vendor: JogAmp Community Implementation-Vendor-Id: com.jogamp Implementation-URL: http://jogamp.org/ diff --git a/make/Manifest-rt-android b/make/Manifest-rt-android index bf5f123..16350df 100755 --- a/make/Manifest-rt-android +++ b/make/Manifest-rt-android @@ -8,6 +8,11 @@ Implementation-Version: @VERSION@ Implementation-Build: @BUILD_VERSION@ Implementation-Branch: @SCM_BRANCH@ Implementation-Commit: @SCM_COMMIT@ +Implementation-SHA256-Sources: @SHA256_SOURCES@ +Implementation-SHA256-Classes: @SHA256_CLASSES@ +Implementation-SHA256-Classes-this: @SHA256_CLASSES_THIS@ +Implementation-SHA256-Natives: @SHA256_NATIVES@ +Implementation-SHA256-Natives-this: @SHA256_NATIVES_THIS@ Implementation-Vendor: JogAmp Community Implementation-Vendor-Id: com.jogamp Implementation-URL: http://jogamp.org/ diff --git a/make/Manifest-rt-natives b/make/Manifest-rt-natives index 90c5590..480f765 100755 --- a/make/Manifest-rt-natives +++ b/make/Manifest-rt-natives @@ -8,6 +8,11 @@ Implementation-Version: @VERSION@ Implementation-Build: @BUILD_VERSION@ Implementation-Branch: @SCM_BRANCH@ Implementation-Commit: @SCM_COMMIT@ +Implementation-SHA256-Sources: @SHA256_SOURCES@ +Implementation-SHA256-Classes: @SHA256_CLASSES@ +Implementation-SHA256-Classes-this: @SHA256_CLASSES_THIS@ +Implementation-SHA256-Natives: @SHA256_NATIVES@ +Implementation-SHA256-Natives-this: @SHA256_NATIVES_THIS@ Implementation-Vendor: JogAmp Community Implementation-Vendor-Id: com.jogamp Implementation-URL: http://jogamp.org/ diff --git a/make/Manifest-rt.cdc b/make/Manifest-rt.cdc index 70c4f92..93a62ae 100755 --- a/make/Manifest-rt.cdc +++ b/make/Manifest-rt.cdc @@ -8,6 +8,11 @@ Implementation-Version: @VERSION@ Implementation-Build: @BUILD_VERSION@ Implementation-Branch: @SCM_BRANCH@ Implementation-Commit: @SCM_COMMIT@ +Implementation-SHA256-Sources: @SHA256_SOURCES@ +Implementation-SHA256-Classes: @SHA256_CLASSES@ +Implementation-SHA256-Classes-this: @SHA256_CLASSES_THIS@ +Implementation-SHA256-Natives: @SHA256_NATIVES@ +Implementation-SHA256-Natives-this: @SHA256_NATIVES_THIS@ Implementation-Vendor: JogAmp Community Implementation-Vendor-Id: com.jogamp Implementation-URL: http://jogamp.org/ diff --git a/make/build.xml b/make/build.xml index dc6602f..61a3880 100644 --- a/make/build.xml +++ b/make/build.xml @@ -87,6 +87,12 @@ <property name="gluegen.version" value="${jogamp.version.base}-b${gluegen.build.number}-${version.timestamp}" /> + <delete includeEmptyDirs="false"> + <fileset dir="${project.root}" includes="make/GnuCTreeParserTokenTypes.txt make/STDCTokenTypes.txt" /> + </delete> + <echo message="gluegen.build.branch ${gluegen.build.branch}"/> + <echo message="gluegen.build.commit ${gluegen.build.commit}"/> + <property name="stub.includes.dir" value="stub_includes" /> <!-- NOTE: this MUST be relative for FileSet --> <!-- The generated source directories. --> @@ -96,6 +102,9 @@ <!-- The compiler output directories. --> <property name="classes" value="${build}/classes" /> + <pathconvert targetos="unix" property="classes.unix"> + <path location="${classes}"/> + </pathconvert> <!-- Call the external config validator script to make sure the config is ok and consistent --> <ant antfile="validate-properties.xml" inheritall="true"/> @@ -500,6 +509,26 @@ </antcall> <antcall target="c.manifest" inheritRefs="true" /> + </target> + + <target name="gluegen.package.native" depends="init, c.configure" unless="build.javaonly" > + <copy file="Manifest-rt-natives" + tofile="${build}/Manifest-rt-natives.temp" + overwrite="true"> + <filterset> + <filter token="VERSION" value="${jogamp.version}"/> + <filter token="BUILD_VERSION" value="${gluegen.version}"/> + <filter token="SCM_BRANCH" value="${gluegen.build.branch}"/> + <filter token="SCM_COMMIT" value="${gluegen.build.commit}"/> + <filter token="SHA256_SOURCES" value="${gluegen.build.sha256.sources}"/> + <filter token="SHA256_CLASSES" value="${gluegen.build.sha256.classes}"/> + <filter token="SHA256_CLASSES_THIS" value="0"/> + <filter token="SHA256_NATIVES" value="${gluegen.build.sha256.natives}"/> + <filter token="SHA256_NATIVES_THIS" value="${gluegen.build.sha256.natives}"/> + <filter token="BASEVERSION" value="${jogamp.version.base}"/> + <filter token="JAR_CODEBASE_TAG" value="${jogamp.jar.codebase}"/> + </filterset> + </copy> <native.tag.jar objdir="${build}/obj" nativejarfile="${build}/gluegen-rt-natives-${os.and.arch}.jar" @@ -765,7 +794,22 @@ <src path="${src.generated.java}" /> <classpath refid="cc_gluegen.classpath" /> </javac> + </target> + + <target name="gluegen.package.javase"> + <java classname="com.jogamp.common.util.SHASum" logError="true" failonerror="true" fork="true" newenvironment="true" + classpath="${classes}" + outputproperty="gluegen.build.sha256.classes.gluegen"> + <sysproperty key="java.library.path" value="${gluegen.lib.dir}"/> + + <arg value="--include"/> + <arg value="${classes.unix}/.*\.class"/> + <arg value="--exclude"/> + <arg value="${classes.unix}/jogamp/android/launcher"/> + + <arg value="${classes.unix}"/> + </java> <copy file="Manifest" tofile="${build}/Manifest.temp" overwrite="true"> @@ -774,6 +818,11 @@ <filter token="BUILD_VERSION" value="${gluegen.version}"/> <filter token="SCM_BRANCH" value="${gluegen.build.branch}"/> <filter token="SCM_COMMIT" value="${gluegen.build.commit}"/> + <filter token="SHA256_SOURCES" value="${gluegen.build.sha256.sources}"/> + <filter token="SHA256_CLASSES" value="${gluegen.build.sha256.classes}"/> + <filter token="SHA256_CLASSES_THIS" value="${gluegen.build.sha256.classes.gluegen}"/> + <filter token="SHA256_NATIVES" value="${gluegen.build.sha256.natives}"/> + <filter token="SHA256_NATIVES_THIS" value="0"/> <filter token="BASEVERSION" value="${jogamp.version.base}"/> <filter token="JAR_CODEBASE_TAG" value="${jogamp.jar.codebase}"/> </filterset> @@ -793,6 +842,27 @@ </fileset> </jar> + <java classname="com.jogamp.common.util.SHASum" logError="true" failonerror="true" fork="true" newenvironment="true" + classpath="${classes}" + outputproperty="gluegen.build.sha256.classes.gluegen-rt"> + <sysproperty key="java.library.path" value="${gluegen.lib.dir}"/> + + <arg value="--include"/> + <arg value="${classes.unix}/com/jogamp/gluegen/runtime/.*\.class" /> + <arg value="--include"/> + <arg value="${classes.unix}/com/jogamp/common/.*" /> + <arg value="--include"/> + <arg value="${classes.unix}/jogamp/common/.*" /> + + <arg value="--exclude"/> + <arg value="${classes.unix}/jogamp/android/launcher"/> + <arg value="--exclude"/> + <arg value="${classes.unix}/jogamp/common/os/android" /> + <arg value="--exclude"/> + <arg value="${classes.unix}/com/jogamp/gluegen/jcpp" /> + + <arg value="${classes.unix}"/> + </java> <copy file="Manifest-rt" tofile="${build}/Manifest-rt.temp" overwrite="true"> @@ -801,93 +871,99 @@ <filter token="BUILD_VERSION" value="${gluegen.version}"/> <filter token="SCM_BRANCH" value="${gluegen.build.branch}"/> <filter token="SCM_COMMIT" value="${gluegen.build.commit}"/> + <filter token="SHA256_SOURCES" value="${gluegen.build.sha256.sources}"/> + <filter token="SHA256_CLASSES" value="${gluegen.build.sha256.classes}"/> + <filter token="SHA256_CLASSES_THIS" value="${gluegen.build.sha256.classes.gluegen-rt}"/> + <filter token="SHA256_NATIVES" value="${gluegen.build.sha256.natives}"/> + <filter token="SHA256_NATIVES_THIS" value="0"/> <filter token="BASEVERSION" value="${jogamp.version.base}"/> <filter token="JAR_CODEBASE_TAG" value="${jogamp.jar.codebase}"/> </filterset> </copy> - <copy file="jogamp-fat.mf" - tofile="${build}/jogamp-fat.mf" - overwrite="true"> - <filterset> - <filter token="VERSION" value="${jogamp.version}"/> - <filter token="BUILD_VERSION" value="${gluegen.version}"/> - <filter token="SCM_BRANCH" value="${gluegen.build.branch}"/> - <filter token="SCM_COMMIT" value="${gluegen.build.commit}"/> - <filter token="BASEVERSION" value="${jogamp.version.base}"/> - <filter token="JAR_CODEBASE_TAG" value="${jogamp.jar.codebase}"/> - </filterset> - </copy> + <!-- Build gluegen-rt.jar. --> + <jar destfile="${build}/gluegen-rt.jar" manifest="${build}/Manifest-rt.temp" filesonly="true"> + <fileset dir="${classes}"> + <include name="com/jogamp/gluegen/runtime/*.class" /> + <include name="com/jogamp/common/**" /> + <include name="jogamp/common/**" /> + <exclude name="${jogamp-android-launcher.classes}" /> + <exclude name="${java.part.android}" /> + <exclude name="${java.part.jcpp}" /> + </fileset> + <fileset dir="resources/assets"> + <include name="**" /> + </fileset> + </jar> - <copy file="jogamp-fat-test.mf" - tofile="${build}/jogamp-fat-test.mf" + <!-- copy file="Manifest-rt-alt" + tofile="${build}/Manifest-rt-alt.temp" overwrite="true"> <filterset> <filter token="VERSION" value="${jogamp.version}"/> <filter token="BUILD_VERSION" value="${gluegen.version}"/> <filter token="SCM_BRANCH" value="${gluegen.build.branch}"/> <filter token="SCM_COMMIT" value="${gluegen.build.commit}"/> + <filter token="SHA256_SOURCES" value="${gluegen.build.sha256.sources}"/> + <filter token="SHA256_CLASSES" value="${gluegen.build.sha256.classes}"/> + <filter token="SHA256_CLASSES_THIS" value="${gluegen.build.sha256.classes.gluegen-rt-alt}"/> + <filter token="SHA256_NATIVES" value="${gluegen.build.sha256.natives}"/> + <filter token="SHA256_NATIVES_THIS" value="0"/> <filter token="BASEVERSION" value="${jogamp.version.base}"/> <filter token="JAR_CODEBASE_TAG" value="${jogamp.jar.codebase}"/> </filterset> - </copy> + </copy --> + <!-- Build gluegen-rt-alt.jar. --> + <!-- jar destfile="${build}/gluegen-rt-alt.jar" manifest="${build}/Manifest-rt-alt.temp"> + <fileset dir="${classes}"> + <include name="com/jogamp/gluegen/runtime/*.class" /> + <include name="com/jogamp/common/**" /> + <include name="jogamp/common/**" /> + <exclude name="${jogamp-android-launcher.classes}" /> + <exclude name="${java.part.android}" /> + <exclude name="${java.part.jcpp}" /> + </fileset> + <fileset dir="resources/assets"> + <include name="**" /> + </fileset> + </jar --> - <!-- copy file="Manifest-rt-alt" - tofile="${build}/Manifest-rt-alt.temp" + <copy file="jogamp-fat.mf" + tofile="${build}/jogamp-fat.mf" overwrite="true"> <filterset> <filter token="VERSION" value="${jogamp.version}"/> <filter token="BUILD_VERSION" value="${gluegen.version}"/> <filter token="SCM_BRANCH" value="${gluegen.build.branch}"/> <filter token="SCM_COMMIT" value="${gluegen.build.commit}"/> + <filter token="SHA256_SOURCES" value="${gluegen.build.sha256.sources}"/> + <filter token="SHA256_CLASSES" value="${gluegen.build.sha256.classes}"/> + <filter token="SHA256_CLASSES_THIS" value="${gluegen.build.sha256.classes}"/> + <filter token="SHA256_NATIVES" value="${gluegen.build.sha256.natives}"/> + <filter token="SHA256_NATIVES_THIS" value="${gluegen.build.sha256.natives}"/> <filter token="BASEVERSION" value="${jogamp.version.base}"/> <filter token="JAR_CODEBASE_TAG" value="${jogamp.jar.codebase}"/> </filterset> - </copy --> + </copy> - <copy file="Manifest-rt-natives" - tofile="${build}/Manifest-rt-natives.temp" + <copy file="jogamp-fat-test.mf" + tofile="${build}/jogamp-fat-test.mf" overwrite="true"> <filterset> <filter token="VERSION" value="${jogamp.version}"/> <filter token="BUILD_VERSION" value="${gluegen.version}"/> <filter token="SCM_BRANCH" value="${gluegen.build.branch}"/> <filter token="SCM_COMMIT" value="${gluegen.build.commit}"/> + <filter token="SHA256_SOURCES" value="${gluegen.build.sha256.sources}"/> + <filter token="SHA256_CLASSES" value="${gluegen.build.sha256.classes}"/> + <filter token="SHA256_CLASSES_THIS" value="${gluegen.build.sha256.classes}"/> + <filter token="SHA256_NATIVES" value="${gluegen.build.sha256.natives}"/> + <filter token="SHA256_NATIVES_THIS" value="${gluegen.build.sha256.natives}"/> <filter token="BASEVERSION" value="${jogamp.version.base}"/> <filter token="JAR_CODEBASE_TAG" value="${jogamp.jar.codebase}"/> </filterset> </copy> - <!-- Build gluegen-rt.jar. --> - <jar destfile="${build}/gluegen-rt.jar" manifest="${build}/Manifest-rt.temp" filesonly="true"> - <fileset dir="${classes}"> - <include name="com/jogamp/gluegen/runtime/*.class" /> - <include name="com/jogamp/common/**" /> - <include name="jogamp/common/**" /> - <exclude name="${jogamp-android-launcher.classes}" /> - <exclude name="${java.part.android}" /> - <exclude name="${java.part.jcpp}" /> - </fileset> - <fileset dir="resources/assets"> - <include name="**" /> - </fileset> - </jar> - - <!-- Build gluegen-rt-alt.jar. --> - <!-- jar destfile="${build}/gluegen-rt-alt.jar" manifest="${build}/Manifest-rt-alt.temp"> - <fileset dir="${classes}"> - <include name="com/jogamp/gluegen/runtime/*.class" /> - <include name="com/jogamp/common/**" /> - <include name="jogamp/common/**" /> - <exclude name="${jogamp-android-launcher.classes}" /> - <exclude name="${java.part.android}" /> - <exclude name="${java.part.jcpp}" /> - </fileset> - <fileset dir="resources/assets"> - <include name="**" /> - </fileset> - </jar --> - <!-- Copy antlr.jar into build directory for convenience so gluegen.jar can be run via "java -jar". antlr.jar is referenced via a Class-Path entry in the Manifest of @@ -921,7 +997,28 @@ <src path="${src.generated.java}" /> <classpath refid="cc_gluegen_android.classpath" /> </javac> - + </target> + + <target name="gluegen.package.android" if="android-jars.available"> + <java classname="com.jogamp.common.util.SHASum" logError="true" failonerror="true" fork="true" newenvironment="true" + classpath="${classes}" + outputproperty="gluegen.build.sha256.classes.gluegen-rt-android"> + <sysproperty key="java.library.path" value="${gluegen.lib.dir}"/> + + <arg value="--include"/> + <arg value="${classes.unix}/com/jogamp/gluegen/runtime/.*\.class" /> + <arg value="--include"/> + <arg value="${classes.unix}/com/jogamp/common/.*" /> + <arg value="--include"/> + <arg value="${classes.unix}/jogamp/common/.*" /> + + <arg value="--exclude"/> + <arg value="${classes.unix}/jogamp/android/launcher"/> + <arg value="--exclude"/> + <arg value="${classes.unix}/com/jogamp/gluegen/jcpp" /> + + <arg value="${classes.unix}"/> + </java> <copy file="Manifest-rt-android" tofile="${build}/Manifest-rt-android.temp" overwrite="true"> @@ -930,6 +1027,11 @@ <filter token="BUILD_VERSION" value="${gluegen.version}"/> <filter token="SCM_BRANCH" value="${gluegen.build.branch}"/> <filter token="SCM_COMMIT" value="${gluegen.build.commit}"/> + <filter token="SHA256_SOURCES" value="${gluegen.build.sha256.sources}"/> + <filter token="SHA256_CLASSES" value="${gluegen.build.sha256.classes}"/> + <filter token="SHA256_CLASSES_THIS" value="${gluegen.build.sha256.classes.gluegen-rt-android}"/> + <filter token="SHA256_NATIVES" value="${gluegen.build.sha256.natives}"/> + <filter token="SHA256_NATIVES_THIS" value="0"/> <filter token="BASEVERSION" value="${jogamp.version.base}"/> <filter token="JAR_CODEBASE_TAG" value="${jogamp.jar.codebase}"/> </filterset> @@ -943,6 +1045,7 @@ <include name="jogamp/common/**" /> <include name="${java.part.android}" /> <exclude name="${jogamp-android-launcher.classes}" /> + <exclude name="${java.part.jcpp}" /> </fileset> <fileset dir="resources/assets"> <include name="**" /> @@ -957,6 +1060,43 @@ <antcall target="gluegen.build.android" inheritRefs="true"/> </target> + <target name="gluegen.packaging" depends="gluegen.cpptasks.detect.os"> + <java classname="com.jogamp.common.util.SHASum" logError="true" failonerror="true" fork="true" newenvironment="true" + classpath="${classes}" + outputproperty="gluegen.build.sha256.sources"> + <sysproperty key="java.library.path" value="${gluegen.lib.dir}"/> + <!-- jvmarg value="-Djogamp.debug.SHASum"/ --> + + <arg value="--exclude"/> + <arg value=".*\.log"/> + + <arg value="--exclude"/> + <arg value="../make/lib/toolchain"/> + + <arg value="../src"/> + <arg value="../jcpp/src"/> + <arg value="../make"/> + </java> + <java classname="com.jogamp.common.util.SHASum" logError="true" failonerror="true" fork="true" newenvironment="true" + classpath="${classes}" + outputproperty="gluegen.build.sha256.classes"> + <sysproperty key="java.library.path" value="${gluegen.lib.dir}"/> + <arg value="${classes.unix}"/> + </java> + <java classname="com.jogamp.common.util.SHASum" logError="true" failonerror="true" fork="true" newenvironment="true" + classpath="${classes}" + outputproperty="gluegen.build.sha256.natives"> + <sysproperty key="java.library.path" value="${gluegen.lib.dir}"/> + <arg value="${gluegen.lib.dir}/${output.lib.name.os}"/> + </java> + <echo message="gluegen.build.sha256.sources ${gluegen.build.sha256.sources}"/> + <echo message="gluegen.build.sha256.classes ${gluegen.build.sha256.classes}"/> + <echo message="gluegen.build.sha256.natives ${gluegen.build.sha256.natives}"/> + <antcall target="gluegen.package.javase" inheritRefs="true"/> + <antcall target="gluegen.package.android" inheritRefs="true"/> + <antcall target="gluegen.package.native" inheritRefs="true"/> + </target> + <target name="gluegen.build.check.android-launcher" depends="init"> <uptodate property="gluegen.build.skip.android-launcher"> <srcfiles dir= "." includes="*.xml"/> @@ -980,7 +1120,19 @@ <src path="${src.java}" /> <classpath refid="android.classpath" /> </javac> + </target> + <target name="android-launcher.package" depends="android-launcher.build" if="isAndroid" unless="gluegen.build.skip.android-launcher"> + <java classname="com.jogamp.common.util.SHASum" logError="true" failonerror="true" fork="true" newenvironment="true" + classpath="${classes}" + outputproperty="gluegen.build.sha256.classes.jogamp-android-launcher"> + <sysproperty key="java.library.path" value="${gluegen.lib.dir}"/> + + <arg value="--include"/> + <arg value="${classes.unix}/jogamp/android/launcher/.*"/> + + <arg value="${classes.unix}/jogamp/android/launcher/"/> + </java> <copy file="Manifest-android-launcher" tofile="${build}/Manifest-android-launcher.temp" overwrite="true"> @@ -989,6 +1141,11 @@ <filter token="BUILD_VERSION" value="${gluegen.version}"/> <filter token="SCM_BRANCH" value="${gluegen.build.branch}"/> <filter token="SCM_COMMIT" value="${gluegen.build.commit}"/> + <filter token="SHA256_SOURCES" value="${gluegen.build.sha256.sources}"/> + <filter token="SHA256_CLASSES" value="${gluegen.build.sha256.classes}"/> + <filter token="SHA256_CLASSES_THIS" value="${gluegen.build.sha256.classes.jogamp-android-launcher}"/> + <filter token="SHA256_NATIVES" value="${gluegen.build.sha256.natives}"/> + <filter token="SHA256_NATIVES_THIS" value="0"/> <filter token="BASEVERSION" value="${jogamp.version.base}"/> <filter token="JAR_CODEBASE_TAG" value="${jogamp.jar.codebase}"/> </filterset> @@ -999,9 +1156,6 @@ <include name="${jogamp-android-launcher.classes}" /> </fileset> </jar> - </target> - - <target name="android-launcher.package" depends="android-launcher.build" if="isAndroid" unless="gluegen.build.skip.android-launcher"> <aapt.signed assetsdir="resources/assets-launcher" jarbuilddir="${build}" @@ -1043,7 +1197,7 @@ </target> <target name="base.compile" description="Base compile ensuring valid build results w/o tampering the artifacts.properties" - depends="init, android-launcher.package, gluegen.build.java, gluegen.build.c" /> + depends="init, android-launcher.build, gluegen.build.java, gluegen.build.c, gluegen.packaging, android-launcher.package" /> <target name="all.no_junit" description="Release build" depends="init, base.compile, tag.build, android.package, developer-zip-archive" /> <target name="all" description="Release build" depends="init, base.compile, tag.build, junit.compile, android.package, developer-zip-archive" /> @@ -1055,6 +1209,7 @@ <target name="clean" depends="init"> <delete includeEmptyDirs="true"> <fileset dir="${build}" /> + <fileset dir="${project.root}" includes="make/GnuCTreeParserTokenTypes.txt make/STDCTokenTypes.txt" /> </delete> </target> @@ -1064,6 +1219,9 @@ <echo message='gluegen.build.id=${gluegen.build.id}${line.separator}' file="${build}/artifact.properties" append="true"/> <echo message='gluegen.build.branch=${gluegen.build.branch}${line.separator}' file="${build}/artifact.properties" append="true"/> <echo message='gluegen.build.commit=${gluegen.build.commit}${line.separator}' file="${build}/artifact.properties" append="true"/> + <echo message='gluegen.build.sha256.sources=${gluegen.build.sha256.sources}${line.separator}' file="${build}/artifact.properties" append="true"/> + <echo message='gluegen.build.sha256.classes=${gluegen.build.sha256.classes}${line.separator}' file="${build}/artifact.properties" append="true"/> + <echo message='gluegen.build.sha256.natives=${gluegen.build.sha256.natives}${line.separator}' file="${build}/artifact.properties" append="true"/> </target> <target name="junit.compile" depends="init"> diff --git a/make/scripts/runtest.sh b/make/scripts/runtest.sh index 5ba9b73..0ce33bd 100755 --- a/make/scripts/runtest.sh +++ b/make/scripts/runtest.sh @@ -63,7 +63,7 @@ X_ARGS="-Drootrel.build=$ROOTREL_BUILD -Dgluegen.root=$GLUEGEN_ROOT" #D_ARGS="-Djogamp.debug.IOUtil -Djogamp.debug.IOUtil.Exe -Djogamp.debug.IOUtil.Exe.NoStream" #D_ARGS="-Djogamp.debug.IOUtil -Djogamp.debug.TempFileCache -Djogamp.debug.TempJarCache -Djogamp.debug.IOUtil.Exe" #D_ARGS="-Djogamp.debug.IOUtil -Djogamp.debug.TempFileCache -Djogamp.debug.TempJarCache -Djava.io.tmpdir=/run/501" -D_ARGS="-Djogamp.debug.IOUtil -Djogamp.debug.TempFileCache -Djogamp.debug.TempJarCache" +#D_ARGS="-Djogamp.debug.IOUtil -Djogamp.debug.TempFileCache -Djogamp.debug.TempJarCache" #D_ARGS="-Djogamp.debug.ByteBufferInputStream" #D_ARGS="-Djogamp.debug.Buffers" #D_ARGS="-Djogamp.debug.Bitstream" diff --git a/src/java/com/jogamp/common/GlueGenVersion.java b/src/java/com/jogamp/common/GlueGenVersion.java index f97aba6..6ed7783 100644 --- a/src/java/com/jogamp/common/GlueGenVersion.java +++ b/src/java/com/jogamp/common/GlueGenVersion.java @@ -29,8 +29,17 @@ package com.jogamp.common; import com.jogamp.common.util.JogampVersion; +import com.jogamp.common.util.SHASum; import com.jogamp.common.util.VersionUtil; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.List; import java.util.jar.Manifest; +import java.util.regex.Pattern; public class GlueGenVersion extends JogampVersion { @@ -59,6 +68,40 @@ public class GlueGenVersion extends JogampVersion { return jogampCommonVersionInfo; } + /** + * {@code gluegen-rt.jar} definition of {@link SHASum.TempJarSHASum}'s specialization of {@link SHASum}. + * <p> + * Implementation uses {@link com.jogamp.common.util.cache.TempJarCache}. + * </p> + * <p> + * Constructor defines the includes and excludes as used for {@code gluegen-rt.jar} {@link SHASum} computation. + * </p> + */ + public static class GluGenRTJarSHASum extends SHASum.TempJarSHASum { + /** + * See {@link GluGenRTJarSHASum} + * @throws SecurityException + * @throws IllegalArgumentException + * @throws NoSuchAlgorithmException + * @throws IOException + * @throws URISyntaxException + */ + public GluGenRTJarSHASum() + throws SecurityException, IllegalArgumentException, NoSuchAlgorithmException, IOException, URISyntaxException + { + super(MessageDigest.getInstance("SHA-256"), GlueGenVersion.class, new ArrayList<Pattern>(), new ArrayList<Pattern>()); + final List<Pattern> excludes = getExcludes(); + final List<Pattern> includes = getIncludes(); + final String origin = getOrigin(); + excludes.add(Pattern.compile(origin+"/jogamp/android/launcher")); + excludes.add(Pattern.compile(origin+"/jogamp/common/os/android")); + excludes.add(Pattern.compile(origin+"/com/jogamp/gluegen/jcpp")); + includes.add(Pattern.compile(origin+"/com/jogamp/gluegen/runtime/.*\\.class")); + includes.add(Pattern.compile(origin+"/com/jogamp/common/.*")); + includes.add(Pattern.compile(origin+"/jogamp/common/.*")); + } + } + public static void main(final String args[]) { System.err.println(VersionUtil.getPlatformInfo()); System.err.println(GlueGenVersion.getInstance()); diff --git a/src/java/com/jogamp/common/util/IOUtil.java b/src/java/com/jogamp/common/util/IOUtil.java index 066500f..0bee22b 100644 --- a/src/java/com/jogamp/common/util/IOUtil.java +++ b/src/java/com/jogamp/common/util/IOUtil.java @@ -50,6 +50,8 @@ import java.net.URLConnection; import java.nio.ByteBuffer; import java.security.AccessController; import java.security.PrivilegedAction; +import java.util.ArrayList; +import java.util.List; import java.util.Locale; import java.util.regex.Pattern; @@ -1402,4 +1404,75 @@ public class IOUtil { } return null; } + + /** + * Retrieve the list of all filenames traversing through given paths + * @param paths list of paths to traverse through, containing directories and files + * @param excludes optional list of exclude {@link Pattern}. All {@link Pattern#matcher(CharSequence) matching} files or directories will be omitted. Maybe be null or empty. + * @param includes optional list of explicit include {@link Pattern}. If given, only {@link Pattern#matcher(CharSequence) matching} files will be returned, otherwise all occurring. + * @return list of unsorted filenames within given paths + */ + public static ArrayList<String> filesOf(final List<String> paths, final List<Pattern> excludes, final List<Pattern> includes) { + final ArrayList<String> files = new ArrayList<String>(paths.size()*32); + final ArrayList<String> todo = new ArrayList<String>(paths); + while(todo.size() > 0) { + final String p = todo.remove(0); + if( null != excludes && excludes.size() > 0) { + boolean exclude = false; + for(int i=0; !exclude && i<excludes.size(); i++) { + exclude = excludes.get(i).matcher(p).matches(); + if( DEBUG ) { + if( exclude ) { + System.err.println("IOUtil.filesOf(): excluding <"+p+"> (exclude["+i+"]: "+excludes.get(i)+")"); + } + } + } + if( exclude ) { + continue; // skip further processing, continue w/ next path + } + } + final File f = new File(p); + if( !f.exists() ) { + if( DEBUG ) { + System.err.println("IOUtil.filesOf(): not existing: "+f); + } + continue; + } else if( f.isDirectory() ) { + final String[] subs = f.list(); + if( null == subs ) { + if( DEBUG ) { + System.err.println("IOUtil.filesOf(): null list of directory: "+f); + } + } else if( 0 == subs.length ) { + if( DEBUG ) { + System.err.println("IOUtil.filesOf(): empty list of directory: "+f); + } + } else { + int j=0; + final String pp = p.endsWith("/") ? p : p+"/"; + for(int i=0; i<subs.length; i++) { + todo.add(j++, pp+subs[i]); // add 'in-place' to soothe the later sorting algorithm + } + } + } else { + if( null != includes && includes.size() > 0) { + boolean include = false; + for(int i=0; !include && i<includes.size(); i++) { + include = includes.get(i).matcher(p).matches(); + if( DEBUG ) { + if( include ) { + System.err.println("IOUtil.filesOf(): including <"+p+"> (including["+i+"]: "+includes.get(i)+")"); + } + } + } + if( include ) { + files.add(p); + } + } else { + files.add(p); + } + } + } + return files; + } } diff --git a/src/java/com/jogamp/common/util/JogampVersion.java b/src/java/com/jogamp/common/util/JogampVersion.java index e06ce1f..c2f3c3e 100644 --- a/src/java/com/jogamp/common/util/JogampVersion.java +++ b/src/java/com/jogamp/common/util/JogampVersion.java @@ -45,6 +45,16 @@ public class JogampVersion { public static final Attributes.Name IMPLEMENTATION_BRANCH = new Attributes.Name("Implementation-Branch"); /** See {@link #getImplementationCommit()} */ public static final Attributes.Name IMPLEMENTATION_COMMIT = new Attributes.Name("Implementation-Commit"); + /** See {@link #getImplementationSHA256Sources()} */ + public static final Attributes.Name IMPLEMENTATION_SHA256_SOURCES = new Attributes.Name("Implementation-SHA256-Sources"); + /** See {@link #getImplementationSHA256Classes()} */ + public static final Attributes.Name IMPLEMENTATION_SHA256_CLASSES = new Attributes.Name("Implementation-SHA256-Classes"); + /** See {@link #getImplementationSHA256ClassesThis()} */ + public static final Attributes.Name IMPLEMENTATION_SHA256_CLASSES_THIS = new Attributes.Name("Implementation-SHA256-Classes-this"); + /** See {@link #getImplementationSHA256Natives()} */ + public static final Attributes.Name IMPLEMENTATION_SHA256_NATIVES = new Attributes.Name("Implementation-SHA256-Natives"); + /** See {@link #getImplementationSHA256NativesThis()} */ + public static final Attributes.Name IMPLEMENTATION_SHA256_NATIVES_THIS = new Attributes.Name("Implementation-SHA256-Natives-this"); /** For FAT JogAmp jar files */ private static final String packageNameFAT = "com.jogamp"; @@ -155,6 +165,41 @@ public class JogampVersion { return this.getAttribute(JogampVersion.IMPLEMENTATION_COMMIT); } + /** + * Returns the SHA256 of all concatenated source files of the whole project + */ + public final String getImplementationSHA256Sources() { + return this.getAttribute(JogampVersion.IMPLEMENTATION_SHA256_SOURCES); + } + + /** + * Returns the SHA256 of all concatenated class files of all build classes + */ + public final String getImplementationSHA256Classes() { + return this.getAttribute(JogampVersion.IMPLEMENTATION_SHA256_CLASSES); + } + + /** + * Returns the SHA256 of all concatenated class files of the local (jar) package subset + */ + public final String getImplementationSHA256ClassesThis() { + return this.getAttribute(JogampVersion.IMPLEMENTATION_SHA256_CLASSES_THIS); + } + + /** + * Returns the SHA256 of all concatenated native library files of all build libs + */ + public final String getImplementationSHA256Natives() { + return this.getAttribute(JogampVersion.IMPLEMENTATION_SHA256_NATIVES); + } + + /** + * Returns the SHA256 of all concatenated native library files of the local (jar) package subset + */ + public final String getImplementationSHA256NativesThis() { + return this.getAttribute(JogampVersion.IMPLEMENTATION_SHA256_NATIVES_THIS); + } + public final String getImplementationTitle() { return this.getAttribute(Attributes.Name.IMPLEMENTATION_TITLE); } @@ -220,6 +265,11 @@ public class JogampVersion { sb.append("Implementation Build: ").append(getImplementationBuild()).append(nl); sb.append("Implementation Branch: ").append(getImplementationBranch()).append(nl); sb.append("Implementation Commit: ").append(getImplementationCommit()).append(nl); + sb.append("Implementation SHA256 Sources: ").append(getImplementationSHA256Sources()).append(nl); + sb.append("Implementation SHA256 Classes: ").append(getImplementationSHA256Classes()).append(nl); + sb.append("Implementation SHA256 Classes-this: ").append(getImplementationSHA256ClassesThis()).append(nl); + sb.append("Implementation SHA256 Natives: ").append(getImplementationSHA256Natives()).append(nl); + sb.append("Implementation SHA256 Natives-this: ").append(getImplementationSHA256NativesThis()).append(nl); if(null != getAndroidPackageVersionName()) { sb.append("Android Package Version: ").append(getAndroidPackageVersionName()).append(nl); } diff --git a/src/java/com/jogamp/common/util/SHASum.java b/src/java/com/jogamp/common/util/SHASum.java new file mode 100644 index 0000000..6489812 --- /dev/null +++ b/src/java/com/jogamp/common/util/SHASum.java @@ -0,0 +1,330 @@ +/** + * Copyright 2019 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +package com.jogamp.common.util; + +import java.io.BufferedInputStream; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.FileNotFoundException; +import java.io.InputStream; +import java.net.URISyntaxException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Locale; +import java.util.regex.Pattern; + +import com.jogamp.common.GlueGenVersion; +import com.jogamp.common.util.cache.TempFileCache; +import com.jogamp.common.util.cache.TempJarCache; + +import jogamp.common.Debug; + +/** + * Utility class to produce secure hash (SHA) sums over diverse input sources. + * <p> + * See {@link #updateDigest(MessageDigest, List)} + * </p> + * <p> + * This implementation is being utilized at JogAmp build time to produce various + * SHA256 sums over sources, class files and native libraries to ensure their identity. + * See {@link JogampVersion#getImplementationSHA256Sources()}, + * {@link JogampVersion#getImplementationSHA256Classes()} + * and {@link JogampVersion#getImplementationSHA256Natives()}. + * </p> + * <p> + * {@link JogampVersion#getImplementationSHA256Sources()} for module gluegen is produced via: + * <pre> + * java -cp build/gluegen-rt.jar com.jogamp.common.util.SHASum --algorithm 256 --exclude ".*\\.log" --exclude "make/lib/toolchain" src jcpp/src make + * </pre> + * </p> + * @see #SHASum(MessageDigest, List, List, List) + * @see #compute(boolean) + * @see TempJarSHASum + * @see #main(String[]) + */ +public class SHASum { + private static final boolean DEBUG = Debug.debug("SHASum"); + + /** + * {@link MessageDigest#update(byte[], int, int) Updates} the given {@code digest} + * with the bytes contained by the files denoted by the given {@code filenames} in the given order. + * <p> + * To retrieve the list of all files traversing through directories, one may use {@link IOUtil#filesOf(List, List, List)}. + * </p> + * <p> + * The SHA implementation is sensitive to the order of input bytes and hence the given filename order. + * </p> + * <p> + * It is advised to pass given list of filenames in lexicographically sorted order to ensure reproducible outcome across all platforms, + * one may use {@link #sort(ArrayList)}. + * </p> + * <p> + * As an example, one could write + * <pre> + * final MessageDigest digest = ...; + * final long totalBytes = updateDigest(digest, sort(IOUtil.filesOf(Arrays.asList("sources"), null, null))); + * </pre> + * </p> + * @param digest to be updated digest + * @param filenames list of filenames denoting files, which bytes will be used to update the digest + * @return total number of bytes read. + * @throws FileNotFoundException see {@link FileInputStream#FileInputStream(String)} + * @throws IOException see {@link InputStream#read(byte[])} + */ + public static long updateDigest(final MessageDigest digest, final List<String> filenames) throws IOException { + long numBytes = 0; + final byte buffer[] = new byte[4096]; // avoid Platform.getMachineDataInfo().pageSizeInBytes() due to native dependency + for(int i=0; i<filenames.size(); i++) { + final InputStream in = new BufferedInputStream(new FileInputStream(filenames.get(i))); + try { + while (true) { + int count; + if ((count = in.read(buffer)) == -1) { + break; + } + digest.update(buffer, 0, count); + numBytes += count; + } + } finally { + in.close(); + } + } + return numBytes; + } + + /** + * Simple helper to print the given byte-array into a string, here appended to StringBuilder + * @param shasum the given byte-array + * @param sb optional pre-existing StringBuilder, may be null + * @return return given or new StringBuilder with appended hex-string + */ + public static StringBuilder toHexString(final byte[] shasum, StringBuilder sb) { + if( null == sb ) { + sb = new StringBuilder(); + } + for(int i=0; i<shasum.length; i++) { + sb.append(String.format((Locale)null, "%02x", shasum[i])); + } + return sb; + } + + /** + * Returns the sorted list of given strings using {@link String#compareTo(String)}'s lexicographically comparison. + * @param source given input strings + * @return sorted list of given strings + */ + public static List<String> sort(final ArrayList<String> source) { + final String s[] = source.toArray(new String[source.size()]); + Arrays.sort(s, 0, s.length, null); + return Arrays.asList(s); + } + + final MessageDigest digest; + final List<String> origins; + final List<Pattern> excludes, includes; + + /** + * Instance to ensure proper {@link #compute(boolean)} of identical SHA sums over same contents within given paths across machines. + * <p> + * Instantiation of this class is lightweight, {@link #compute(boolean)} performs all operations. + * </p> + * + * @param digest the SHA algorithm + * @param origins the mandatory path origins to be used for {@link IOUtil#filesOf(List, List, List)} + * @param excludes the optional exclude patterns to be used for {@link IOUtil#filesOf(List, List, List)} + * @param includes the optional include patterns to be used for {@link IOUtil#filesOf(List, List, List)} + * @throws IllegalArgumentException + * @throws IOException + * @throws URISyntaxException + */ + public SHASum(final MessageDigest digest, final List<String> origins, final List<Pattern> excludes, final List<Pattern> includes) { + this.digest = digest; + this.origins = origins; + this.excludes = excludes; + this.includes = includes; + } + + /** + * Implementation gathers all files traversing through given paths via {@link IOUtil#filesOf(List, List, List)}, + * sorts the resulting file list via {@link #sort(ArrayList)} and finally + * calculates the SHA sum over its byte content via {@link #updateDigest(MessageDigest, List)}. + * <p> + * This ensures identical SHA sums over same contents within given paths across machines. + * </p> + * <p> + * This method is heavyweight and performs all operations. + * </p> + * + * @param verbose if true, all used files will be dumped as well as the digest result + * @return the resulting SHA value + * @throws IOException + */ + public final byte[] compute(final boolean verbose) throws IOException { + final List<String> fnamesS = SHASum.sort(IOUtil.filesOf(origins, excludes, includes)); + if( verbose ) { + for(int i=0; i<fnamesS.size(); i++) { + System.err.println(fnamesS.get(i)); + } + } + final long numBytes = SHASum.updateDigest(digest, fnamesS); + final byte[] shasum = digest.digest(); + if( verbose ) { + System.err.println("Digested "+numBytes+" bytes, shasum size "+shasum.length+" bytes"); + System.err.println("Digested result: "+SHASum.toHexString(shasum, null).toString()); + } + return shasum; + } + + public final List<String> getOrigins() { return origins; } + public final List<Pattern> getExcludes() { return excludes; } + public final List<Pattern> getIncludes() { return includes; } + + /** + * {@link SHASum} specialization utilizing {@link TempJarCache} to access jar file content for SHA computation + */ + public static class TempJarSHASum extends SHASum { + /** + * Instance to ensure proper {@link #compute(boolean)} of identical SHA sums over same contents within given paths across machines. + * <p> + * Instantiation of this class is lightweight, {@link #compute(boolean)} performs all operations. + * </p> + * <p> + * {@link TempJarCache#getTempFileCache()}'s {@link TempFileCache#getTempDir()} is used as origin for {@link IOUtil#filesOf(List, List, List)} + * </p> + * + * @param digest the SHA algorithm + * @param jarclazz a class from the desired classpath jar file used for {@link TempJarCache#addAll(Class, com.jogamp.common.net.Uri)} + * @param excludes the optional exclude patterns to be used for {@link IOUtil#filesOf(List, List, List)} + * @param includes the optional include patterns to be used for {@link IOUtil#filesOf(List, List, List)} + * @throws SecurityException + * @throws IllegalArgumentException + * @throws IOException + * @throws URISyntaxException + */ + public TempJarSHASum(final MessageDigest digest, final Class<?> jarclazz, final List<Pattern> excludes, final List<Pattern> includes) + throws SecurityException, IllegalArgumentException, IOException, URISyntaxException + { + super(digest, Arrays.asList(IOUtil.slashify(TempJarCache.getTempFileCache().getTempDir().getAbsolutePath(), false, false)), + excludes, includes); + TempJarCache.addAll(jarclazz, JarUtil.getJarFileUri(jarclazz.getName(), jarclazz.getClassLoader())); + } + + public final String getOrigin() { return origins.get(0); } + } + + /** + * Main entry point taking var-arg path or gnu-arguments with a leading '--'. + * <p> + * Implementation gathers all files traversing through given paths via {@link IOUtil#filesOf(List, List, List)}, + * sorts the resulting file list via {@link #sort(ArrayList)} and finally + * calculates the SHA sum over its byte content via {@link #updateDigest(MessageDigest, List)}. + * This ensures identical SHA sums over same contents within given paths. + * </p> + * <p> + * Example to calculate the SHA-256 over our source files as performed for {@link JogampVersion#getImplementationSHA256Sources()} + * <pre> + * java -cp build/gluegen-rt.jar com.jogamp.common.util.SHASum --algorithm 256 --exclude ".*\\.log" --exclude "make/lib/toolchain" src jcpp/src make + * </pre> + * </p> + * <p> + * To validate the implementation, one can gather the sorted list of files (to ensure same order) + * <pre> + * java -cp build/gluegen-rt.jar com.jogamp.common.util.SHASum --listfilesonly --exclude ".*\\.log" --exclude "make/lib/toolchain" src jcpp/src make >& java.sorted.txt + * </pre> + * and then calculate the shasum independently + * <pre> + * find `cat java.sorted.txt` -exec cat {} + | shasum -a 256 -b - | awk '{print $1}' + * </pre> + * </p> + * @param args + * @throws IOException + * @throws URISyntaxException + * @throws IllegalArgumentException + */ + public static void main(final String[] args) throws IOException { + boolean listFilesOnly = false; + int shabits = 256; + int i; + final ArrayList<String> pathU = new ArrayList<String>(); + final ArrayList<Pattern> excludes = new ArrayList<Pattern>(); + final ArrayList<Pattern> includes = new ArrayList<Pattern>(); + { + for(i=0; i<args.length; i++) { + if(null != args[i]) { + if( args[i].startsWith("--") ) { + // options + if( args[i].equals("--algorithm")) { + shabits = Integer.parseInt(args[++i]); + } else if( args[i].equals("--exclude")) { + excludes.add(Pattern.compile(args[++i])); + if( DEBUG ) { + System.err.println("adding exclude: <"+args[i]+"> -> <"+excludes.get(excludes.size()-1)+">"); + } + } else if( args[i].equals("--include")) { + includes.add(Pattern.compile(args[++i])); + if( DEBUG ) { + System.err.println("adding include: <"+args[i]+"> -> <"+includes.get(includes.size()-1)+">"); + } + } else if( args[i].equals("--listfilesonly")) { + listFilesOnly = true; + } else { + System.err.println("Abort, unknown argument: "+args[i]); + return; + } + } else { + pathU.add(args[i]); + if( DEBUG ) { + System.err.println("adding path: <"+args[i]+">"); + } + } + } + } + if( listFilesOnly ) { + final List<String> fnamesS = sort(IOUtil.filesOf(pathU, excludes, includes)); + for(i=0; i<fnamesS.size(); i++) { + System.out.println(fnamesS.get(i)); + } + return; + } + } + final String shaalgo = "SHA-"+shabits; + final MessageDigest digest; + try { + digest = MessageDigest.getInstance(shaalgo); + } catch (final NoSuchAlgorithmException e) { + System.err.println("Abort, implementation for "+shaalgo+" not available: "+e.getMessage()); + return; + } + final SHASum shaSum = new SHASum(digest, pathU, excludes, includes); + System.out.println(toHexString(shaSum.compute(DEBUG), null).toString()); + } +} diff --git a/src/java/com/jogamp/common/util/cache/TempJarCache.java b/src/java/com/jogamp/common/util/cache/TempJarCache.java index c5cca3a..dbb97a9 100644 --- a/src/java/com/jogamp/common/util/cache/TempJarCache.java +++ b/src/java/com/jogamp/common/util/cache/TempJarCache.java @@ -43,6 +43,12 @@ import com.jogamp.common.os.NativeLibrary; import com.jogamp.common.util.JarUtil; import com.jogamp.common.util.SecurityUtil; +/** + * Static Jar file cache handler using an underlying instance of {@link TempFileCache}, see {@link #getTempFileCache()}. + * <p> + * Lifecycle: Concurrently running JVMs and ClassLoader + * </p> + */ public class TempJarCache { private static final boolean DEBUG = Debug.debug("TempJarCache"); diff --git a/src/junit/com/jogamp/common/util/TestVersionInfo.java b/src/junit/com/jogamp/common/util/TestVersionInfo.java index 2a9dfa1..de0d8d6 100644 --- a/src/junit/com/jogamp/common/util/TestVersionInfo.java +++ b/src/junit/com/jogamp/common/util/TestVersionInfo.java @@ -29,19 +29,24 @@ package com.jogamp.common.util; import java.io.IOException; +import java.net.URISyntaxException; +import java.security.NoSuchAlgorithmException; import org.junit.Test; import com.jogamp.common.GlueGenVersion; import com.jogamp.junit.util.SingletonJunitCase; +import org.junit.Assert; import org.junit.FixMethodOrder; import org.junit.runners.MethodSorters; @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class TestVersionInfo extends SingletonJunitCase { + static boolean VERBOSE = false; @Test - public void testInfo01() { + public void test01Info() { + System.err.println(VersionUtil.getPlatformInfo()); System.err.println("Version Info:"); System.err.println(GlueGenVersion.getInstance()); System.err.println(""); @@ -49,8 +54,23 @@ public class TestVersionInfo extends SingletonJunitCase { System.err.println(GlueGenVersion.getInstance().getFullManifestInfo(null)); } + @Test + public void test02ValidateSHA256() + throws IllegalArgumentException, IOException, URISyntaxException, SecurityException, NoSuchAlgorithmException + { + final GlueGenVersion info = GlueGenVersion.getInstance(); + final String sha256ClassesThis = info.getImplementationSHA256ClassesThis(); + System.err.println("SHA256 CLASSES.this (build-time): "+sha256ClassesThis); + + final GlueGenVersion.GluGenRTJarSHASum shaSum = new GlueGenVersion.GluGenRTJarSHASum(); + final byte[] shasum = shaSum.compute(VERBOSE); + final String sha256Classes = SHASum.toHexString(shasum, null).toString(); + System.err.println("SHA256 CLASSES.this (now): "+sha256Classes); + Assert.assertEquals("SHA256 not equal", sha256ClassesThis, sha256Classes); + } public static void main(final String args[]) throws IOException { + // VERBOSE = true; final String tstname = TestVersionInfo.class.getName(); org.junit.runner.JUnitCore.main(tstname); } |