Mercurial > cgi-bin > hgweb.cgi > PassMan
diff src/main/kotlin/name/blackcap/passman/ImportSubcommand.kt @ 16:7a74ae668665
Add export subcommand.
author | David Barts <n5jrn@me.com> |
---|---|
date | Sun, 05 Feb 2023 10:50:39 -0800 |
parents | 4dae7a15ee48 |
children | ea65ab890f66 |
line wrap: on
line diff
--- a/src/main/kotlin/name/blackcap/passman/ImportSubcommand.kt Fri Feb 03 18:48:13 2023 -0800 +++ b/src/main/kotlin/name/blackcap/passman/ImportSubcommand.kt Sun Feb 05 10:50:39 2023 -0800 @@ -3,37 +3,21 @@ import com.opencsv.CSVParserBuilder import com.opencsv.CSVReaderBuilder import com.opencsv.exceptions.CsvException -import org.apache.commons.cli.* -import java.io.FileReader +import org.apache.commons.cli.ParseException +import java.io.FileInputStream import java.io.IOException +import java.io.InputStreamReader import java.text.SimpleDateFormat import java.util.* -import kotlin.system.exitProcess class ImportSubcommand(): Subcommand() { private companion object { - val CSV_DATE_FORMAT = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'").apply { - timeZone = TimeZone.getTimeZone("UTC") - isLenient = false - } - const val ESCAPE = "escape" - const val FORCE = "force" - const val HELP = "help" - const val IGNORE = "ignore" - const val QUOTE = "quote" - const val SEPARATOR = "separator" - const val SKIP = "skip" const val NFIELDS = 7 - } - private lateinit var commandLine: CommandLine + private lateinit var csvDateFormat: SimpleDateFormat private lateinit var db: Database - - /* default option values */ - private var escape = '\\' - private var quote = '"' - private var separator = ',' - + private val options = ImportExportArguments() + private lateinit var csvFile: String private var line = 0 override fun run(args: Array<String>) { @@ -50,58 +34,32 @@ } private fun parseArguments(args: Array<String>) { - val options = Options().apply { - addOption("e", ImportSubcommand.ESCAPE, true, "CSV escape character (default $escape).") - addOption("f", ImportSubcommand.FORCE, false, "Do not ask before overwriting.") - addOption("h", ImportSubcommand.HELP, false, "Print this help message.") - addOption("i", ImportSubcommand.IGNORE, false, "Ignore white space before quoted strings.") - addOption("q", ImportSubcommand.QUOTE, true, "CSV string-quoting character (default $quote).") - addOption("s", ImportSubcommand.SEPARATOR, true, "CSV separator character (default $separator).") - addOption("k", ImportSubcommand.SKIP, false, "Skip first line of input.") - } - try { - commandLine = DefaultParser().parse(options, args) - } catch (e: ParseException) { - die(e.message ?: "syntax error", 2) - } - if (commandLine.hasOption(ImportSubcommand.HELP)) { - HelpFormatter().printHelp("$SHORTNAME import [options] csv_file", options) - exitProcess(0) + val params = parseInto("import", args, options) + when (params.size) { + 0 -> die("expecting CSV file name", 2) + 1 -> csvFile = params[0] + else -> die("unexpected trailing arguments", 2) } - if (commandLine.args.isEmpty()) { - die("expecting other CSV file name", 2) - } - if (commandLine.args.size > 1) { - die("unexpected trailing arguments", 2) + csvDateFormat = SimpleDateFormat(options.format).apply { + timeZone = TimeZone.getTimeZone(options.zone) + isLenient = false } - escape = getOptionChar(ImportSubcommand.ESCAPE, escape) - quote = getOptionChar(ImportSubcommand.QUOTE, quote) - separator = getOptionChar(ImportSubcommand.SEPARATOR, separator) - } - - private fun getOptionChar(optionName: String, defaultValue: Char): Char { - val optionValue = commandLine.getOptionValue(optionName) ?: return defaultValue - val ret = optionValue.firstOrNull() - if (ret == null) { - die("--$optionName value must not be empty") - } - return ret!! } private fun doImport() { val csvParser = CSVParserBuilder() - .withEscapeChar(escape) - .withQuoteChar(quote) - .withSeparator(separator) - .withIgnoreLeadingWhiteSpace(commandLine.hasOption(ImportSubcommand.IGNORE)) + .withEscapeChar(options.escape) + .withQuoteChar(options.quote) + .withSeparator(options.separator) + .withIgnoreLeadingWhiteSpace(options.ignore) .build() - val csvReader = CSVReaderBuilder(FileReader(commandLine.args[0])) + val csvReader = CSVReaderBuilder(InputStreamReader(FileInputStream(csvFile), options.charset)) .withCSVParser(csvParser) .build() csvReader.use { - if (commandLine.hasOption(ImportSubcommand.SKIP)) { + if (options.skip) { line++ it.skip(1) } @@ -145,7 +103,7 @@ return null } try { - return CSV_DATE_FORMAT.parse(unparsed) + return csvDateFormat.parse(unparsed) } catch (e: ParseException) { die("${see(unparsed)} - invalid date/time string") throw e /* kotlin is too stupid to realize this never happens */ @@ -153,7 +111,7 @@ } private fun okToChange(thisEntry: Entry?, otherEntry: Entry): Boolean = - thisEntry == null || commandLine.hasOption(FORCE) || askUserIfOkToOverwrite(thisEntry, otherEntry) + thisEntry == null || options.force || askUserIfOkToOverwrite(thisEntry, otherEntry) private fun saysNull(string: String) = string.lowercase() == "null"