All Downloads are FREE. Search and download functionalities are using the official Maven repository.

javax0.jamal.cmd.JamalMain Maven / Gradle / Ivy

package javax0.jamal.cmd;

import javax0.jamal.api.EnvironmentVariables;
import javax0.jamal.api.Input;
import javax0.jamal.api.Position;
import javax0.jamal.engine.Processor;
import javax0.jamal.poi.word.XWPFProcessor;
import javax0.jamal.tools.CmdParser;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.Arrays;
import java.util.Optional;
import java.util.Properties;
import java.util.Set;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * This is a command line file that can be used to process Jamal files starting Jamal from the command line.
 */
public class JamalMain {

    final static Set parameters = Set.of(
            "version",
            "verbose",
            "debug",
            "open",
            "close",
            "include",
            "exclude",
            "source",
            "target",
            "from", "to",
            "depth",
            "dry-dry-run",
            "dry-run",
            "docx",
            "help",
            "shcnf"
    );

    public static void main(String[] args) {
        final var params = CmdParser.parse(args, parameters);
        if (params.get("version").isPresent()) {
            final var version = new Properties();
            javax0.jamal.api.Processor.jamalVersion(version);
            System.out.printf("Jamal Version %s", version.getProperty("version"));
            return;
        }
        if (params.get("shcnf").isPresent()) {
            EnvironmentVariables.getProperties().forEach((k, v) -> System.out.printf("%s=%s\n", k, v));
            return;
        }
        if (params.get("help").isPresent()) {
            System.out.println("Usage: jamal [options] input output\n" +
                    "  -help                      help\n" +
                    "  -shcnf                     show the configuration values from ~/.jamal/setup.(properties|xml)\n" +
                    "  -version                   display version\n" +
                    "  -verbose                   print out the conversions\n" +
                    "  -open=          the macro opening string\n" +
                    "  -close=        the macro closing string\n" +
                    "  -depth=             directory traversal depth, default is infinite\n" +
                    "  -debug=             type:port, usually http:8080\n" +
                    "  -include=         file name regex pattern to include into the processing\n" +
                    "  -exclude=         file name regex pattern to exclude from the processing\n" +
                    "  -source=  source directory to start the processing\n" +
                    "  -target=  target directory to create the output\n" +
                    "  -from=              pattern for the file name transformation.\n" +
                    "  -to=          replacement for the file name transformation.\n" +
                    "  -dry-dry-run               run dry, do not execute Jamal\n" +
                    "  -dry-run                   run dry, do not write result to output file\n" +
                    "  -docx                      treat the input as a docx, Microsoft Word file\n" +
                    "");
            return;
        }
        if (params.get("debug").isPresent()) {
            EnvironmentVariables.setenv(EnvironmentVariables.JAMAL_DEBUG_ENV, params.get("debug").get());
        }
        if (Arrays.stream("include,exclude,source,target,from,to,depth".split(",")).map(params::get).anyMatch(Optional::isPresent)) {
            final var sourceDirectory = params.get("source").orElse(".");
            final var depth = params.get("depth").map(Integer::parseInt).orElse(Integer.MAX_VALUE);
            final var include = params.get("include").orElse(".*jam$");
            final var exclude = params.get("exclude").orElse(null);
            final var includePredicate = getPathPredicate(include);
            final var excludePredicate = getPathPredicate(exclude).negate();
            try {
                Files.walk(Paths.get(sourceDirectory), depth)
                        .filter(Files::isRegularFile)
                        .filter(includePredicate)
                        .filter(excludePredicate)
                        .forEach(s -> executeJamal(s, params));
            } catch (IOException e) {
                throw new RuntimeException("Cannot process the files by Jamal. Something is wrong.", e);
            }
        } else {
            if (params.get(0).isEmpty() || params.get(1).isEmpty()) {
                throw new IllegalArgumentException("You must specify at least two arguments: input and output");
            }
            if (params.get(2).isPresent()) {
                throw new IllegalArgumentException("You cannot specify more than two arguments: input and output");
            }
            final var inputFile = params.get(0).get();
            final var outputFile = params.get(1).get();
            executeJamal(Paths.get(new File(inputFile).getAbsolutePath()), Paths.get(new File(outputFile).getAbsolutePath()), params);
        }
    }

    private static void executeJamal(final Path inputPath, CmdParser params) {
        executeJamal(inputPath.toAbsolutePath(), calculateTargetFile(inputPath, params).toAbsolutePath(), params);
    }

    private static void executeJamal(final Path inputPath, final Path outputPath, CmdParser params) {
        try {
            if (params.get("verbose").isPresent()) {
                System.out.println("Jamal " + inputPath.toString() + " -> " + outputPath);
            }
            final var drydry = params.get("dry-dry-run").isPresent();
            final var dry = params.get("dry-run").isPresent();
            final var macroOpen = params.get("open").orElse("{");
            final var macroClose = params.get("close").orElse("}");
            if (!drydry) {
                if (params.get("docx").isPresent()) {
                    final var processor = new XWPFProcessor(macroOpen, macroClose);
                    processor.process(inputPath, dry ? null : outputPath);
                } else {
                    final String result;
                    try (final var processor = new Processor(macroOpen, macroClose)) {
                        result = processor.process(createInput(inputPath));
                    }
                    if (!dry) {
                        writeOutput(outputPath, result);
                    }
                }
            }

        } catch (Exception e) {
            logException(e);
        }

    }

    private static void writeOutput(Path output, String result) throws IOException {
        try {
            final var parent = output.getParent();
            if (parent != null) {
                if (!Files.exists(parent)) {
                    Files.createDirectories(parent);
                }
            }
        } catch (Exception e) {
            logException(e);
        }
        Files.write(output, result.getBytes(StandardCharsets.UTF_8),
                StandardOpenOption.WRITE,
                StandardOpenOption.TRUNCATE_EXISTING,
                StandardOpenOption.CREATE);
    }


    private static void logException(Exception e) {
        var sw = new StringWriter();
        var out = new PrintWriter(sw);
        e.printStackTrace(out);
        Arrays.stream(sw.toString().split("\n")).forEach(System.err::println);
    }

    private static Input createInput(Path inputFile) throws IOException {
        try (final var lines = Files.lines(inputFile)) {
            final var fileContent = lines.collect(Collectors.joining("\n"));
            return new javax0.jamal.tools.Input(fileContent, new Position(inputFile.toString(), 1));
        }
    }

    private static Path calculateTargetFile(final Path inputFile, CmdParser params) {
        final var sourceDirectory = params.get("source").orElse(".");
        final var targetDirectory = params.get("target").orElse(".");
        final var from = params.get("from").orElse("\\.jam$");
        final var to = params.get("to").orElse("");
        final var inputFileName = inputFile.toString();
        if (!inputFile.toString().replaceAll("\\\\","/").startsWith(sourceDirectory)) {
            throw new IllegalArgumentException(
                    String.format("The input file '%s' is not in the source directory '%s'"
                            , inputFileName
                            , sourceDirectory));

        }
        return Paths.get((targetDirectory + inputFile.toString().substring(sourceDirectory.length()))
                .replaceAll(from, to));
    }


    /**
     * Convert the regular expression to a predicate. If the regular expression is null or empty string then the
     * predicate is constant false.
     *
     * @param param regular expression or simple wild card string to be converted to match predicate
     * @return the predicate.
     */
    private static Predicate getPathPredicate(final String param) {
        final Predicate predicate;
        if (param != null && param.length() > 0) {
            Pattern pattern = Pattern.compile(param);
            predicate = p -> pattern.matcher(p.toString()).find();
        } else {
            predicate = p -> false;
        }
        return predicate;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy