1 /**
2 An application-local variant map of string keys.
3 These are static properties loaded at compile-time
4 from the file "dxx.ini".
5 So it's a map of the platform info that we can use
6 for example in a dynamic module to ensure compatibility.
7 The ini properties are labelled DXXConfig.
8 The local properties are first loaded from a config
9 file at runtime, specified by a parameter in "dxx.ini"
10 
11 Copyright: Copyright 2018 Mark Fisher
12 
13 License:
14 Permission is hereby granted, free of charge, to any person obtaining a copy of
15 this software and associated documentation files (the "Software"), to deal in
16 the Software without restriction, including without limitation the rights to
17 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
18 of the Software, and to permit persons to whom the Software is furnished to do
19 so, subject to the following conditions:
20 
21 The above copyright notice and this permission notice shall be included in all
22 copies or substantial portions of the Software.
23 
24 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30 SOFTWARE.
31 **/
32 module dxx.util.config;
33 
34 private import ctini.ctini;
35 
36 private import std.format;
37 private import std.array : appender,join;
38 private import std.stdio;
39 private import std.experimental.logger;
40 private import std.conv;
41 private import std.traits;
42 private import std.compiler;
43 private import std.process : environment;
44 private import std.variant;
45 
46 private import core.runtime;
47 
48 private import dxx.packageVersion;
49 private import dxx.constants;
50 private import dxx.util.storage;
51 private import dxx.util.ini;
52 
53 // Compile-time config loaded from "dxx.ini"
54 enum DXXConfig = IniConfig!("dxx.ini");
55 
56 /**
57  * Singleton class containing the variant map.
58 **/
59 final class LocalConfig {
60     static __gshared LocalConfig _appconfig;
61     static __gshared Variant[string] properties;
62 
63     static void setRuntimeDefaults(ref Variant[string] properties) {
64         properties[DXXConfig.keys.packageVersion] = Constants.libVersion;
65         properties[DXXConfig.keys.packageTimestamp] = Constants.libTimestamp;
66         properties[DXXConfig.keys.packageTimestampISO] = Constants.libTimestampISO;
67         properties[DXXConfig.keys.compilerName] = Constants.compilerName;
68         properties[DXXConfig.keys.compilerVersionMajor] = Constants.compilerVersionMajor.to!string;
69         properties[DXXConfig.keys.compilerVersionMinor] = Constants.compilerVersionMinor.to!string;
70         properties[DXXConfig.keys.compileTimestamp] = Constants.compileTimestamp;
71 
72         properties[DXXConfig.keys.hostOS] =  RTConstants.constants.argString;
73         properties[DXXConfig.keys.unitTest] =  RTConstants.constants.unitTest;
74         properties[DXXConfig.keys.buildType] =  RTConstants.constants.buildType;
75 
76         properties[DXXConfig.keys.dxxModule] =  RTConstants.constants.dxxModule;
77 
78         properties[DXXConfig.keys.currentDir] = RTConstants.constants.curDir;
79         properties[DXXConfig.keys.appDir] = RTConstants.constants.appDir;
80         //properties[DXXConfig.keys.applicationName] =
81         properties[DXXConfig.keys.commandLine] = RTConstants.constants.argString;
82         properties[DXXConfig.keys.appCommandLine] = RTConstants.constants.argsApp;
83         properties[DXXConfig.keys.commandLinePassthrough] = RTConstants.constants.argsAppPassthrough;
84         properties[DXXConfig.keys.appName] =  RTConstants.constants.appBaseName;
85         properties[DXXConfig.keys.appFileName] =  RTConstants.constants.appFileName;
86         properties[DXXConfig.keys.appBaseName] =  RTConstants.constants.appBaseName;
87         
88         properties[DXXConfig.keys.processID] =  RTConstants.constants.processID;
89         // how to make a static per-thread key.
90         //properties[DXXConfig.keys.threadID] =  RTConstants.constants.appThreadID;
91         
92     }
93 
94     static Variant[string] readProperties(File* f) {
95       Variant[string] p;
96       return p;
97     }
98 
99     shared static this() {
100         debug {
101           sharedLog.info("Config initialising.");
102         }
103         //MsgLog.info(DXXConfig.messages.MSG_CONFIG_INIT);
104         File f;
105         auto configFile = environment.get(DXXConfig.envKeys.configFile,
106                 DXXConfig.app.configFile);
107         try {
108             sharedLog.info(MsgText!(DXXConfig.messages.MSG_CONFIG_DEFAULT)(configFile));
109             f = inputConfigFile!(DXXConfig.app)(configFile);
110             properties = readProperties(&f);
111         } catch(Exception e) {
112             if(DXXConfig.app.createDefaultConfig) {
113               sharedLog.info(MsgText!(DXXConfig.messages.MSG_CONFIG_INIT_DEFAULT));
114               auto of = outputConfigFile!(DXXConfig.app)(DXXConfig.app.configFile);
115               of.write(import(DXXConfig.app.configDefaults));
116               of.flush;
117               of.close;
118               f = inputConfigFile!(DXXConfig.app)(DXXConfig.app.configFile);
119               properties = readProperties(&f);
120           }
121         }
122 
123         iterateValuesF!(DXXConfig.vars)( (string fqn,string k,string v) {
124             properties[k]=v;
125         } );
126 
127         version(Windows) {
128             static if(__traits(compiles,DXXConfig.windows.vars)) {
129                 iterateValuesF!(DXXConfig.windows.vars)( (string fqn,string k,string v) {
130                     properties[k]=v;
131                 } );
132             }
133         }
134 
135         version(Win32) {
136             static if(__traits(compiles,DXXConfig.win32.vars)) {
137                 iterateValuesF!(DXXConfig.win32.vars)( (string fqn,string k,string v) {
138                     properties[k]=v;
139                 } );
140             }
141         }
142 
143         version(Win64) {
144             static if(__traits(compiles,DXXConfig.win64.vars)) {
145                 iterateValuesF!(DXXConfig.win64.vars)( (string fqn,string k,string v) {
146                     properties[k]=v;
147                 } );
148             }
149         }
150 
151         version(Posix) {
152             static if(__traits(compiles,DXXConfig.posix.vars)) {
153                 iterateValuesF!(DXXConfig.posix.vars)( (string fqn,string k,string v) {
154                     properties[k]=v;
155                 } );
156             }
157         }
158 
159         version(Linux) {
160             static if(__traits(compiles,DXXConfig.linux.vars)) {
161                 iterateValuesF!(DXXConfig.linux.vars)( (string fqn,string k,string v) {
162                     properties[k]=v;
163                 } );
164             }
165         }
166 
167         version(MacOS) {
168             static if(__traits(compiles,DXXConfig.macos.vars)) {
169                 iterateValuesF!(DXXConfig.macos.vars)( (string fqn,string k,string v) {
170                     properties[k]=v;
171                 } );
172             }
173         }
174 
175         setRuntimeDefaults(properties);
176 
177         if(_appconfig is null) {
178             _appconfig = new LocalConfig;
179         }
180     }
181 
182     auto static get(string s) {
183         if(auto x = s in properties) return *x;
184         else return Variant(null);
185     }
186 
187     auto static get(s : string)() {
188         if(auto x = s in properties) return *x;
189         else return Variant(null);
190     }
191 
192     auto static lookup(T)(string s) {
193         //if(s in properties) {
194           return get(s).get!T;
195         //} else return null;
196     }
197 
198     auto static lookup(T,s : string)() {
199         //if(s in properties) {
200           return get!(s).get!T;
201         //} else return null;
202     }
203 }