1 /**
2  * This file is part of DCD, a development tool for the D programming language.
3  * Copyright (C) 2014 Brian Schott
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 module dcd.server.server;
20 
21 import std.algorithm;
22 import std.array;
23 import std.experimental.logger;
24 import std.file;
25 import std.path;
26 import std.process: environment;
27 import std.stdio: File;
28 import std.stdio: KeepTerminator;
29 
30 import dsymbol.modulecache;
31 
32 /// Name of the server configuration file
33 enum CONFIG_FILE_NAME = "dcd.conf";
34 
35 version(linux) version = useXDG;
36 version(BSD) version = useXDG;
37 version(FreeBSD) version = useXDG;
38 version(OSX) version = useXDG;
39 
40 /**
41  * Locates the configuration file
42  */
43 string getConfigurationLocation()
44 {
45 	version (useXDG)
46 	{
47 		string configDir = environment.get("XDG_CONFIG_HOME", null);
48 		if (configDir is null)
49 		{
50 			configDir = environment.get("HOME", null);
51 			if (configDir !is null)
52 				configDir = buildPath(configDir, ".config", "dcd", CONFIG_FILE_NAME);
53 			if (!exists(configDir))
54 				configDir = buildPath("/etc/", CONFIG_FILE_NAME);
55 		}
56 		else
57 		{
58 			configDir = buildPath(configDir, "dcd", CONFIG_FILE_NAME);
59 		}
60 		return configDir;
61 	}
62 	else version(Windows)
63 	{
64 		return CONFIG_FILE_NAME;
65 	}
66 }
67 
68 import std.regex : ctRegex;
69 alias envVarRegex = ctRegex!(`\$\{([_a-zA-Z][_a-zA-Z 0-9]*)\}`);
70 
71 private unittest
72 {
73 	import std.regex : replaceAll;
74 
75 	enum input = `${HOME}/aaa/${_bb_b}/ccc`;
76 
77 	assert(replaceAll!(m => m[1])(input, envVarRegex) == `HOME/aaa/_bb_b/ccc`);
78 }
79 
80 /**
81  * Loads import directories from the configuration file
82  */
83 string[] loadConfiguredImportDirs()
84 {
85 	string expandEnvVars(string l)
86 	{
87 		import std.regex : replaceAll;
88 		return replaceAll!(m => environment.get(m[1], ""))(l, envVarRegex);
89 	}
90 
91 	immutable string configLocation = getConfigurationLocation();
92 	if (!configLocation.exists())
93 		return [];
94 	info("Loading configuration from ", configLocation);
95 	File f = File(configLocation, "rt");
96 	return f.byLine(KeepTerminator.no)
97 		.filter!(a => a.length > 0 && a[0] != '#')
98 		.map!(a => a.idup)
99 		.map!(expandEnvVars)
100 		.filter!(a => existanceCheck(a))
101 		.array();
102 }