001package Torello.Java.Build;
002
003import Torello.Java.ReadOnly.ReadOnlyList;
004
005import Torello.Java.Shell;
006import Torello.Java.GSUTIL;
007import Torello.Java.OSResponse;
008import Torello.Java.OSExtras;
009import Torello.Java.StringParse;
010
011import Torello.Java.Additional.BiAppendable;
012import Torello.Java.Additional.AppendableSafe;
013
014import static Torello.Java.C.BYELLOW;
015import static Torello.Java.C.BGREEN;
016import static Torello.Java.C.RESET;
017
018import java.io.File;
019import java.io.IOException;
020import java.util.Vector;
021import java.util.stream.Stream;
022
023/**
024 * This is the fifth Build-Stage, and it is part of the synchronization of a project with Google
025 * Cloud Platform Stroage Buckets.  This class relies heavily on the GCP Shell-Command
026 * {@code 'gsutil'} and it's Java implementation - {@link GSUTIL Torello.Java.GSUTIL}.
027 * 
028 * <BR /><BR />This class' synchronization-efforts entail copying the File-System's Java-Doc
029 * Directory-Contents onto the (User-Specified) Google Cloud Server Storage-Bucket.
030 * 
031 * <EMBED CLASS=external-html DATA-FILE-ID=STAGE_PRIVATE_NOTE>
032 * <EMBED CLASS='external-html' DATA-FILE-ID=S05_SYNC_JAVADOC>
033 */
034@Torello.JavaDoc.StaticFunctional
035public class S05_SyncJavaDoc
036{
037    // Completely irrelevant, and the 'private' modifier keeps it off of JavaDoc
038    private S05_SyncJavaDoc() { }
039
040    private static final String FS = java.io.File.separator;
041
042
043    // ********************************************************************************************
044    // ********************************************************************************************
045    // Copies entire 'javadoc/' directory-tree to GCS
046    // ********************************************************************************************
047    // ********************************************************************************************
048
049
050    public static void sync(final BuilderRecord brec) throws IOException
051    {
052        brec.timers.startStage05();
053        Printing.startStep(5);
054
055        OSResponse      osr     = null;
056        StringBuilder   logOnly = new StringBuilder();
057
058        final AppendableSafe logAndScreen = new AppendableSafe(
059            new BiAppendable(System.out, logOnly),
060            AppendableSafe.USE_APPENDABLE_ERROR
061        );
062
063        // Uses Shell-Contructor:
064        // (outputAppendable, commandStrAppendable, standardOutput, errorOutput)
065
066        // GSUTIL gsutil = new GSUTIL(logOnly, logAndScreen, null, null);
067        brec.cloudSync.initStage(logOnly, logAndScreen);
068        Shell shell = new Shell(logOnly, logAndScreen, null, null);
069
070        // Data-Record Explanation:
071        // 
072        // brec: BuilderRecord - Top-of-Tree Data-Record for executing a build, Contains everything
073        // cli:  (Command-Line-Interface) - All info gathered from user-input to "String[] argv"
074        // aor:  Auxiliary-Options Record - A Record containing only final / constant booleans,
075        //       whose values are all exactly equal to whether or not each of the 6 or 7 Auxiliary
076        //       options were passed, by the user, to "String[] argv" at the command line.
077
078        if (! brec.cli.aor.SKIP_REMOVE_GCS_FILES_SWITCH)
079        {
080            // osr = gsutil.RM(brec.cli.GCS_DIR + "javadoc/" + "**");
081            osr = brec.cloudSync.removeCloudJavaDocDir();
082            Util.HALT_ON_ERROR(osr);
083            Printing.PLS(logOnly, false);
084        }
085
086        // TRICKY !!! Do not use 'GCS_JAVADOC_DIR' here - because then it will be
087        // 'javadoc/javadoc/!!!
088
089        // osr = gsutil.CP(brec.LOCAL_JAVADOC_DIR, brec.cli.GCS_DIR, "-r");
090        osr = brec.cloudSync.copyJavaDocDirToCloudDir();
091        Util.HALT_ON_ERROR(osr);
092        Printing.PLS(logOnly, false);
093
094        osr = shell.RM(brec.LOCAL_JAVADOC_DIR, "-r");
095        Util.HALT_ON_ERROR(osr);
096        Printing.PLS(logOnly, false);
097
098        // if (brec.RUN_MAKE_PUBLIC)
099        if (brec.cloudSync.shouldRunMakePublic)
100        {
101            Printing.PLS(logOnly, false);
102            // osr = gsutil.MP(brec.cli.GCS_DIR + "javadoc/**");
103            osr = brec.cloudSync.makePublicJavaDocDir();
104            Util.HALT_ON_ERROR(osr);
105        }
106
107        brec.logs.write_S05_LOG(logOnly.toString());
108        brec.cloudSync.endStage();
109        brec.timers.endStage05();
110    }
111
112
113    // ********************************************************************************************
114    // ********************************************************************************************
115    // Copies only selected packages of the Java-Doc Directory to GCS
116    // ********************************************************************************************
117    // ********************************************************************************************
118
119
120    static void syncPart(final BuilderRecord brec) throws IOException
121    {
122        brec.timers.startStage05();
123        Printing.startStep(5);
124
125        OSResponse      osr     = null;
126        StringBuilder   logOnly = new StringBuilder();
127
128        final AppendableSafe logAndScreen = new AppendableSafe(
129            new BiAppendable(System.out, logOnly),
130            AppendableSafe.USE_APPENDABLE_ERROR
131        );
132
133        // Uses Shell-Contructor:
134        // (outputAppendable, commandStrAppendable, standardOutput, errorOutput)
135
136        Shell       shell   = new Shell(logOnly, logAndScreen, null, null);
137        OSExtras    ose     = new OSExtras();
138
139        // GSUTIL gsutil = new GSUTIL(logOnly, logAndScreen, null, null);
140        brec.cloudSync.initStage(logOnly, logAndScreen);
141
142        Stream.Builder<String>  aclCommandB = Stream.builder();
143        Vector<String>          copyDirs    = new Vector<>(4);
144
145
146        // brec: class BuilderRecord
147        // cli:  class CLI
148        // aor:  class AuxiliaryOptRecord
149
150        for (BuildPackage bp : brec.cli.sor.userSpecifiedPackages)
151        {
152            final String pkgRootLocalDir =
153                brec.LOCAL_JAVADOC_DIR + bp.fullName.replace(".", FS) + FS;
154
155            final String pkgRootCloudDir =
156
157                // brec.cli.GCS_DIR + "javadoc/" + bp.fullName.replace('.', '/') + '/';
158                //
159                // TO-DO: When I am capable of holding this inside my brain, I need to revisit
160                //        this line.  For now, I simply cannot think - and I'm trying to get this
161                //        B.S. to compile.  The current plan is to only run "syncAll" and not
162                //        "syncPart".  I will worry about this very soon, just not right now.
163                //        NOTE THE ORIGINAL LINE OF CODE IS DIRECTLY ABOVE, COMMENTED OUT.
164                // 
165                // Not sure brec.cloudSync
166
167                brec.cloudSync.cloudRootStorageDir +
168                "javadoc/" + bp.fullName.replace('.', '/') + '/';
169
170            logAndScreen.append("\nCopying Package HTML: " + BYELLOW + bp.fullName + RESET + '\n');
171            // osr = gsutil.CP(pkgRootLocalDir + '*', pkgRootCloudDir);
172            osr = brec.cloudSync.copySingleJDPackageToCloud
173                (pkgRootLocalDir, pkgRootCloudDir);
174
175            Util.HALT_ON_ERROR(osr);
176
177            // The GSUTIL.MP (Make-Public) Command is called once at the very end.
178            aclCommandB.accept(pkgRootCloudDir + '*');
179
180            // Empty out the previous calls stuff
181            copyDirs.clear();
182
183            if (new java.io.File(pkgRootLocalDir + "doc-files" + FS).exists())
184            {
185                copyDirs.add("doc-files" + FS);
186                aclCommandB.accept(pkgRootCloudDir + "doc-files" + FS + "**");
187            }
188
189            if (new java.io.File(pkgRootLocalDir + "hilite-files" + FS).exists())
190            {
191                copyDirs.add("hilite-files" + FS);
192                aclCommandB.accept(pkgRootCloudDir + "hilite-files" + FS + "**");
193            }
194
195            if (new java.io.File(pkgRootLocalDir + "stylesheets" + FS).exists())
196            {
197                copyDirs.add("stylesheets" + FS);
198                aclCommandB.accept(pkgRootCloudDir + "stylesheets" + FS + "**");
199            }
200
201
202            // This part (this 'if' statement) is a litte weird.
203            // If there are no 'doc-files/', 'stylesheets/' or 'hilite-files/' the next few lines
204            // will CRASH the BUILD.  However, there should always be 'hilite-files/', so the
205            // following check should always get a PASS!
206            // 
207            // I'm going to leave this check here, for now.  This error was discovered when trying
208            // to figure out the source of a different bug.  Because it is possible for a user to
209            // actually "turn off" the "HiLite Source" feature for an entire package - this check
210            // isn't actually a complete joke.  I never turned of Hi-Lite Files, since that's the
211            // main thing this Upgrader does!  Anyway, if such a decision by the user were made,
212            // then this 'if-statement' is very important...  OK?  :)  Have a nice day.
213            // 
214            // By the way, it's also possible for this list to empty because there were no
215            // no 'hilite-files/' due to a bug in the CLI-Processing for the "Partial-Build's"
216            // Menu-Options Package-Lists...  Specifically if a package were included in the list,
217            // but the Ugprader hadn't been run on that package, then this specific list right here
218            // (directly below) would, indeed, be empty.  That's the bug that was just fixed a
219            // moment ago.  (TL;DR: If you try to "Synchronize a Package" that wasn't upgraded by
220            // the Upgrader, It's very likely it won't have any of these "Copy-Dirs" either).  The
221            // Upgrader will **ALWAYS** at least add a 'hilite-files/' directory, unless that
222            // features was explicitly requested to be turned off by the user.
223
224            if (copyDirs.size() == 0) continue;
225
226
227            // This is the culmination of quite a bit of playing with the OSCommands class
228            // to allow a user to execute / run an external OS-Call (an external program)
229            // as if it had been invoked inside of some other directory that the in which
230            // the original Java-VM / JRE had been invoked.
231
232            ose.currentWorkingDirectory = new File(pkgRootLocalDir);
233
234            logAndScreen.append(
235                "\nOSExtras.currentWorkingDirectory was assigned:  " +
236                BYELLOW + pkgRootLocalDir + RESET + '\n'
237            );
238
239
240            // ORIGINAL:
241            // osr = gsutil.CP(copyDirs, pkgRootCloudDir, "-r");
242            //
243            // TO-DO PART 2: I am incapable of analyzing this right now.  I just want it to compile
244            //               and build at the moment.  I hate breaking my build, and that is what I
245            //               I have just done.  When the Build itself won't work, that is when 
246            //               I get really aggrivated
247            // 
248            //               THERE ARE ONLY TWO LINES THAT NEED REAL FIXING.
249            //               BOTH OF THEM ARE IN THIS FILE.
250            //
251            // OK, I SOLVED THE PROBLEM - HOWEVER, THE REIGNING SOLUTION DOES NOT EXTEND TO THE
252            // SCENARIO WHERE I STOP USING "GSUTIL" AND START ALLOWING "RCLONE" OR SOME KIND OF
253            // "S3".
254            // 
255            // Currently, "SyncPart" is a GSUTIL only method.  And since Torello.Java.Build is 
256            // just impossible for me to think about for very long.  I am going to stop this for a
257            // few weeks, and it is now going to be time to finish JavaDoc.Upgrade...
258            //
259            // "syncPart" works, but only with the GSUTILCloudSync version.  However since I have
260            // not written S3CloudSync, or RCloneCloudSync - I'm just not going to worry about it
261            // right now.  Build is true madness is what it usually feels like.  It is nothing but
262            // a long, long, LONG list of configurations, settings, and choices that are supposed
263            // to all be controllable from a simple CLI-argv String...-Array thing.
264
265            osr = brec.cloudSync.copyOtherPackageDirsToCloudDir
266                (ose, copyDirs, pkgRootCloudDir);
267
268            Util.HALT_ON_ERROR(osr);
269        }
270
271        String[] makePublicArr = aclCommandB.build().toArray(String[]::new);
272
273
274        // My Cute little hack for the day.  This will make Stage 8 a lot faster.
275        // Well, this isn't considered a hack anymore, because it works pretty well.
276        //
277        // NOTE: Even if "Make-Public" isn't executed on a directory because that GCP Bucket
278        //       directory has been assigned "Bucket-Level Permissions", it will stll be necessary
279        //       to run the "Set Max Age" (Stage 8 Stuff), if the user has requested it!  Therefore
280        //       we cannot just 'discard' the 'makePublicArr' when RUN_MAKE_PUBLIC is false.
281
282        brec.stage8GCSDirs = makePublicArr;
283
284
285        // REMEMBER: if this is ever invoked on a bucket that has bucket-level
286        // permissions, instead of object level permissions, THIS WOULD CRASH.
287        //
288        // NOTE: the content of the 'aclCommandB' Stream.Builder are just wholly ignored and
289        //       discarded (eventually), by the garbage-collector if the Storage-Bucket has been
290        //       assigned Bucket-Level permissions instead of Object-Level Permissions.
291
292        // if (brec.RUN_MAKE_PUBLIC)
293        if (brec.cloudSync.shouldRunMakePublic)
294        {
295            // Print these so they are legible
296            logAndScreen.append(BGREEN + "\nMake Copied Files Public:\n\n" + RESET);
297            for (String gcsDir : makePublicArr) logAndScreen.append('\t' + gcsDir + "\n");
298            logAndScreen.append('\n');
299
300            // Now do the actual "Make Public" Command
301            // osr = gsutil.MP(makePublicArr);
302
303            osr = brec.cloudSync.makePublicDirArr(makePublicArr);
304            Util.HALT_ON_ERROR(osr);
305        }
306
307        logAndScreen.append(BGREEN + "\nClean Up:\n" + RESET);
308        osr = shell.RM(brec.LOCAL_JAVADOC_DIR, "-r");
309        Util.HALT_ON_ERROR(osr);
310
311        brec.logs.write_S05_LOG(logOnly.toString());
312        brec.cloudSync.endStage();
313        brec.timers.endStage05();
314    }
315}