ProgressTransformDriver.java

/*
** Module   : ProgressTransformDriver.java
** Abstract : runs the Progress 4GL to Progress 4GL transformation for a file or set of files
**
** Copyright (c) 2018-2021, Golden Code Development Corporation.
**
** -#- -I- --Date-- ---------------------------------------Description---------------------------------------
** 001 GES 20181023 First version.
** 002 ECF 20190221 Added blacklist (filespec + ignore list) mode.
** 003 CA  20200412 Added incremental conversion support.
**     OM  20210923 Added -P<name> command line option for specifying the configuration profile.
*/

/*
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU Affero General Public License as
** published by the Free Software Foundation, either version 3 of the
** License, or (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU Affero General Public License for more details.
**
** You may find a copy of the GNU Affero GPL version 3 at the following
** location: https://www.gnu.org/licenses/agpl-3.0.en.html
** 
** Additional terms under GNU Affero GPL version 3 section 7:
** 
**   Under Section 7 of the GNU Affero GPL version 3, the following additional
**   terms apply to the works covered under the License.  These additional terms
**   are non-permissive additional terms allowed under Section 7 of the GNU
**   Affero GPL version 3 and may not be removed by you.
** 
**   0. Attribution Requirement.
** 
**     You must preserve all legal notices or author attributions in the covered
**     work or Appropriate Legal Notices displayed by works containing the covered
**     work.  You may not remove from the covered work any author or developer
**     credit already included within the covered work.
** 
**   1. No License To Use Trademarks.
** 
**     This license does not grant any license or rights to use the trademarks
**     Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
**     of Golden Code Development Corporation. You are not authorized to use the
**     name Golden Code, FWD, or the names of any author or contributor, for
**     publicity purposes without written authorization.
** 
**   2. No Misrepresentation of Affiliation.
** 
**     You may not represent yourself as Golden Code Development Corporation or FWD.
** 
**     You may not represent yourself for publicity purposes as associated with
**     Golden Code Development Corporation, FWD, or any author or contributor to
**     the covered work, without written authorization.
** 
**   3. No Misrepresentation of Source or Origin.
** 
**     You may not represent the covered work as solely your work.  All modified
**     versions of the covered work must be marked in a reasonable way to make it
**     clear that the modified work is not originating from Golden Code Development
**     Corporation or FWD.  All modified versions must contain the notices of
**     attribution required in this license.
*/

package com.goldencode.p2j.convert;

import java.io.*;
import java.util.*;
import com.goldencode.ast.*;
import com.goldencode.p2j.cfg.*;
import com.goldencode.p2j.schema.*;

/**
 * Provides a harness to drive the Progress 4GL to Progress 4GL transformation for a file or set
 * of files.
 * <p>
 * This program provides a command line interface.  See {@link #main} for the syntax. 
 */
public class ProgressTransformDriver
extends TransformDriver
{
   /** Associates mode names with detailed mode definitions. */
   private static final Map<String, RunMode> modes = new HashMap<>();
   
   /** Job title, which needs to be implemented in each subclass. */
   private static final String TITLE = "Progress 4GL Transformation Driver";
   
   /** Help text, which needs to be implemented in each subclass. */
   private static final String[] helpText = new String[]
   {
      "--------------------" + TITLE + "--------------------",
      "",
      "Syntax:",
      "   java -DP2J_HOME=<home> ProgressTransformDriver [options]* <mode> [user_defined_rule_set] <file-specs>",
      "",
      "Where",
      "   Options (F, S, and X are mutually exclusive. If none is specified <file-specs>",
      "              is a list of files added to command line):",
      "      Dn    = set DEBUG level 'n'. Must be a numeric digit between " + MSG_NONE + " (none)",
      "              and " + MSG_TRACE + " (trace) inclusive",
      "      F     = <file-specs> is a <filename> containing a custom FILE-LIST",
      "      S     = <file-specs> is composed of a root <directory> and \"<file-filter>\"",
      "              to select SPECIFIC files",
      "      X     = <file-specs> is similar to S but has an additional custom EXCLUDE",
      "              list file \"<filename>\" to be ignored",
      "      N     = NO recursion in <file-filter> (S/X options)",
      "      A     = ABORT scan part of front end on an error",
      "      Tn    = specify number of THREADS 'n' to use for front end file scan ('n'",
      "              must be >= 0; defaults to 1; set to 0 to use 1 thread per",
      "              available CPU)",
      "      L     = LIST files to be processed only; do not perform any further task",
      "      I     = INCREMENTAL conversion; only changed/new programs will be parsed",
      "              and converted",
      "      Pname = the <name> of the configuration PROFILE follows the option",
      "",
      "   Mode (one or more of the following values, use '+' to delimit if there are two", 
      "           or more values; don't insert spaces!)", 
      "      -------------------------------- Front End --------------------------------",
      "      F0 = preprocessor (in honor cache mode), lexer, parser, AST persistence and", 
      "           post-parse fixups",
      "      F1 = F0 + forced preprocessor execution",
      "      F2 = F1 + schema loader/fixups",
      "      F3 = F2 + call graph generation",
      "",
      "      ----------------------------- Transformation ------------------------------",
      "      TR = execute a user-defined transformation ruleset (this requires the",
      "           user-defined rule-set to be added)",
      "",
      "      ------------------------------ Anti-Parsing -------------------------------",
      "      AP = output ASTs to Progress 4GL source code",
      "",
      "   user_defined_rule_set (only possible in TR mode)",
      "",
      "   filelist   = arbitrary list of absolute and/or relative file names to scan",
      "                   (default approach)",
      "   directory  = a relative or absolute path (only used when using <file-filter>,",
      "                   S/X options)",
      "   file-filter= file filter specification of the filenames in the given directory",
      "                   to scan, should be enclosed in double quotes if any of the",
      "                   wildcard characters '*' or '?' are used (only used with S/X",
      "                   modes)",
      "   filename   = when used with the -F option, this is a single absolute or",
      "                   relative name of a text file that contains a custom list of",
      "                   absolute and/or relative file names of files to scan (i.e. the",
      "                   file list will be read from a file instead of being hard coded",
      "                   on the command line); there must be one file name per line in",
      "                   the file;",
      "                when used with the -X option, this is a single absolute or",
      "                   relative name of a text file that contains a custom list of",
      "                   specifications of file names to ignore; all other files",
      "                   specified by the primary <file-filter> are scanned.",
   };
   
   static
   {
      modes.put("F0", new RunMode(true , false, false, false, false, false));
      modes.put("F1", new RunMode(true , true , false, false, false, false));
      modes.put("F2", new RunMode(true , true , true , false, false, false));
      modes.put("F3", new RunMode(true , true , true , true , false, false));
      modes.put("TR", new RunMode(false, false, false, false, true , false));
      modes.put("AP", new RunMode(false, false, false, false, false, true));
   }
   
   /**
    * Creates an instance with a specific configuration.
    *
    * @param    job
    *           The details of this driver run.
    */
   ProgressTransformDriver(JobDefinition job)
   {
      super(job);
   }

   /**
    * Drive the transformation process using the file list of Progress ASTs that is already
    * defined in this instance.  The user must have provided a TRPL rule-set to execute,
    * otherwise this phase will be a NOP.
    */
   protected void middle()
   throws ConfigurationException,
          AstException,
          SchemaException,
          IOException
   {
      if (job.transform == null || job.transform.isEmpty())
      {
         return;
      }
      
      // ensure that downstream processing has the proper list of files
      convertSourceNamesToAstNames();
      
      processTrees("User-Defined Transformation", 
                   job.transform,
                   null,
                   false,
                   asts,
                   debug);
   }
   
   /**
    * Drive the back end of the transformation process using the file list of Progress ASTs
    * that is already defined in this instance.  Each AST will be anti-parsed back to
    * Progress 4GL source code.
    */
   protected void back()
   throws ConfigurationException,
          AstException,
          SchemaException,
          IOException
   {      
      // ensure that downstream processing has the proper list of files
      convertSourceNamesToAstNames();
      
      processTrees("Anti-Parsing",
                   "progress/anti_parser",
                   null,
                   false,
                   asts,
                   debug);
   }
   
   /**
    * Provides a command line interface for an end user to drive the scanning harness.
    * <p>
    * The program will return a non-zero code if there is a fatal error running the conversion.
    * <p>
    * Syntax:
    * <pre>{@code java -DP2J_HOME=<home> ProgressTransformDriver [-options]* <mode> [user_defined_rule_set] <file-specs>}</pre>
    * Where:
    * <ul>
    *   <li>Options (F, S, and X are mutually exclusive. If none is specified <file-specs> is a list of files
    *       added to command line):
    *       <ul>
    *          <li>Dn = set debug level 'n' (must be a numeric digit between {@code MSG_NONE} (0) and 
    *              {@code MSG_TRACE} (3) inclusive
    *          <li>I = incremental conversion; only changed/new programs will be parsed and converted.
    *          <li>F = {@code <file-specs>} is a {@code <filename>} containing a custom FILE-LIST, instead of
    *              using the explicit command line file list
    *          <li>S = {@code <file-specs>} is composed of a root {@code <directory>} and a {@code
    *              "<file-filter>"}, to select SPECIFIC files instead of an explicit command line file list
    *          <li>X = {@code <file-specs>} is similar to S but has an additional custom EXCLUDE list file
    *              {@code "<filename>"} to be ignored
    *          <li>N = NO recursion in {@code <file-filter>} (S/X options)",
    *          <li>A = ABORT scan part of front end on an error
    *          <li>Tn = specify number of THREADS 'n' to use for front end file scan ('n' must be {@code >=}
    *              0; defaults to 1; set to 0 to use 1 thread per available CPU)
    *          <li>L = LIST files to be processed only; do not perform any further task
    *          <li>Pname = the {@code <name>} of the configuration PROFILE follows the option
    *       </ul>
    *   <li>{@code mode} (one or more of the following values, use '+' to delimit if there are two or more
    *       values; don't insert spaces!)
    *       <ul>
    *          <li>Front End
    *              <ul>
    *                 <li>F0 = preprocessor (in honor cache mode), lexer, parser, AST persistence and
    *                          post-parse fixups
    *                 <li>F1 = F0 + forced preprocessor execution
    *                 <li>F2 = F1 + schema loader/fixups
    *                 <li>F3 = F2 + call graph generation
    *              </ul>
    *          <li>Transformation
    *              <ul>
    *                 <li>TR = execute a user-defined transformation ruleset (this requires an extra parameter
    *                          after the mode and before the source file specifications)
    *              </ul>
    *          <li>Anti-Parsing
    *              <ul>
    *                 <li>AP = output ASTs to Progress 4GL source code
    *              </ul>
    *       </ul>
    *   <li>The optional {@code user_defined_rule_set} specifies the user-defined rule-set filename to execute
    *        (only some modes support this, see sub-class documentation for details)
    *   <li>explicit command line list (default approach if none of S, P, or F are present)
    *       <ul>
    *          <li>{@code <filelist>} is arbitrary list of absolute and/or relative file names to scan, this
    *              list is hard coded in the command line itself
    *          <li>any number of files may be listed on the command line, subject to command shell limits
    *       </ul>
    *   <li>custom file list (FILE approach)
    *       <ul>
    *          <li>{@code <filename>} is a single absolute or relative filename of a text file that contains a
    *              custom list of absolute and/or relative file names of files to scan
    *          <li>in other words, the file list will be read from a file instead of being hard coded on the
    *              command line
    *          <li>there must be one filename per line in the file
    *          <li>there is no limit of the number of files in the list
    *       </ul>
    *   <li>file-spec mode (expressly SPECIFIED files approach)
    *       <ul>
    *          <li>{@code <directory>} is the root directory to search for files
    *          <li>{@code "filespec"} is the file specification that will be used to create a list of files to
    *              process, should be enclosed in double quotes if any of the wildcard characters '*' or '?'
    *              are used
    *       </ul>
    *   <li>custom ignore list (file-spec mode with additional EXCLUDE list)
    *       <ul>
    *          <li>{@code <directory>} is the root directory to search for files
    *          <li>{@code "filespec"}" is the file specification that will be used to create a list of files
    *              to process, should be enclosed in double quotes if any of the wildcard characters '*' or
    *              '?' are used
    *          <li>{@code <filename>} is a single absolute or relative filename of a text file that contains a
    *              custom list of specifications of file names to ignore
    *          <li>asterisk (*) and question mark (?) wildcards are permitted to represent zero or more and
    *              exactly one wildcard characters, respectively
    *          <li>files specified by the primary {@code filespec} which are not matched by the ignore list
    *              are scanned as they would be in {@code filespec} mode.
    *       </ul>
    * </ul>
    *
    * @param   args 
    *          List of command line arguments.
    */
   public static void main(String[] args)
   {
      JobDefinition job = processCommandLine(args, modes, helpText);
      
      if (job != null)
      {
         ProgressTransformDriver driver = new ProgressTransformDriver(job);
         driver.executeJob(TITLE);
      }
   }
}