1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
package Torello.Java.Build;

import Torello.Java.ReadOnly.ReadOnlyList;

import Torello.Java.Shell;
import Torello.Java.GSUTIL;
import Torello.Java.OSResponse;
import Torello.Java.OSExtras;
import Torello.Java.StringParse;

import Torello.Java.Additional.BiAppendable;
import Torello.Java.Additional.AppendableSafe;

import static Torello.Java.C.BYELLOW;
import static Torello.Java.C.BGREEN;
import static Torello.Java.C.RESET;

import java.io.File;
import java.io.IOException;
import java.util.Vector;
import java.util.stream.Stream;

/**
 * This is the fifth Build-Stage, and it is part of the synchronization of a project with Google
 * Cloud Platform Stroage Buckets.  This class relies heavily on the GCP Shell-Command
 * {@code 'gsutil'} and it's Java implementation - {@link GSUTIL Torello.Java.GSUTIL}.
 * 
 * <BR /><BR />This class' synchronization-efforts entail copying the File-System's Java-Doc
 * Directory-Contents onto the (User-Specified) Google Cloud Server Storage-Bucket.
 * 
 * <EMBED CLASS=external-html DATA-FILE-ID=STAGE_PRIVATE_NOTE>
 * <EMBED CLASS='external-html' DATA-FILE-ID=S05_SYNC_JAVADOC>
 */
@Torello.JavaDoc.StaticFunctional
public class S05_SyncJavaDoc
{
    // Completely irrelevant, and the 'private' modifier keeps it off of JavaDoc
    private S05_SyncJavaDoc() { }

    private static final String FS = java.io.File.separator;


    // ********************************************************************************************
    // ********************************************************************************************
    // Copies entire 'javadoc/' directory-tree to GCS
    // ********************************************************************************************
    // ********************************************************************************************


    public static void sync(final BuilderRecord brec) throws IOException
    {
        brec.timers.startStage05();
        Printing.startStep(5);

        OSResponse      osr     = null;
        StringBuilder   logOnly = new StringBuilder();

        final AppendableSafe logAndScreen = new AppendableSafe(
            new BiAppendable(System.out, logOnly),
            AppendableSafe.USE_APPENDABLE_ERROR
        );

        // Uses Shell-Contructor:
        // (outputAppendable, commandStrAppendable, standardOutput, errorOutput)

        // GSUTIL gsutil = new GSUTIL(logOnly, logAndScreen, null, null);
        brec.cloudSync.initStage(logOnly, logAndScreen);
        Shell shell = new Shell(logOnly, logAndScreen, null, null);

        // Data-Record Explanation:
        // 
        // brec: BuilderRecord - Top-of-Tree Data-Record for executing a build, Contains everything
        // cli:  (Command-Line-Interface) - All info gathered from user-input to "String[] argv"
        // aor:  Auxiliary-Options Record - A Record containing only final / constant booleans,
        //       whose values are all exactly equal to whether or not each of the 6 or 7 Auxiliary
        //       options were passed, by the user, to "String[] argv" at the command line.

        if (! brec.cli.aor.SKIP_REMOVE_GCS_FILES_SWITCH)
        {
            // osr = gsutil.RM(brec.cli.GCS_DIR + "javadoc/" + "**");
            osr = brec.cloudSync.removeCloudJavaDocDir();
            Util.HALT_ON_ERROR(osr);
            Printing.PLS(logOnly, false);
        }

        // TRICKY !!! Do not use 'GCS_JAVADOC_DIR' here - because then it will be
        // 'javadoc/javadoc/!!!

        // osr = gsutil.CP(brec.LOCAL_JAVADOC_DIR, brec.cli.GCS_DIR, "-r");
        osr = brec.cloudSync.copyJavaDocDirToCloudDir();
        Util.HALT_ON_ERROR(osr);
        Printing.PLS(logOnly, false);

        osr = shell.RM(brec.LOCAL_JAVADOC_DIR, "-r");
        Util.HALT_ON_ERROR(osr);
        Printing.PLS(logOnly, false);

        // if (brec.RUN_MAKE_PUBLIC)
        if (brec.cloudSync.shouldRunMakePublic)
        {
            Printing.PLS(logOnly, false);
            // osr = gsutil.MP(brec.cli.GCS_DIR + "javadoc/**");
            osr = brec.cloudSync.makePublicJavaDocDir();
            Util.HALT_ON_ERROR(osr);
        }

        brec.logs.write_S05_LOG(logOnly.toString());
        brec.cloudSync.endStage();
        brec.timers.endStage05();
    }


    // ********************************************************************************************
    // ********************************************************************************************
    // Copies only selected packages of the Java-Doc Directory to GCS
    // ********************************************************************************************
    // ********************************************************************************************


    static void syncPart(final BuilderRecord brec) throws IOException
    {
        brec.timers.startStage05();
        Printing.startStep(5);

        OSResponse      osr     = null;
        StringBuilder   logOnly = new StringBuilder();

        final AppendableSafe logAndScreen = new AppendableSafe(
            new BiAppendable(System.out, logOnly),
            AppendableSafe.USE_APPENDABLE_ERROR
        );

        // Uses Shell-Contructor:
        // (outputAppendable, commandStrAppendable, standardOutput, errorOutput)

        Shell       shell   = new Shell(logOnly, logAndScreen, null, null);
        OSExtras    ose     = new OSExtras();

        // GSUTIL gsutil = new GSUTIL(logOnly, logAndScreen, null, null);
        brec.cloudSync.initStage(logOnly, logAndScreen);

        Stream.Builder<String>  aclCommandB = Stream.builder();
        Vector<String>          copyDirs    = new Vector<>(4);


        // brec: class BuilderRecord
        // cli:  class CLI
        // aor:  class AuxiliaryOptRecord

        for (BuildPackage bp : brec.cli.sor.userSpecifiedPackages)
        {
            final String pkgRootLocalDir =
                brec.LOCAL_JAVADOC_DIR + bp.fullName.replace(".", FS) + FS;

            final String pkgRootCloudDir =

                // brec.cli.GCS_DIR + "javadoc/" + bp.fullName.replace('.', '/') + '/';
                //
                // TO-DO: When I am capable of holding this inside my brain, I need to revisit
                //        this line.  For now, I simply cannot think - and I'm trying to get this
                //        B.S. to compile.  The current plan is to only run "syncAll" and not
                //        "syncPart".  I will worry about this very soon, just not right now.
                //        NOTE THE ORIGINAL LINE OF CODE IS DIRECTLY ABOVE, COMMENTED OUT.
                // 
                // Not sure brec.cloudSync

                brec.cloudSync.cloudRootStorageDir +
                "javadoc/" + bp.fullName.replace('.', '/') + '/';

            logAndScreen.append("\nCopying Package HTML: " + BYELLOW + bp.fullName + RESET + '\n');
            // osr = gsutil.CP(pkgRootLocalDir + '*', pkgRootCloudDir);
            osr = brec.cloudSync.copySingleJDPackageToCloud
                (pkgRootLocalDir, pkgRootCloudDir);

            Util.HALT_ON_ERROR(osr);

            // The GSUTIL.MP (Make-Public) Command is called once at the very end.
            aclCommandB.accept(pkgRootCloudDir + '*');

            // Empty out the previous calls stuff
            copyDirs.clear();

            if (new java.io.File(pkgRootLocalDir + "doc-files" + FS).exists())
            {
                copyDirs.add("doc-files" + FS);
                aclCommandB.accept(pkgRootCloudDir + "doc-files" + FS + "**");
            }

            if (new java.io.File(pkgRootLocalDir + "hilite-files" + FS).exists())
            {
                copyDirs.add("hilite-files" + FS);
                aclCommandB.accept(pkgRootCloudDir + "hilite-files" + FS + "**");
            }

            if (new java.io.File(pkgRootLocalDir + "stylesheets" + FS).exists())
            {
                copyDirs.add("stylesheets" + FS);
                aclCommandB.accept(pkgRootCloudDir + "stylesheets" + FS + "**");
            }


            // This part (this 'if' statement) is a litte weird.
            // If there are no 'doc-files/', 'stylesheets/' or 'hilite-files/' the next few lines
            // will CRASH the BUILD.  However, there should always be 'hilite-files/', so the
            // following check should always get a PASS!
            // 
            // I'm going to leave this check here, for now.  This error was discovered when trying
            // to figure out the source of a different bug.  Because it is possible for a user to
            // actually "turn off" the "HiLite Source" feature for an entire package - this check
            // isn't actually a complete joke.  I never turned of Hi-Lite Files, since that's the
            // main thing this Upgrader does!  Anyway, if such a decision by the user were made,
            // then this 'if-statement' is very important...  OK?  :)  Have a nice day.
            // 
            // By the way, it's also possible for this list to empty because there were no
            // no 'hilite-files/' due to a bug in the CLI-Processing for the "Partial-Build's"
            // Menu-Options Package-Lists...  Specifically if a package were included in the list,
            // but the Ugprader hadn't been run on that package, then this specific list right here
            // (directly below) would, indeed, be empty.  That's the bug that was just fixed a
            // moment ago.  (TL;DR: If you try to "Synchronize a Package" that wasn't upgraded by
            // the Upgrader, It's very likely it won't have any of these "Copy-Dirs" either).  The
            // Upgrader will **ALWAYS** at least add a 'hilite-files/' directory, unless that
            // features was explicitly requested to be turned off by the user.

            if (copyDirs.size() == 0) continue;


            // This is the culmination of quite a bit of playing with the OSCommands class
            // to allow a user to execute / run an external OS-Call (an external program)
            // as if it had been invoked inside of some other directory that the in which
            // the original Java-VM / JRE had been invoked.

            ose.currentWorkingDirectory = new File(pkgRootLocalDir);

            logAndScreen.append(
                "\nOSExtras.currentWorkingDirectory was assigned:  " +
                BYELLOW + pkgRootLocalDir + RESET + '\n'
            );


            // ORIGINAL:
            // osr = gsutil.CP(copyDirs, pkgRootCloudDir, "-r");
            //
            // TO-DO PART 2: I am incapable of analyzing this right now.  I just want it to compile
            //               and build at the moment.  I hate breaking my build, and that is what I
            //               I have just done.  When the Build itself won't work, that is when 
            //               I get really aggrivated
            // 
            //               THERE ARE ONLY TWO LINES THAT NEED REAL FIXING.
            //               BOTH OF THEM ARE IN THIS FILE.
            //
            // OK, I SOLVED THE PROBLEM - HOWEVER, THE REIGNING SOLUTION DOES NOT EXTEND TO THE
            // SCENARIO WHERE I STOP USING "GSUTIL" AND START ALLOWING "RCLONE" OR SOME KIND OF
            // "S3".
            // 
            // Currently, "SyncPart" is a GSUTIL only method.  And since Torello.Java.Build is 
            // just impossible for me to think about for very long.  I am going to stop this for a
            // few weeks, and it is now going to be time to finish JavaDoc.Upgrade...
            //
            // "syncPart" works, but only with the GSUTILCloudSync version.  However since I have
            // not written S3CloudSync, or RCloneCloudSync - I'm just not going to worry about it
            // right now.  Build is true madness is what it usually feels like.  It is nothing but
            // a long, long, LONG list of configurations, settings, and choices that are supposed
            // to all be controllable from a simple CLI-argv String...-Array thing.

            osr = brec.cloudSync.copyOtherPackageDirsToCloudDir
                (ose, copyDirs, pkgRootCloudDir);

            Util.HALT_ON_ERROR(osr);
        }

        String[] makePublicArr = aclCommandB.build().toArray(String[]::new);


        // My Cute little hack for the day.  This will make Stage 8 a lot faster.
        // Well, this isn't considered a hack anymore, because it works pretty well.
        //
        // NOTE: Even if "Make-Public" isn't executed on a directory because that GCP Bucket
        //       directory has been assigned "Bucket-Level Permissions", it will stll be necessary
        //       to run the "Set Max Age" (Stage 8 Stuff), if the user has requested it!  Therefore
        //       we cannot just 'discard' the 'makePublicArr' when RUN_MAKE_PUBLIC is false.

        brec.stage8GCSDirs = makePublicArr;


        // REMEMBER: if this is ever invoked on a bucket that has bucket-level
        // permissions, instead of object level permissions, THIS WOULD CRASH.
        //
        // NOTE: the content of the 'aclCommandB' Stream.Builder are just wholly ignored and
        //       discarded (eventually), by the garbage-collector if the Storage-Bucket has been
        //       assigned Bucket-Level permissions instead of Object-Level Permissions.

        // if (brec.RUN_MAKE_PUBLIC)
        if (brec.cloudSync.shouldRunMakePublic)
        {
            // Print these so they are legible
            logAndScreen.append(BGREEN + "\nMake Copied Files Public:\n\n" + RESET);
            for (String gcsDir : makePublicArr) logAndScreen.append('\t' + gcsDir + "\n");
            logAndScreen.append('\n');

            // Now do the actual "Make Public" Command
            // osr = gsutil.MP(makePublicArr);

            osr = brec.cloudSync.makePublicDirArr(makePublicArr);
            Util.HALT_ON_ERROR(osr);
        }

        logAndScreen.append(BGREEN + "\nClean Up:\n" + RESET);
        osr = shell.RM(brec.LOCAL_JAVADOC_DIR, "-r");
        Util.HALT_ON_ERROR(osr);

        brec.logs.write_S05_LOG(logOnly.toString());
        brec.cloudSync.endStage();
        brec.timers.endStage05();
    }
}