Skip to content

Commit 204abb6

Browse files
author
José Valim
committed
Add System.tmp_dir, System.cwd and System.user_home
1 parent 6109768 commit 204abb6

File tree

4 files changed

+117
-23
lines changed

4 files changed

+117
-23
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
* [Mix] `mix escriptize` only generates escript if necessary and accept `--force` and `--no-compile` as options
1818
* [Path] Introduce `Path` module to hold filesystem paths related functions
1919
* [String] Add `String.capitalize` and `String.slice`
20+
* [System] Add `System.tmp_dir`, `System.cwd` and `System.user_home`
2021

2122
* bug fix
2223
* [Kernel] `import` with `only` accepts functions starting with underscore

lib/elixir/lib/path.ex

Lines changed: 4 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
11
defmodule Path do
2-
defexception NoHomeError,
3-
message: "could not find the user home, please set the HOME environment variable"
4-
52
@moduledoc """
63
This module provides conveniences for manipulating or
74
retrieving filesystem paths.
@@ -322,35 +319,19 @@ defmodule Path do
322319

323320
## Helpers
324321

325-
defp get_home do
326-
get_unix_home || get_windows_home || raise NoHomeError
327-
end
328-
329-
defp get_unix_home do
330-
System.get_env("HOME")
331-
end
332-
333-
defp get_windows_home do
334-
System.get_env("USERPROFILE") || (
335-
hd = System.get_env("HOMEDRIVE")
336-
hp = System.get_env("HOMEPATH")
337-
hd && hp && hd <> hp
338-
)
339-
end
340-
341-
defp get_cwd(path) when is_list(path), do: File.cwd! |> binary_to_list
342-
defp get_cwd(_), do: File.cwd!
322+
defp get_cwd(path) when is_list(path), do: System.cwd! |> binary_to_list
323+
defp get_cwd(_), do: System.cwd!
343324

344325
# Normalize the given path by expanding "..", "." and "~".
345326

346327
defp normalize(path), do: do_normalize(FN.split(path))
347328

348329
defp do_normalize(["~"|t]) do
349-
do_normalize t, [get_home]
330+
do_normalize t, [System.user_home!]
350331
end
351332

352333
defp do_normalize(['~'|t]) do
353-
do_normalize t, [get_home |> binary_to_list]
334+
do_normalize t, [System.user_home! |> binary_to_list]
354335
end
355336

356337
defp do_normalize(t) do

lib/elixir/lib/system.ex

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,13 @@
11
defmodule System do
2+
defexception NoHomeError,
3+
message: "could not find the user home, please set the HOME environment variable"
4+
5+
defexception NoTmpDirError,
6+
message: "could not get a writable temporary directory, please set the TMPDIR environment variable"
7+
8+
defexception NoAccessCwdError,
9+
message: "could not get a current working directory, the current location is not accessible"
10+
211
@moduledoc """
312
The System module provides access to some variables used or
413
maintained by the VM and to functions that interact strongly
@@ -44,6 +53,94 @@ defmodule System do
4453
:gen_server.call(:elixir_code_server, :argv)
4554
end
4655

56+
@doc """
57+
Returns the current working directory or nil if one
58+
is not available.
59+
"""
60+
def cwd do
61+
case :file.get_cwd do
62+
{ :ok, list } -> list_to_binary(list)
63+
_ -> nil
64+
end
65+
end
66+
67+
@doc """
68+
Returns the current working directory or raises `System.NoAccessCwdError`.
69+
"""
70+
def cwd! do
71+
cwd || raise NoAccessCwdError
72+
end
73+
74+
@doc """
75+
Returns the user home (platform independent).
76+
It returns nil if no user home is set.
77+
"""
78+
def user_home do
79+
get_unix_home || get_windows_home
80+
end
81+
82+
@doc """
83+
Same as `user_home` but raises `System.NoHomeError`
84+
instead of returning nil if no user home is set.
85+
"""
86+
def user_home! do
87+
user_home || raise NoHomeError
88+
end
89+
90+
defp get_unix_home do
91+
get_env("HOME")
92+
end
93+
94+
defp get_windows_home do
95+
get_env("USERPROFILE") || (
96+
hd = get_env("HOMEDRIVE")
97+
hp = get_env("HOMEPATH")
98+
hd && hp && hd <> hp
99+
)
100+
end
101+
102+
@doc %B"""
103+
Returns a writable temporary directory.
104+
It searches for directories in the following order:
105+
106+
1. The directory named by the TMPDIR environment variable
107+
2. The directory named by the TEMP environment variable
108+
3. The directory named by the TMP environment variable
109+
4. `C:\TMP` on Windows or `/tmp` on Unix
110+
5. As a last resort, the current working directory
111+
112+
Returns nil if none of the above are writable.
113+
"""
114+
def tmp_dir do
115+
write_env_tmp_dir('TMPDIR') ||
116+
write_env_tmp_dir('TEMP') ||
117+
write_env_tmp_dir('TMP') ||
118+
write_tmp_dir("/tmp") ||
119+
((cwd = cwd()) && write_tmp_dir(cwd))
120+
end
121+
122+
@doc """
123+
Same as `tmp_dir` but raises `System.NoTmpDirError`
124+
instead of returning nil if no temp dir is set.
125+
"""
126+
def tmp_dir! do
127+
tmp_dir || raise NoTmpDirError
128+
end
129+
130+
defp write_env_tmp_dir(env) do
131+
case System.get_env(env) do
132+
nil -> nil
133+
tmp -> write_tmp_dir tmp
134+
end
135+
end
136+
137+
defp write_tmp_dir(dir) do
138+
case File.stat(dir) do
139+
{ :ok, File.Stat[type: :directory, access: access] } when access in [:read_write, :write] -> dir
140+
{ :error, _ } -> nil
141+
end
142+
end
143+
47144
@doc """
48145
Registers a function that will be invoked
49146
at the end of program execution. Useful for

lib/elixir/test/elixir/system_test.exs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,21 @@ defmodule SystemTest do
1212
assert not nil?(System.build_info[:date])
1313
end
1414

15+
test :cwd do
16+
assert is_binary System.cwd
17+
assert is_binary System.cwd!
18+
end
19+
20+
test :user_home do
21+
assert is_binary System.user_home
22+
assert is_binary System.user_home!
23+
end
24+
25+
test :tmp_dir do
26+
assert is_binary System.tmp_dir
27+
assert is_binary System.tmp_dir!
28+
end
29+
1530
test :argv do
1631
list = elixir('-e "IO.inspect System.argv" -- -o opt arg1 arg2 --long-opt 10')
1732
{ args, _ } = Code.eval list, []

0 commit comments

Comments
 (0)