1 /// Utility functions to work with paths
2 module thepath.utils;
3 
4 private import std.exception: enforce;
5 private static import std.path;
6 
7 private import thepath.exception: PathException;
8 private import thepath.path: Path;
9 
10 
11 /** Create temporary directory
12   * Note, that caller is responsible to remove created directory.
13   * The temp directory will be created inside specified path.
14   * 
15   * Params:
16   *     path = path to already existing directory to create
17   *         temp directory inside. Default: std.file.tempDir
18   *     prefix = prefix to be used in name of temp directory. Default: "tmp"
19   * Returns: string, representing path to created temporary directory
20   * Throws: PathException in case of error
21   **/
22 string createTempDirectory(in string prefix="tmp") {
23     import std.file : tempDir;
24     return createTempDirectory(tempDir, prefix);
25 }
26 
27 /// ditto
28 string createTempDirectory(in string path, in string prefix) {
29     version(Posix) {
30         import std.string : fromStringz;
31         import std.conv: to;
32         import core.sys.posix.stdlib : mkdtemp;
33 
34         // Prepare template for mkdtemp function.
35         // It have to be mutable array of chars ended with zero to be compatibale
36         // with mkdtemp function.
37         scope char[] tempname_str = std.path.buildNormalizedPath(
38             std.path.expandTilde(path),
39             prefix ~ "-XXXXXX").dup ~ "\0";
40 
41         // mkdtemp will modify tempname_str directly. and res is pointer to
42         // tempname_str in case of success.
43         char* res = mkdtemp(tempname_str.ptr);
44         enforce!PathException(
45             res !is null, "Cannot create temporary directory");
46 
47         // Converting to string will duplicate result.
48         // But may be it have sense to do it in more obvious way
49         // for example: return tempname_str[0..$-1].idup;
50         return to!string(res.fromStringz);
51     } else {
52         import std.ascii: letters;
53         import std.random: uniform;
54 
55         // Generate new random temp path to test using provided path and prefix
56         // as template.
57         string generate_temp_dir() {
58             string suffix = "-";
59             for(ubyte i; i<6; i++) suffix ~= letters[uniform(0, $)];
60             return std.path.buildNormalizedPath(
61                 std.path.expandTilde(path), prefix ~ suffix);
62         }
63 
64         string temp_dir = generate_temp_dir();
65         while (std.file.exists(temp_dir)) {
66             temp_dir = generate_temp_dir();
67         }
68         std.file.mkdir(temp_dir);
69         return temp_dir;
70     }
71 }
72 
73 
74 /** Create temporary directory
75   * Note, that caller is responsible to remove created directory.
76   * The temp directory will be created inside specified path.
77   *
78   * Params:
79   *     path = path to already existing directory to create
80   *         temp directory inside. Default: std.file.tempDir
81   *     prefix = prefix to be used in name of temp directory. Default: "tmp"
82   * Returns: Path to created temp directory
83   * Throws: PathException in case of error
84   **/
85 Path createTempPath(in string prefix="tmp") {
86     return Path(createTempDirectory(prefix));
87 }
88 
89 /// ditto
90 Path createTempPath(in string path, in string prefix) {
91     return Path(createTempDirectory(path, prefix));
92 }
93 
94 /// ditto
95 Path createTempPath(in Path path, in string prefix) {
96     return createTempPath(path.toString, prefix);
97 }
98 
99