1 module settings;
2 
3 import core.stdc.stdlib;
4 import model;
5 import std.range;
6 import std.regex;
7 import std.stdio;
8 version (unittest) import unit_threaded;
9 
10 struct Settings
11 {
12     string compiler;
13     string[] depsFiles;
14     bool scan;
15     string[] umlFiles;
16     Regex!char pattern;
17     bool detail;
18     bool transitive;
19     bool dot;
20     string[] targetFiles;
21     bool simplify;
22     string[] unrecognizedArgs;
23 }
24 
25 Settings read(string[] args)
26 in (!args.empty)
27 {
28     import std.exception : enforce;
29     import std.getopt : config, defaultGetoptPrinter, getopt, GetoptResult;
30 
31     Settings settings;
32 
33     with (settings)
34     {
35         string filter;
36         GetoptResult result;
37 
38         try
39         {
40             result = getopt(args,
41                 config.passThrough,
42                 "compiler|c", "Specify the compiler to use", &compiler,
43                 "deps", "Read module dependencies from file", &depsFiles,
44                 "uml", "Read dependencies from PlantUML file", &umlFiles,
45                 "filter", "Filter source files  matching the regular expression", &filter,
46                 "detail", "Inspect dependencies between modules instead of packages", &detail,
47                 "transitive|t", "Keep transitive dependencies", &transitive,
48                 "dot", "Write dependency graph in the DOT language", &dot,
49                 "check", "Check against the PlantUML target dependencies", &targetFiles,
50                 "simplify", "Use simplifying assumptions for the check (experimental)", &simplify,
51             );
52             if (!filter.empty)
53             {
54                 enforce(!compiler.empty || !depsFiles.empty,
55                         "filter can only be applied to dependencies collected by a compiler");
56 
57                 pattern = regex(filter);
58             }
59         }
60         catch (Exception exception)
61         {
62             stderr.writeln("error: ", exception.msg);
63             exit(EXIT_FAILURE);
64         }
65         if (result.helpWanted)
66         {
67             import std.path : baseName;
68 
69             writefln("Usage: %s [options] files", args.front.baseName);
70             writeln("Process import dependencies as created by dmd with the --deps switch.");
71             writeln("If no compiler is specified, source files are scanned for (simple) import declarations.");
72             defaultGetoptPrinter("Options:", result.options);
73             exit(EXIT_SUCCESS);
74         }
75         unrecognizedArgs = args.dropOne;
76     }
77     return settings;
78 }
79 
80 @("read settings")
81 unittest
82 {
83     const settings = read(["depend", "--deps", "dependencies", "--check", "target"]);
84 
85     with (settings)
86     {
87         depsFiles.should.be == ["dependencies"];
88         targetFiles.should.be == ["target"];
89     }
90 }
91 
92 @("read settings with unrecognized arguments")
93 unittest
94 {
95     const settings = read(["depend", "main.d", "--detail"]);
96 
97     with (settings)
98     {
99         unrecognizedArgs.should.be == ["main.d"];
100         detail.should.be == true;
101     }
102 }