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 &amp; Output:</B>
131     * 
132     * <BR />This class &amp; 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 &amp;
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}