v2 / vlib / io / util / util.v
85 lines · 76 sloc · 2.5 KB · fa2383a0b7c868bed1293545045514626fd7d4ea
Raw
1module util
2
3import os
4import rand
5
6const retries = 10000
7
8@[params]
9pub struct TempFileOptions {
10pub:
11 path string = os.temp_dir()
12 pattern string
13}
14
15// temp_file returns a uniquely named, open, writable, `os.File` and it's path.
16pub fn temp_file(tfo TempFileOptions) !(os.File, string) {
17 mut d := tfo.path
18 if d == '' {
19 d = os.temp_dir()
20 }
21 os.ensure_folder_is_writable(d) or {
22 return error(@FN +
23 ' could not create temporary file in "${d}". Please ensure write permissions.')
24 }
25 d = d.trim_right(os.path_separator)
26 prefix, suffix := prefix_and_suffix(tfo.pattern) or { return error(@FN + ' ${err.msg()}') }
27 for retry := 0; retry < retries; retry++ {
28 path := os.join_path(d, prefix + random_number() + suffix)
29 mut mode := 'rw+'
30 $if windows {
31 mode = 'w+'
32 }
33 mut file := os.open_file(path, mode, 0o600) or { continue }
34 if os.exists(path) && os.is_file(path) {
35 return file, path
36 }
37 }
38 return error(@FN +
39 ' could not create temporary file in "${d}". Retry limit (${retries}) exhausted. Please ensure write permissions.')
40}
41
42@[params]
43pub struct TempDirOptions {
44pub:
45 path string = os.temp_dir()
46 pattern string
47}
48
49fn error_for_temporary_folder(fn_name string, d string) !string {
50 return error('${fn_name} could not create temporary directory "${d}". Please ensure you have write permissions for it.')
51}
52
53// temp_dir returns a uniquely named, writable, directory path.
54pub fn temp_dir(tdo TempDirOptions) !string {
55 mut d := tdo.path
56 if d == '' {
57 d = os.temp_dir()
58 }
59 os.ensure_folder_is_writable(d) or { return error_for_temporary_folder(@FN, d) }
60 d = d.trim_right(os.path_separator)
61 prefix, suffix := prefix_and_suffix(tdo.pattern) or { return error(@FN + ' ${err.msg()}') }
62 for retry := 0; retry < retries; retry++ {
63 path := os.join_path(d, prefix + random_number() + suffix)
64 os.mkdir_all(path) or { continue }
65 if os.is_dir(path) && os.exists(path) {
66 os.ensure_folder_is_writable(path) or { return error_for_temporary_folder(@FN, d) }
67 return path
68 }
69 }
70 return error('${@FN} could not create temporary directory "${d}". Retry limit (${retries}) exhausted.')
71}
72
73// * Utility functions
74fn random_number() string {
75 s := (1_000_000_000 + (u32(os.getpid()) + rand.u32n(1_000_000_000) or { 0 })).str()
76 return s.substr(1, s.len)
77}
78
79fn prefix_and_suffix(pattern string) !(string, string) {
80 if pattern.contains(os.path_separator) {
81 return error('pattern cannot contain path separators (${os.path_separator}).')
82 }
83 prefix, suffix := pattern.rsplit_once('*') or { pattern, '' }
84 return prefix, suffix
85}
86