src/litestorepkg/lib/cli.nim
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 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 |
import parseopt, strutils, json, os, strtabs import logger, config, types, utils const favicon = "../../admin/favicon.ico".slurp var operation = opRun directory:string = "" readonly = false logLevel = "warn" system = false mount = false auth = newJNull() middleware = newStringTable() configuration = newJNull() authFile = "" configFile = "" exOperation = "" exFile = "" exBody = "" exType = "" exUri = "" cliSettings = newJObject() let usage* = appname & " v" & pkgVersion & " - Lightweight REST Document Store" & """ (c) 2015-2020 Fabio Cevasco Usage: litestore [command] [option1 option2 ...] Commands: delete Delete a previously-imported specified directory (requires -d). execute Execute an operation on data stored in the datastore (requires -o, -u, and in certain cases -f or -b and -t). import Import the specified directory into the datastore (requires -d). export Export the previously-imported specified directory to the current directory (requires -d). optimize Optimize search indexes. vacuum Vacuum datastore. Options: -a, --address Specify server address (default: 127.0.0.1). --auth Specify an authentication/authorization configuration file. -b, --body Specify a string containing input data for an operation to be executed. -w, --middleware Specify a path to a folder containing middleware definitions. -d, --directory Specify a directory to serve, import, export, delete, or mount. -c, --config Specify a configuration file. -f, --file Specify a file containing input data for an operation to be executed. -h, --help Display this message. -l, --log Specify the log level: debug, info, warn, error, none (default: info) -m, --mount Mirror database changes to the specified directory on the filesystem. -o, --operation Specify an operation to execute via the execute command: get, put, delete, patch, post, head, options. -p, --port Specify server port number (default: 9500). -r, --readonly Allow only data retrieval operations. -s, --store Specify a datastore file (default: data.db) --system Set the system flag for import, export, and delete operations -t, --type Specify a content type for the body an operation to be executed via the execute command. -u, --uri Specify an uri to execute an operation through the execute command. -v, --version Display the program version. -w, --middleware Specify a path to a folder containing middleware definitions. """ for kind, key, val in getOpt(): case kind: of cmdArgument: case key: of "run": operation = opRun of "import": operation = opImport of "execute": operation = opExecute of "export": operation = opExport of "delete": operation = opDelete of "optimize": operation = opOptimize of "vacuum": operation = opVacuum else: discard of cmdLongOption, cmdShortOption: case key: of "address", "a": if val == "": fail(100, "Address not specified.") address = val cliSettings["address"] = %address of "port", "p": if val == "": fail(101, "Port not specified.") port = val.parseInt cliSettings["port"] = %port of "store", "s": file = val cliSettings["store"] = %file of "log", "l": if val == "": fail(102, "Log level not specified.") case val: of "info": LOG.level = lvInfo of "warn": LOG.level = lvWarn of "debug": LOG.level = lvDebug of "error": LOG.level = lvError of "none": LOG.level = lvNone else: fail(103, "Invalid log level '$1'" % val) loglevel = val cliSettings["log"] = %logLevel of "directory", "d": if val == "": fail(104, "Directory not specified.") directory = val cliSettings["directory"] = %directory of "middleware", "w": if val == "": fail(115, "Middleware path not specified.") if not val.existsDir(): fail(116, "Middleware directory does not exist.") for file in val.walkDir(): if file.kind == pcFile or file.kind == pcLinkToFile: middleware[file.path.splitFile[1]] = file.path.readFile() of "operation", "o": if val == "": fail(106, "Operation not specified.") exOperation = val of "file", "f": if val == "": fail(107, "File not specified.") exFile = val of "uri", "u": if val == "": fail(108, "URI not specified.") exUri = val of "body", "b": if val == "": fail(112, "Body not specified.") exBody = val of "type", "t": if val == "": fail(113, "Content type not specified.") exType = val of "auth": if val == "": fail(114, "Authentication/Authorization configuration file not specified.") authFile = val of "config", "c": if val == "": fail(115, "Configuration file not specified.") configuration = val.parseFile configFile = val of "mount", "m": mount = true cliSettings["mounnt"] = %mount of "version", "v": echo pkgVersion quit(0) of "help", "h": echo usage quit(0) of "readonly", "r": readonly = true cliSettings["readonly"] = %readonly else: discard else: discard # Process auth configuration if present if auth == newJNull() and configuration != newJNull() and configuration.hasKey("signature"): auth = newJObject(); auth["access"] = newJObject(); auth["signature"] = configuration["signature"] for k, v in configuration["resources"].pairs: if v.hasKey("auth"): auth["access"][k] = v["auth"] # Process config settings if present and if no cli settings are set if configuration != newJNull() and configuration.hasKey("settings"): let settings = configuration["settings"] if not cliSettings.hasKey("address") and settings.hasKey("address"): address = settings["address"].getStr if not cliSettings.hasKey("port") and settings.hasKey("port"): port = settings["port"].getInt if not cliSettings.hasKey("store") and settings.hasKey("store"): file = settings["store"].getStr if not cliSettings.hasKey("directory") and settings.hasKey("directory"): directory = settings["directory"].getStr if not cliSettings.hasKey("mount") and settings.hasKey("mount"): mount = settings["mount"].getBool if not cliSettings.hasKey("readonly") and settings.hasKey("readonly"): readonly = settings["readonly"].getBool # Validation if directory == "" and (operation in [opDelete, opImport, opExport] or mount): fail(105, "--directory option not specified.") if exFile == "" and (exOperation in ["put", "post", "patch"]): fail(109, "--file option not specified") if exUri == "" and operation == opExecute: fail(110, "--uri option not specified") if exOperation == "" and operation == opExecute: fail(111, "--operation option not specified") LS.operation = operation LS.address = address LS.port = port LS.file = file LS.directory = directory LS.readonly = readonly LS.favicon = favicon LS.loglevel = loglevel LS.auth = auth LS.manageSystemData = system LS.middleware = middleware LS.authFile = authFile LS.config = configuration LS.configFile = configFile LS.mount = mount LS.execution.file = exFile LS.execution.body = exBody LS.execution.ctype = exType LS.execution.uri = exUri LS.execution.operation = exOperation |