1 /**
2 Copyright: Copyright (c) 2017, Joakim Brännström. All rights reserved.
3 License: MPL-2
4 Author: Joakim Brännström (joakim.brannstrom@gmx.com)
5 
6 This Source Code Form is subject to the terms of the Mozilla Public License,
7 v.2.0. If a copy of the MPL was not distributed with this file, You can obtain
8 one at http://mozilla.org/MPL/2.0/.
9 
10 This file contains an optional main function suitable for plugins.
11 
12 It takes care of configuring the logging level in std.experimental.logger if
13 the user call the program with "-d|--debug".
14 
15 This optional main function requires that:
16  - the module is named dextool.plugin.runner
17  - the module provides a function runPlugin that takes the program arguments.
18 */
19 module dextool.plugin.main.standard;
20 
21 import logger = std.experimental.logger;
22 import std.algorithm : filter, among, findAmong, canFind, sort;
23 import std.array : array, empty, appender;
24 import std.conv : to;
25 import std.stdio : writeln;
26 
27 import colorlog : VerboseMode, confLogger, setLogLevel, toLogLevel, RootLogger,
28     SpanMode, getRegisteredLoggers, parseLogNames, NameLevel;
29 
30 /** Parse the raw command line.
31  */
32 VerboseMode parseLogLevel(string[] args) {
33     import std.traits : EnumMembers;
34 
35     if (!findAmong(args, ["-d", "--debug"]).empty)
36         return VerboseMode.trace;
37 
38     auto verbose = findAmong(args, ["--verbose"]);
39     try {
40         if (verbose.length >= 2)
41             return verbose[1].to!VerboseMode;
42     } catch (Exception e) {
43         logger.warning(e.msg);
44         logger.info("--verbose supports ", [EnumMembers!VerboseMode]);
45     }
46 
47     return VerboseMode.info;
48 }
49 
50 NameLevel[] parseLogModules(string[] args, logger.LogLevel defaultLogLvl) {
51     auto modules = findAmong(args, ["--verbose-module"]);
52     try {
53         if (modules.length >= 2)
54             return parseLogNames(modules[1], defaultLogLvl);
55     } catch (Exception e) {
56         logger.info(e.msg);
57     }
58 
59     return [NameLevel(RootLogger, defaultLogLvl)];
60 }
61 
62 int main(string[] args) {
63     if (canFind(args, "--short-plugin-help")) {
64         confLogger(VerboseMode.warning);
65         setLogLevel(RootLogger, logger.LogLevel.warning, SpanMode.depth);
66     } else {
67         const mode = parseLogLevel(args);
68         confLogger(mode);
69 
70         const modules = parseLogModules(args, toLogLevel(mode));
71         try {
72             if (modules.empty)
73                 setLogLevel([RootLogger], toLogLevel(mode), SpanMode.depth);
74             else
75                 setLogLevel(modules, SpanMode.depth);
76         } catch (Exception e) {
77             logger.info(e.msg);
78             logger.info("--verbose-module supports ", getRegisteredLoggers.sort);
79             logger.info("Use comma to separate name=logLevel");
80         }
81     }
82 
83     auto remArgs = appender!(string[])();
84     for (size_t i = 0; i < args.length; ++i) {
85         if (args[i].among("-d", "--debug")) {
86             // skip one
87         } else if (args[i].among("--verbose", "--verbose-module")) {
88             ++i; //skip two
89         } else {
90             remArgs.put(args[i]);
91         }
92     }
93 
94     // REQUIRED BY PLUGINS USING THIS MAIN
95     import dextool.plugin.runner : runPlugin;
96 
97     return runPlugin(remArgs.data);
98 }