11package org .ohnlp .backbone .pluginmanager ;
22
3+ import com .fasterxml .jackson .databind .ObjectMapper ;
4+ import com .fasterxml .jackson .databind .node .JsonNodeFactory ;
5+ import com .fasterxml .jackson .databind .node .ObjectNode ;
6+
37import java .io .File ;
48import java .io .IOException ;
9+ import java .math .BigInteger ;
510import java .nio .file .*;
611import java .nio .file .attribute .BasicFileAttributes ;
12+ import java .security .MessageDigest ;
13+ import java .security .NoSuchAlgorithmException ;
714import java .util .*;
15+ import java .util .concurrent .atomic .AtomicBoolean ;
816import java .util .stream .Collectors ;
917
1018public class PluginManager {
1119
1220 public static void main (String ... args ) throws IOException {
21+ File hashFile = new File ("bin" , "last_modified.json" );
22+
23+ ObjectNode hashes = hashFile .exists () ? (ObjectNode ) new ObjectMapper ().readTree (hashFile ) : JsonNodeFactory .instance .objectNode ();
1324 Set <String > builds = new HashSet <>();
1425 if (args .length > 0 ) {
1526 builds = Arrays .stream (args ).map (String ::toLowerCase ).collect (Collectors .toSet ());
@@ -22,72 +33,139 @@ public static void main(String... args) throws IOException {
2233 if (f .getName ().startsWith ("Backbone-Core" ) && !f .getName ().endsWith ("Packaged.jar" )) {
2334 File source = f ;
2435 String type = f .getName ().substring (14 , f .getName ().length () - 4 );
36+ if (!hashes .has (type )) {
37+ hashes .set (type , JsonNodeFactory .instance .objectNode ());
38+ }
39+ ObjectNode typeHash = (ObjectNode ) hashes .get (type );
2540 if (builds .size () == 0 || builds .contains (type .toLowerCase (Locale .ROOT ))) {
41+ System .out .println ("Repackaging files changed since last packaging of " + type + " platform-specific JAR:" );
2642 File target = new File ("bin/Backbone-Core-" + type + "-Packaged.jar" );
27- Files .copy (source .toPath (), target .toPath (), StandardCopyOption .REPLACE_EXISTING );
28- install (target , modules , configs , resources );
29- System .out .println ("Successfully Packaged Platform-Specific JAR: " + target .getAbsolutePath ());
43+ // Do a complete rebuild in update in case of class conflicts between submodules
44+ // TODO actually check this in the future (i.e., by preventing overwrites in org.ohnlp.backbone
45+ // classes during install()
46+ boolean invalidateAllHashes = false ;
47+ boolean updated = false ;
48+ if (!checkAndUpdateMD5ChecksumRegistry (false , typeHash , f )) {
49+ System .out .println ("- " + getRelativePath (f ));
50+ Files .copy (source .toPath (), target .toPath (), StandardCopyOption .REPLACE_EXISTING );
51+ invalidateAllHashes = true ;
52+ updated = true ;
53+ }
54+ updated = install (invalidateAllHashes , target , typeHash , modules , configs , resources ) || updated ;
55+ if (!updated ) {
56+ System .out .println ("No changed files found" );
57+ } else {
58+ System .out .println ("Successfully Packaged Platform-Specific JAR: " + target .getAbsolutePath ());
59+ }
3060 }
3161 }
3262 }
3363 }
64+ // Write hashes out
65+ new ObjectMapper ().writerWithDefaultPrettyPrinter ().writeValue (hashFile , hashes );
3466 System .out .println ("Packaging complete!" );
3567 }
3668
69+ private static boolean checkAndUpdateMD5ChecksumRegistry (boolean invalidateAllHashes , ObjectNode hashRegistry , File f ) {
70+ try {
71+ byte [] data = Files .readAllBytes (Paths .get (f .getPath ()));
72+ byte [] hash = MessageDigest .getInstance ("MD5" ).digest (data );
73+ String checksum = new BigInteger (1 , hash ).toString (16 );
74+ String relativePath = getRelativePath (f );
75+ if (invalidateAllHashes
76+ || !hashRegistry .has (relativePath )
77+ || !hashRegistry .get (relativePath ).asText ().equals (checksum )) {
78+ hashRegistry .put (relativePath , checksum );
79+ return false ;
80+ } else {
81+ return true ;
82+ }
83+ } catch (IOException | NoSuchAlgorithmException e ) {
84+ e .printStackTrace ();
85+ }
86+ return false ;
87+ }
88+
3789 /**
3890 * Packs an OHNLP backbone executable with the specified set of modules, configurations, and resources
3991 *
92+ * @param invalidateAllHashes Whether to ignore/replace all hashes
4093 * @param target The target file for packaging/into which items should be installed
94+ * @param hashRegistry A registry of currently
4195 * @param modules A list of module jar files to install
4296 * @param configurations A set of configuration files to install
4397 * @param resources A set of resource directories to install
4498 */
45- public static void install (File target , List <File > modules , List <File > configurations , List <File > resources ) {
99+ public static boolean install (boolean invalidateAllHashes , File target , ObjectNode hashRegistry , List <File > modules , List <File > configurations , List <File > resources ) {
100+ AtomicBoolean updated = new AtomicBoolean (false );
46101 Map <String , String > env = new HashMap <>();
47102 env .put ("create" , "false" );
48103 try (FileSystem fs = FileSystems .newFileSystem (target .toPath (), PluginManager .class .getClassLoader ())) {
49104 for (File module : modules ) {
50- try (FileSystem srcFs = FileSystems .newFileSystem (module .toPath (), PluginManager .class .getClassLoader ())) {
51- Path srcRoot = srcFs .getPath ("/" );
52- Files .walkFileTree (srcRoot , new SimpleFileVisitor <Path >() {
53- @ Override
54- public FileVisitResult visitFile (Path path , BasicFileAttributes attrs ) throws IOException {
55- String fName = path .getFileName ().toString ().toLowerCase (Locale .ROOT );
56- if (fName .endsWith (".sf" ) || fName .endsWith (".dsa" ) || fName .endsWith (".rsa" )) {
105+ if (!checkAndUpdateMD5ChecksumRegistry (invalidateAllHashes , hashRegistry , module )) {
106+ updated .set (true );
107+ System .out .println ("- " + getRelativePath (module ));
108+ try (FileSystem srcFs = FileSystems .newFileSystem (module .toPath (), PluginManager .class .getClassLoader ())) {
109+ Path srcRoot = srcFs .getPath ("/" );
110+ Files .walkFileTree (srcRoot , new SimpleFileVisitor <Path >() {
111+ @ Override
112+ public FileVisitResult visitFile (Path path , BasicFileAttributes attrs ) throws IOException {
113+ String fName = path .getFileName ().toString ().toLowerCase (Locale .ROOT );
114+ if (fName .endsWith (".sf" ) || fName .endsWith (".dsa" ) || fName .endsWith (".rsa" )) {
115+ return FileVisitResult .CONTINUE ;
116+ }
117+ Path tgtPath = fs .getPath (path .toString ());
118+ Files .createDirectories (tgtPath .getParent ());
119+ Files .copy (path , tgtPath , StandardCopyOption .REPLACE_EXISTING );
57120 return FileVisitResult .CONTINUE ;
58121 }
59- Path tgtPath = fs .getPath (path .toString ());
60- Files .createDirectories (tgtPath .getParent ());
61- Files .copy (path , tgtPath , StandardCopyOption .REPLACE_EXISTING );
62- return FileVisitResult .CONTINUE ;
63- }
64- });
122+ });
123+ }
65124 }
66125 }
67126 Files .createDirectories (fs .getPath ("/configs" ));
68127 for (File config : configurations ) {
69- Files .copy (config .toPath (), fs .getPath ("/configs/" + config .getName ()), StandardCopyOption .REPLACE_EXISTING );
128+ if (!checkAndUpdateMD5ChecksumRegistry (invalidateAllHashes , hashRegistry , config )) {
129+ updated .set (true );
130+ System .out .println ("- " + getRelativePath (config ));
131+ Files .copy (config .toPath (), fs .getPath ("/configs/" + config .getName ()), StandardCopyOption .REPLACE_EXISTING );
132+ }
70133 }
71134 Files .createDirectories (fs .getPath ("/resources" ));
135+ // Always update all resources
72136 for (File resource : resources ) {
73137 String resourceDir = resource .getParentFile ().toPath ().toAbsolutePath ().toString ();
74138 if (resource .isDirectory ()) {
75139 // Recursively find all files in directory (up to arbitrary max depth of 999
76140 Files .find (resource .toPath (), 999 , (p , bfa ) -> bfa .isRegularFile ()).forEach (p -> {
77141 try {
78- Path filePath = fs .getPath (p .toAbsolutePath ().toString ().replace (resourceDir , "/resources" ));
79- Files .createDirectories (filePath .getParent ());
80- Files .copy (p , filePath , StandardCopyOption .REPLACE_EXISTING );
142+ if (!checkAndUpdateMD5ChecksumRegistry (invalidateAllHashes , hashRegistry , p .toFile ())) {
143+ System .out .println ("- " + getRelativePath (p .toFile ()));
144+ updated .set (true );
145+ Path filePath = fs .getPath (p .toAbsolutePath ().toString ().replace (resourceDir , "/resources" ));
146+ Files .createDirectories (filePath .getParent ());
147+ Files .copy (p , filePath , StandardCopyOption .REPLACE_EXISTING );
148+ }
81149 } catch (IOException e ) {
82150 throw new IllegalStateException (e );
83151 }
84152 });
85153 } else {
86- Files .copy (resource .toPath (), fs .getPath ("/resources/" + resource .getName ()), StandardCopyOption .REPLACE_EXISTING );
154+ if (!checkAndUpdateMD5ChecksumRegistry (invalidateAllHashes , hashRegistry , resource )) {
155+ System .out .println ("- " + getRelativePath (resource ));
156+ updated .set (true );
157+ Files .copy (resource .toPath (), fs .getPath ("/resources/" + resource .getName ()), StandardCopyOption .REPLACE_EXISTING );
158+ }
87159 }
88160 }
89161 } catch (IOException e ) {
90162 throw new IllegalStateException (e );
91163 }
164+ return updated .get ();
165+ }
166+
167+ private static String getRelativePath (File f ) {
168+ File root = new File ("." );
169+ return root .toURI ().relativize (f .toURI ()).getPath ();
92170 }
93171}
0 commit comments