1 /**
2  * ae.utils.path
3  *
4  * License:
5  *   This Source Code Form is subject to the terms of
6  *   the Mozilla Public License, v. 2.0. If a copy of
7  *   the MPL was not distributed with this file, You
8  *   can obtain one at http://mozilla.org/MPL/2.0/.
9  *
10  * Authors:
11  *   Vladimir Panteleev <vladimir@thecybershadow.net>
12  */
13 
14 module ae.utils.path;
15 
16 import std.path;
17 
18 /// Modify a path under oldBase to a new path with the same subpath under newBase.
19 /// E.g.: `/foo/bar`.rebasePath(`/foo`, `/quux`) == `/quux/bar`
20 string rebasePath(string path, string oldBase, string newBase)
21 {
22 	return buildPath(newBase, path.absolutePath.relativePath(oldBase.absolutePath));
23 }
24 
25 /// Like Pascal's IncludeTrailingPathDelimiter
26 string includeTrailingPathSeparator(string path)
27 {
28 	if (path.length && !path[$-1].isDirSeparator())
29 		path ~= dirSeparator;
30 	return path;
31 }
32 
33 /// Like Pascal's ExcludeTrailingPathDelimiter
34 string excludeTrailingPathSeparator(string path)
35 {
36 	if (path.length && path[$-1].isDirSeparator())
37 		path = path[0..$-1];
38 	return path;
39 }
40 
41 // ************************************************************************
42 
43 import std.process : environment;
44 import std.string : split;
45 
46 @property string[] pathDirs()
47 {
48 	return environment["PATH"].split(pathSeparator);
49 }
50 
51 bool haveExecutable(string name)
52 {
53 	return findExecutable(name, pathDirs) !is null;
54 }
55 
56 /// Find an executable with the given name
57 /// (no extension) in the given directories.
58 /// Returns null if not found.
59 string findExecutable(string name, string[] dirs)
60 {
61 	import std.file : exists;
62 
63 	version (Windows)
64 		enum executableSuffixes = [".exe", ".bat", ".cmd"];
65 	else
66 		enum executableSuffixes = [""];
67 
68 	foreach (dir; dirs)
69 		foreach (suffix; executableSuffixes)
70 		{
71 			auto fn = buildPath(dir, name) ~ suffix;
72 			if (fn.exists)
73 				return fn;
74 		}
75 
76 	return null;
77 }
78 
79 
80 // ************************************************************************
81 
82 /// The file name for the null device
83 /// (which discards all writes).
84 version (Windows)
85 	enum nullFileName = "nul";
86 else
87 	enum nullFileName = "/dev/null";