aboutsummaryrefslogtreecommitdiff
path: root/common/src/main/kotlin/Cli.kt
blob: 4c231e74811dccb85498cd3347ac3ba4cab3001b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
/*
 * This file is part of LibEuFin.
 * Copyright (C) 2023-2024 Taler Systems S.A.

 * LibEuFin 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, or
 * (at your option) any later version.

 * LibEuFin 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 should have received a copy of the GNU Affero General Public
 * License along with LibEuFin; see the file COPYING.  If not, see
 * <http://www.gnu.org/licenses/>
 */

package tech.libeufin.common

import com.github.ajalt.clikt.core.*
import com.github.ajalt.clikt.parameters.types.*
import com.github.ajalt.clikt.parameters.arguments.*
import com.github.ajalt.clikt.parameters.options.*
import com.github.ajalt.clikt.parameters.groups.*
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.slf4j.event.Level
import java.nio.file.Path

private val logger: Logger = LoggerFactory.getLogger("libeufin-config")

fun Throwable.fmtLog(logger: Logger) {
    var msg = StringBuilder(message ?: this::class.simpleName)
    var cause = cause;
    while (cause != null) {
        msg.append(": ")
        msg.append(cause.message ?: cause::class.simpleName)
        cause = cause.cause
    }
    logger.error(msg.toString())
    logger.debug("{}", this)
}

fun cliCmd(logger: Logger, level: Level, lambda: () -> Unit) {
    // Set root log level
    val root = LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME) as ch.qos.logback.classic.Logger
    root.setLevel(ch.qos.logback.classic.Level.convertAnSLF4JLevel(level));
    // Run cli command catching all errors
    try {
        lambda()
    } catch (e: Throwable) {
        e.fmtLog(logger)
        throw ProgramResult(1)
    }
}

class CommonOption: OptionGroup() {
    val config by option(
        "--config", "-c",
        help = "Specifies the configuration file"
    ).path()
    val log by option(
        "--log", "-L",
        help = "Configure logging to use LOGLEVEL"
    ).enum<Level>().default(Level.INFO)
}

class CliConfigCmd(configSource: ConfigSource) : CliktCommand("Inspect or change the configuration", name = "config") {
    init {
        subcommands(CliConfigDump(configSource), CliConfigPathsub(configSource), CliConfigGet(configSource))
    }

    override fun run() = Unit
}

private class CliConfigGet(private val configSource: ConfigSource) : CliktCommand("Lookup config value", name = "get") {
    private val common by CommonOption()
    private val isPath by option(
        "--filename", "-f",
        help = "Interpret value as path with dollar-expansion"
    ).flag()
    private val section by argument()
    private val option by argument()


    override fun run() = cliCmd(logger, common.log) {
        val config = configSource.fromFile(common.config)
        if (isPath) {
            val res = config.lookupPath(section, option)
            if (res == null) {
                throw Exception("option '$option' in section '$section' not found in config")
            }
            println(res)
        } else {
            val res = config.lookupString(section, option)
            if (res == null) {
                throw Exception("option '$option' in section '$section' not found in config")
            }
            println(res)
        }
    }
}



private class CliConfigPathsub(private val configSource: ConfigSource) : CliktCommand("Substitute variables in a path", name = "pathsub") {
    private val common by CommonOption()
    private val pathExpr by argument()

    override fun run() = cliCmd(logger, common.log) {
        val config = configSource.fromFile(common.config)
        println(config.pathsub(pathExpr))
    }
}

private class CliConfigDump(private val configSource: ConfigSource) : CliktCommand("Dump the configuration", name = "dump") {
    private val common by CommonOption()

    override fun run() = cliCmd(logger, common.log) {
        val config = configSource.fromFile(common.config)
        println("# install path: ${config.getInstallPath()}")
        println(config.stringify())
    }
}