package com.owent.xresloader; import org.apache.commons.cli.*; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import java.io.IOException; import java.io.InputStream; import java.nio.charset.UnsupportedCharsetException; import java.util.Properties; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; // Import log4j classes. public class ProgramOptions { private static Logger logger = null; public class RenameRule { public Pattern match; public String replace; } /** * 单例 */ private static ProgramOptions instance = null; private static Options options = null; private static String version = null; public FileType outType; public Protocol protocol; public String protocolFile = ""; public String outputDirectory = "."; public String dataSourceDirectory = "."; public String dataSourceFile = ""; public FileType dataSourceType; public String[] dataSourceMetas = null; public String dataSourceMetaDelimiter = "\\|"; public RenameRule renameRule = null; public boolean enableFormular = true; public boolean enbleEmptyList = false; public int prettyIndent = 0; public boolean enableStdin = false; public String constPrint = ""; public boolean luaGlobal = false; public String xmlRootName = "root"; public String javascriptExport = null; public String javascriptGlobalVar = ""; private ProgramOptions() { dataSourceMetas = new String[]{}; outType = FileType.BIN; protocol = Protocol.PROTOBUF; outputDirectory = System.getProperty("user.dir"); dataSourceDirectory = outputDirectory; dataSourceType = FileType.BIN; } public static ProgramOptions getInstance() { if (instance == null) { instance = new ProgramOptions(); instance.reset(); } return instance; } public void reset() { outType = FileType.BIN; protocol = Protocol.PROTOBUF; protocolFile = ""; outputDirectory = ""; dataSourceDirectory = ""; dataSourceFile = ""; dataSourceType = FileType.BIN; dataSourceMetas = null; dataSourceMetaDelimiter = "\\|"; renameRule = null; enableFormular = true; enbleEmptyList = false; prettyIndent = 0; enableStdin = false; constPrint = ""; luaGlobal = false; xmlRootName = "root"; javascriptExport = null; javascriptGlobalVar = ""; } private static Options get_options_group() { if (null != options) { return options; } // create the Options options = new Options(); options.addOption("h", "help", false, "print this help message and exit"); options.addOption(Option.builder("t") .longOpt("output-type") .desc("output type(bin, lua, msgpack, json, xml, javascript/js)") .hasArg() .argName("TYPE") .build() ); options.addOption(Option.builder("p") .longOpt("proto") .desc("protocol(protobuf)") .hasArg() .argName("PROTOCOL") .build() ); options.addOption(Option.builder("f") .longOpt("proto-file") .desc("protocol description file") .hasArg() .argName("FILE NAME") .build() ); options.addOption(Option.builder("o") .longOpt("output-dir") .desc("output directory") .hasArg() .argName("DIRECTORY PATH") .build() ); options.addOption(Option.builder("d") .longOpt("data-src-dir") .desc("data source directory(where to find excel specified by meta)") .hasArg() .argName("DIRECTORY PATH") .build() ); options.addOption(Option.builder("s") .longOpt("src-file") .desc("data source file(.xls, .xlsx, .cvs, .xlsm, .ods, .ini, .cfg, .conf, .json)") .hasArg() .argName("META FILE PATH") .build() ); options.addOption(Option.builder("m") .longOpt("src-meta") .desc( String.format("%s\n\t%-32s=>%s\n\t%-32s=>%s\n\t%-32s=>%s\n\t%-32s=>%s", "data description meta information of data source.", ".xls,/xlsx/.cvx/.xlsm/.dos", "scheme sheet name", ".ini/.cfg/.conf", "scheme section name", ".json", "scheme key name", "[NOTHING]", "KEY=VALUE1|VAL2|VAL3 pair of scheme configures" ) ) .hasArg() .argName("META NAME") .build() ); options.addOption(Option.builder("l") .longOpt("delimiter") .desc(String.format("regex delimiter for description meta when data source file is [NOTHING].(default: %s)", getInstance().dataSourceMetaDelimiter)) .hasArg() .argName("DELTMITER") .build() ); options.addOption("v", "version", false, "print version and exit"); options.addOption(Option.builder("n") .longOpt("rename") .desc("rename output file name(regex), sample: /(?i)\\.bin$/\\.lua/") .hasArg() .argName("RENAME PATTERN") .build() ); options.addOption(Option.builder() .longOpt("pretty") .desc("set pretty output and set ident length when output type supported.(disable pretty output by set to 0)") .hasArg() .argName("INDENT LENGTH") .build() ); options.addOption(Option.builder("c") .longOpt("const-print") .desc("print all const data to file") .hasArg() .argName("OUTPUT FILE PATH") .build() ); options.addOption(Option.builder() .longOpt("xml-root") .desc("set xml root node name.(default: root)") .hasArg() .argName("ROOT NAME") .build() ); options.addOption(Option.builder() .longOpt("javascript-export") .desc("set javascript export mode(nodejs, amd or no)") .hasArg() .argName("EXPORT MODE") .build() ); options.addOption(Option.builder() .longOpt("javascript-global") .desc("set javascript export namespace of window or global") .hasArg() .argName("NAME") .build() ); options.addOption(null, "disable-excel-formular", false, "disable formular in excel. will be faster when convert data."); options.addOption(null, "enable-excel-formular", false, "[default] enable formular in excel. will be slower when convert data."); options.addOption(null, "disable-empty-list", false, "[default] remove empty elements in a list or repeated field."); options.addOption(null, "enable-empty-list", false, "keep empty elements in a list or repeated field with default value."); options.addOption(null, "stdin", false, "enable read from stdin and convert more files."); options.addOption(null, "lua-global", false, "add data to _G if in lua mode when print const data"); return options; } public int init(String[] args) { reset(); // create parser DefaultParser parser = new DefaultParser(); CommandLine cmd = null; try { // parse the command line arguments cmd = parser.parse( get_options_group(), args ); } catch( ParseException exp ) { // oops, something went wrong ProgramOptions.getLoger().error("parsing failed. reason: \"%s\" failed", exp.getMessage()); String script = System.getProperty("java.class.path"); HelpFormatter formatter = new HelpFormatter(); formatter.setWidth(140); formatter.printHelp("Usage: java -client -jar " + script + " [options...]", options); return -1; } if (cmd.hasOption('h')) { String script = System.getProperty("java.class.path"); HelpFormatter formatter = new HelpFormatter(); formatter.setWidth(140); formatter.printHelp(String.format("java -client -jar \"%s\" [options...]", script), get_options_group()); return 1; } if (cmd.hasOption('v')) { System.out.println(getVersion()); return 1; } if (cmd.hasOption("stdin")) { enableStdin = true; } if (cmd.hasOption("disable-empty-list")) { enbleEmptyList = false; } else if(cmd.hasOption("enable-empty-list")) { enbleEmptyList = true; } // target type if (cmd.hasOption('t')) { String val = cmd.getOptionValue('t'); if (val.equalsIgnoreCase("bin")) { outType = FileType.BIN; } else if (val.equalsIgnoreCase("lua")) { outType = FileType.LUA; } else if (val.equalsIgnoreCase("msgpack")){ outType = FileType.MSGPACK; } else if (val.equalsIgnoreCase("json")){ outType = FileType.JSON; } else if (val.equalsIgnoreCase("xml")){ outType = FileType.XML; } else if (val.equalsIgnoreCase("js") || val.equalsIgnoreCase("javascript")) { outType = FileType.JAVASCRIPT; } else { ProgramOptions.getLoger().error("invalid output type ", val); return -1; } } // protocol type if (cmd.hasOption('p')) { String val = cmd.getOptionValue('p'); if (val.equalsIgnoreCase("protobuf")) { protocol = Protocol.PROTOBUF; } else if (val.equalsIgnoreCase("capnproto")) { protocol = Protocol.CAPNPROTO; } else if (val.equalsIgnoreCase("flatbuffer")){ protocol = Protocol.FLATBUFFER; } else { ProgramOptions.getLoger().error("invalid protocol type ", val); return -2; } } // protocol file protocolFile = cmd.getOptionValue('f', ""); if (protocolFile.isEmpty()) { return 1; } luaGlobal = cmd.hasOption("lua-global"); xmlRootName = cmd.getOptionValue("xml-root", xmlRootName); javascriptExport = cmd.getOptionValue("javascript-export", javascriptExport); javascriptGlobalVar = cmd.getOptionValue("javascript-global", javascriptGlobalVar); // output dir outputDirectory = cmd.getOptionValue('o', "."); // data sorce dir dataSourceDirectory = cmd.getOptionValue('d', "."); // pretty print prettyIndent = Integer.parseInt(cmd.getOptionValue("pretty", "0")); // const print if (cmd.hasOption('c')) { constPrint = cmd.getOptionValue('c'); return 0; } // macro source file path if (cmd.hasOption('s')) { dataSourceFile = cmd.getOptionValue('s'); int dot_index = dataSourceFile.lastIndexOf('.'); String name_suffix = dot_index >= 0 && dot_index < dataSourceFile.length() - 1? dataSourceFile.substring(dot_index + 1) : null; if (null != name_suffix && ( name_suffix.equalsIgnoreCase("xls") || name_suffix.equalsIgnoreCase("xlsx") || name_suffix.equalsIgnoreCase("cvs") || name_suffix.equalsIgnoreCase("xlsm") || name_suffix.equalsIgnoreCase("ods") )) { dataSourceType = FileType.EXCEL; } else if (null != name_suffix && ( name_suffix.equalsIgnoreCase("ini") || name_suffix.equalsIgnoreCase("cfg") || name_suffix.equalsIgnoreCase("conf") )) { dataSourceType = FileType.INI; } else if (null != name_suffix && name_suffix.equalsIgnoreCase("json")) { dataSourceType = FileType.JSON; // } else if (null != name_suffix && name_suffix.equalsIgnoreCase("lua")) { // dataSourceType = FileType.LUA; // } else if (null != name_suffix && name_suffix.equalsIgnoreCase("xml")) { // dataSourceType = FileType.XML; } } // macro names dataSourceMetas = cmd.getOptionValues('m'); if (cmd.hasOption('l')) { dataSourceMetaDelimiter = cmd.getOptionValue('l'); } // rename rules if (cmd.hasOption('n')) { do { String rule_string = cmd.getOptionValue('n'); rule_string = rule_string.trim(); if (rule_string.isEmpty()) { ProgramOptions.getLoger().error("Invalid rename rule %s", rule_string); break; } String[] groups = rule_string.split(rule_string.substring(0, 1)); int start_index = 0; for (; start_index < groups.length; ++start_index) { if (groups[start_index].isEmpty()) continue; break; } if (groups.length < start_index + 2) { ProgramOptions.getLoger().error("Invalid rename rule %s", rule_string); break; } Pattern match_rule = null; try { match_rule = Pattern.compile(groups[start_index]); } catch (PatternSyntaxException e) { ProgramOptions.getLoger().error("Invalid rename regex rule %s", groups[start_index]); break; } renameRule = new RenameRule(); renameRule.match = match_rule; renameRule.replace = groups[start_index + 1]; } while(false); } // special functions if (cmd.hasOption("disable-excel-formular")) { enableFormular = false; } else if(cmd.hasOption("enable-excel-formular")) { enableFormular = true; } if (cmd.hasOption("disable-empty-list")) { enbleEmptyList = false; } else if(cmd.hasOption("enable-empty-list")) { enbleEmptyList = true; } return 0; } public String getVersion() { if (version == null) { InputStream inCfg = getClass().getClassLoader().getResourceAsStream("application.properties"); Properties props = new Properties(); try { props.load(inCfg); version = props.getProperty("version"); } catch (IOException e) { ProgramOptions.getLoger().error("Get version failed.\n%s", e.toString()); version = "Unknown"; } } return version; } public enum FileType {BIN, LUA, MSGPACK, JSON, XML, INI, EXCEL, JAVASCRIPT} public enum Protocol {PROTOBUF, CAPNPROTO, FLATBUFFER} static public Logger getLoger() { if (null != logger) { return logger; } String name = "xresloader"; InputStream inCfg = getInstance().getClass().getClassLoader().getResourceAsStream("application.properties"); Properties props = new Properties(); try { props.load(inCfg); name = props.getProperty("name"); } catch (IOException e) { System.err.println(String.format("[ERROR] Get application name failed.\n%s", e.toString())); } try { logger = LogManager.getFormatterLogger(name); } catch (UnsupportedCharsetException e) { System.err.println(String.format("[WARN] Unknown console charset %s, we will try use UTF-8 for console output", e.getCharsetName())); } if (null == logger) { //logger = LogManager.get } return logger; } }