CommandLine.java

  1. /*
  2.  *    Copyright 2010-2023 the original author or authors.
  3.  *
  4.  *    Licensed under the Apache License, Version 2.0 (the "License");
  5.  *    you may not use this file except in compliance with the License.
  6.  *    You may obtain a copy of the License at
  7.  *
  8.  *       https://www.apache.org/licenses/LICENSE-2.0
  9.  *
  10.  *    Unless required by applicable law or agreed to in writing, software
  11.  *    distributed under the License is distributed on an "AS IS" BASIS,
  12.  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13.  *    See the License for the specific language governing permissions and
  14.  *    limitations under the License.
  15.  */
  16. package org.apache.ibatis.migration;

  17. import static org.apache.ibatis.migration.options.OptionsParser.parse;

  18. import java.io.File;
  19. import java.io.PrintStream;
  20. import java.util.Date;

  21. import org.apache.ibatis.migration.commands.Command;
  22. import org.apache.ibatis.migration.commands.Commands;
  23. import org.apache.ibatis.migration.commands.InfoCommand;
  24. import org.apache.ibatis.migration.commands.InitializeCommand;
  25. import org.apache.ibatis.migration.options.Options;
  26. import org.apache.ibatis.migration.options.SelectedOptions;
  27. import org.apache.ibatis.migration.utils.Util;

  28. public class CommandLine {
  29.   // Leave this non static as it is messed with in this project tests
  30.   private final PrintStream console = System.out;
  31.   private final String[] args;

  32.   public CommandLine(String[] args) {
  33.     this.args = args;
  34.   }

  35.   public void execute() {
  36.     final SelectedOptions selectedOptions = parse(args);
  37.     if (selectedOptions.needsHelp()) {
  38.       printUsage();
  39.       return;
  40.     }
  41.     if (selectedOptions.getCommand() == null) {
  42.       console.printf("No command specified.%n");
  43.       printUsage();
  44.       return;
  45.     }
  46.     try {
  47.       Command command = Commands.resolveCommand(selectedOptions.getCommand(), selectedOptions);
  48.       if (command instanceof InitializeCommand || command instanceof InfoCommand
  49.           || validBasePath(selectedOptions.getPaths().getBasePath())) {
  50.         runCommand(command, selectedOptions);
  51.       }
  52.     } catch (Exception e) {
  53.       String errorMessage = e.getMessage();

  54.       if (hasColor(selectedOptions)) {
  55.         console.printf(ConsoleColors.RED + "%nERROR: %s%n", errorMessage + ConsoleColors.RESET);
  56.       } else {
  57.         console.printf("%nERROR: %s%n", errorMessage);
  58.       }

  59.       if (selectedOptions.isTrace()) {
  60.         e.printStackTrace();
  61.       }
  62.       console.close();
  63.       System.exit(1); // Issue 730
  64.     }
  65.     console.close();
  66.   }

  67.   private void runCommand(Command command, SelectedOptions selectedOptions) {
  68.     console.printf("------------------------------------------------------------------------%n");
  69.     console.printf("-- MyBatis Migrations - %s%n", selectedOptions.getCommand());
  70.     console.printf("------------------------------------------------------------------------%n");

  71.     long start = System.currentTimeMillis();
  72.     boolean exceptionCaught = false;

  73.     try {
  74.       command.execute(selectedOptions.getParams());
  75.     } catch (Throwable t) {
  76.       exceptionCaught = true;
  77.       if (t instanceof MigrationException) {
  78.         throw (MigrationException) t;
  79.       }
  80.       throw new MigrationException(t);
  81.     } finally {
  82.       console.printf("------------------------------------------------------------------------%n");

  83.       if (hasColor(selectedOptions)) {
  84.         console.printf("-- MyBatis Migrations %s%s%s%n", exceptionCaught ? ConsoleColors.RED : ConsoleColors.GREEN,
  85.             exceptionCaught ? "FAILURE" : "SUCCESS", ConsoleColors.RESET);
  86.       } else {
  87.         console.printf("-- MyBatis Migrations %s%n", exceptionCaught ? "FAILURE" : "SUCCESS");
  88.       }

  89.       console.printf("-- Total time: %ss%n", (System.currentTimeMillis() - start) / 1000);
  90.       console.printf("-- Finished at: %s%n", new Date());
  91.       printMemoryUsage();
  92.       console.printf("------------------------------------------------------------------------%n");
  93.     }
  94.   }

  95.   protected boolean hasColor(SelectedOptions selectedOptions) {
  96.     return selectedOptions.hasColor() || Util.getPropertyOptionAsBoolean(Options.COLOR.toString().toLowerCase());
  97.   }

  98.   private void printMemoryUsage() {
  99.     final Runtime runtime = Runtime.getRuntime();
  100.     final int megaUnit = 1024 * 1024;
  101.     final long usedMemory = (runtime.totalMemory() - runtime.freeMemory()) / megaUnit;
  102.     final long totalMemory = runtime.totalMemory() / megaUnit;

  103.     console.printf("-- Final Memory: %sM/%sM%n", usedMemory, totalMemory);
  104.   }

  105.   private boolean validBasePath(File basePath) {
  106.     final boolean validDirectory = basePath.exists() && basePath.isDirectory();

  107.     if (!validDirectory) {
  108.       console.printf("Migrations path must be a directory: %s%n", basePath.getAbsolutePath());
  109.     }

  110.     return validDirectory;
  111.   }

  112.   private void printUsage() {
  113.     console.printf(
  114.         "%nUsage: migrate command [parameter] [--path=<directory>] [--env=<environment>] [--template=<path to custom template>]%n%n");
  115.     console.printf("--path=<directory>   Path to repository.  Default current working directory.%n");
  116.     console.printf("--env=<environment>  Environment to configure. Default environment is 'development'.%n");
  117.     console.printf("--template=<template>  Path to custom template for creating new sql scripts.%n");
  118.     console.printf("--force              Forces script to continue even if SQL errors are encountered.%n");
  119.     console.printf("--help               Displays this usage message.%n");
  120.     console.printf("--trace              Shows additional error details (if any).%n");
  121.     console.printf("--quiet              Suppresses output.%n");
  122.     console.printf("--color              Colorize output.%n");
  123.     console.printf("%n");
  124.     console.printf("Commands:%n");
  125.     console.printf("  info               Display build version informations.%n");
  126.     console.printf("  init               Creates (if necessary) and initializes a migration path.%n");
  127.     console.printf("  bootstrap          Runs the bootstrap SQL script (see scripts/bootstrap.sql for more).%n");
  128.     console.printf("  new <description>  Creates a new migration with the provided description.%n");
  129.     console.printf("  up [n]             Run unapplied migrations, ALL by default, or 'n' specified.%n");
  130.     console
  131.         .printf("  down [n]           Undoes migrations applied to the database. ONE by default or 'n' specified.%n");
  132.     console.printf("  version <version>  Migrates the database up or down to the specified version.%n");
  133.     console.printf("  pending            Force executes pending migrations out of order (not recommended).%n");
  134.     console.printf("  status             Prints the changelog from the database if the changelog table exists.%n");
  135.     console
  136.         .printf("  script <v1> <v2>   Generates a delta migration script from version v1 to v2 (undo if v1 > v2).%n");
  137.     console.printf("%n");
  138.     console.printf("  * Shortcuts are accepted by using the first few (unambiguous) letters of each command..%n");
  139.     console.printf("%n");
  140.   }
  141. }