001package Torello.Java.Build; 002 003import Torello.Java.FileTransfer; 004import Torello.Java.FileNode; 005import Torello.Java.StringParse; 006import Torello.Java.RTC; 007 008import Torello.Java.ReadOnly.ReadOnlyList; 009import Torello.Java.ReadOnly.ReadOnlyArrayList; 010 011import static Torello.Java.C.BGREEN_BKGND; 012import static Torello.Java.C.BRED_BKGND; 013import static Torello.Java.C.BCYAN; 014import static Torello.Java.C.BGREEN; 015import static Torello.Java.C.BYELLOW; 016import static Torello.Java.C.RESET; 017 018import java.io.File; 019import java.io.IOException; 020 021import java.util.Map; 022import java.util.TreeMap; 023 024/** 025 * The purpose of a Build-Tool is, fundamentally, to make a project possible by doing what a 026 * programmer would otherwise need enter manually into a keyboard hundreds of thousands of times 027 * himself. The package {@lnk Torello.Java.Build} provides a CLI Menu that would performs hundreds 028 * and hundreds of otherwise <B STYLE='color: red;'><I>extremely trivial tasks</I></B> via a single 029 * UNIX CLI Command. 030 * 031 * <BR /><BR />It is likely that no programmer on earth would determine that running the Standard 032 * Java Command <B>{@code 'javac'}</B> at a UNIX prompt to be an overly cumbersome or difficult 033 * task. Building and re-building the Data-Files for a particular project requires just that: 034 * compiling some {@code '.java'} files, and then executing their {@code '.class'} Files in order 035 * to obtain their output. Everything seems quite trivial so far. 036 * 037 * <BR /><BR />Things become difficult when a project (for example the Java-HTML Library Tool) has 038 * such Data-File Building {@code '.java'} classes spread out across quite a number of 039 * <B STYLE='color:red;'>{@code ../data-files/}</B> directories, and furthermore each of those 040 * directories have multiple Data-Files Classes to both compile and build. In such cases, whenever 041 * the need arises to tweak, debug, update or add to the 042 * <B STYLE='color:red;'>{@code ../data-files/}</B> directories, the value of some sort of 043 * scripting tool starts to look like an invaluable tool in the programmer's arsenal. 044 * 045 * <BR /><BR />Why? 046 * 047 * <BR /><BR />Because typing: 048 * 049 * <BR /><BR /><OL CLASS=JDOL> 050 * <LI>{@code 'cd <dir-name>'} and</LI> 051 * <LI>{@code 'javac -switches <java-files>'} and</LI> 052 * <LI>{@code 'java <class-files>'}</LI> 053 * </OL> 054 * 055 * <BR /><BR >over and over again is a ROYAL PAIN IN THE ASS. 056 * 057 * <BR /><BR />That's what this tool does for you. It enters all {@code '../data-files/'} 058 * sub-directories of all Package Source Directories in your project and compiles then. 059 * Afterwards, it invokes the <B>{@link DataFileBuilderClass#build(String) build}</B> Method on 060 * any {@code '.class'} files which have implemented the <B>{@link DataFileBuilderClass}</B> 061 * inteface. 062 * 063 * <BR /><BR /><UL CLASS=JDUL> 064 * 065 * <LI> Enter all <B STYLE='color:red;'>{@code my/package/dir/data-files/}</B> directories 066 * <BR ><BR /> 067 * </LI> 068 * 069 * <LI> Wipe / Delete all Java {@code '.class'}-Files present in {@code ../data-files/} and its 070 * sub-directories. 071 * <BR /><BR /> 072 * </LI> 073 * 074 * <LI> Invoke {@code 'javac'} (Re-Compile) all {@code '.java'}-Files present in the directory and 075 * its sub-directories. 076 * <BR /><BR /> 077 * </LI> 078 * 079 * <LI> Scan {@code ../data-files/} and its sub directories for any and all {@code '.class'}-Files. 080 * Afterwards, seek and identify if any of them implement the 081 * {@link DataFileBuilderClass} interface. 082 * <BR /><BR /> 083 * </LI> 084 * 085 * <LI> Invoke the {@link DataFileBuilderClass#build(String)} method on those classes which do 086 * implement the aforementioned interface. If the user has properly written them, those 087 * classes will produce Data-Files which are needed and required for the particular 088 * Java-Package being examined. 089 * <BR /><BR /> 090 * </LI> 091 * 092 * <LI> That's all folks! It is that simple... 😊😊😊</LI> 093 * </UL> 094 * 095 * <BR /><BR /><B CLASS=JDDescLabel>CLI Output Example:</B> 096 * 097 * <BR />The following {@code '.html'}-Page demonstrates what the output looks like when running 098 * this class against all of the <B STYLE='color: red;'>{@code '../data-files/'}</B> directries 099 * which are utilized by this Java-HTML JAR-Library. This output was generated by this tool on 100 * Janaury 6th, 2025. 101 * 102 * <BR /><BR /><B><CODE><A HREF='doc-files/Data-File-Builder.Output.html'> 103 * Data-File-Builder.Output.html</A></CODE></B> 104 */ 105public class BuildDataFiles 106{ 107 private BuildDataFiles() { } 108 109 /** 110 * This method should be invoked by any {@code public static void main} method, and pass 111 * <B STYLE='color: red;'><I>BOTH</I></B> the provided {@code 'String[] argv'} parameter to 112 * this method, <B STYLE='color: red;'><I>AND</I></B> the remained of the required parameters 113 * needed. 114 * 115 * <BR /><BR /><B CLASS=JDDescLabel>Helper Code:</B> 116 * 117 * <BR />This method invokes two Package-Private and Internal-Classes for help. These external 118 * classes are listed above, at the top of this class' documentation page, and also here, below: 119 * 120 * <BR /><BR /><UL CLASS=JDUL> 121 * 122 * <LI> <B><A HREF='hilite-files/CompileDataFilesBuilders.java.html'> 123 * CompileDataFilesBuilders.java</A></B></LI> 124 * 125 * <LI> <B><A HREF='hilite-files/RunDataFilesBuilders.java.html'> 126 * RunDataFilesBuilders.java</A></B></LI> 127 * 128 * </UL> 129 * 130 * <BR /><BR /><B CLASS=JDDescLabel>Example & Output:</B> 131 * 132 * <BR />This class & method are, indeed, utilized by the Java-HTML JAR-Library (this tool) 133 * to build its own Data-Files. The links here are also included above. These links are to 134 * Syntax-Hilited Source - <I>and the output it produces</I>- showing how this method & 135 * class may be used. These links are also included, here, directly below: 136 * 137 * <BR /><BR /><UL CLASS=JDUL> 138 * 139 * <LI> <B><A HREF='hilite-files/DataFiles.java.html'> 140 * Torello.BuildJAR.DataFiles.java</A></B></LI> 141 * 142 * <LI> <B><A HREF='doc-files/Data-File-Builder.Output.html'> 143 * Data-File-Builder.Output.html</A></B></LI> 144 * 145 * </UL> 146 * 147 * @param pkgList This list of {@link BuildPackage} instances ought to be the exact same list 148 * which is passed to the {@link Config} class instance used for running a build with this 149 * package. 150 * 151 * @param argv This is the {@code String[] argv} parameter received from a CLI Processor at the 152 * Command-Line. 153 * 154 * @param additionalCompilerArgs This should be a list 155 * 156 * @param JAVAC_BIN This parameter may be null, and if it is, it shall be safely ignored. This 157 * parameter may include a relative or full path to a binary for the {@code 'javac'} program. 158 * 159 * <BR /><BR />When this parameter is null, this Data-File Builder-Class will utilize whichever 160 * {@code 'javac'} binary is available within the Operating-System's {@code 'PATH'} 161 * Environment-Variable. 162 * 163 * @throws IOException If any Operating-System I/O Errors throw. 164 */ 165 public static void build( 166 final BuildPackage[] pkgList, 167 final String[] argv, 168 final ReadOnlyList<String> additionalCompilerArgs, 169 final String JAVAC_BIN 170 ) 171 throws IOException 172 { 173 final ReadOnlyList<BuildPackage> selectedPackages = DataFilesCLI.run(pkgList, argv); 174 175 final PkgTextBar textBarPrinter = new PkgTextBar 176 (selectedPackages, "Working Package", BGREEN_BKGND, BCYAN); 177 178 final Map<String, Integer> totals = new TreeMap<>(); 179 180 int maxLen = 0; 181 182 for (final BuildPackage bp : selectedPackages) 183 { 184 textBarPrinter.print(bp); 185 clearClassFiles(bp.pkgRootDirectory + "data-files" + File.separator); 186 CompileDataFilesBuilders.compile(bp, additionalCompilerArgs, JAVAC_BIN); 187 int numExecuted = RunDataFilesBuilders.run(bp); 188 totals.put(bp.fullName, numExecuted); 189 if (bp.fullName.length() > maxLen) maxLen = bp.fullName.length(); 190 } 191 192 if (selectedPackages.size() > 1) printTotals(totals, maxLen+2); 193 } 194 195 196 // ******************************************************************************************** 197 // ******************************************************************************************** 198 // Utility / Helper Methods 199 // ******************************************************************************************** 200 // ******************************************************************************************** 201 202 203 // Clear Class Files in a Directory 204 private static void clearClassFiles(final String dataFilesDirName) throws IOException 205 { 206 final FileNode fn = FileNode 207 .createRoot(dataFilesDirName) 208 .loadTree(-1, FileNode.CLASS_FILES, null); 209 210 FileTransfer.deleteFilesRecursive(fn, null, null, System.out); 211 } 212 213 214 // Print up the little Map that the main for-loop keeps - which contains a tally or count 215 // on how many DataFileBuilderClass were found in each of the user's '../data-files/' 216 // directories. 217 218 private static void printTotals(Map<String, Integer> m, int MAX) 219 { 220 System.out.println( 221 "\n\n" + BRED_BKGND + " Package Totals: " + RESET + "\n\n" + 222 "The table below lists how many Java '.class'-Files were found within the " + 223 "'../data-files/' sub-directory (and all of its sub-directories) and implemented " + 224 "the 'DataFileBuilderClass' interface. These classes were all invoked using their " + 225 "respective 'DataFileBuilderClass.build(String)' methods.\n" 226 ); 227 228 for (Map.Entry<String, Integer> e : m.entrySet()) 229 { 230 final String k = e.getKey(); 231 final String s = StringParse.nChars(' ', MAX - k.length()); 232 System.out.println(k + s + e.getValue()); 233 } 234 235 System.out.println(); 236 } 237}