Packages
igniter
0.5.38
0.8.2
0.8.1
0.8.0
0.7.9
0.7.8
0.7.7
0.7.6
0.7.5
0.7.4
0.7.3
0.7.2
0.7.1
0.7.0
0.6.30
0.6.29
0.6.28
0.6.27
0.6.26
0.6.25
0.6.24
0.6.23
0.6.22
0.6.21
0.6.20
0.6.19
0.6.18
0.6.17
0.6.16
0.6.15
0.6.14
0.6.13
0.6.12
0.6.11
0.6.10
0.6.9
0.6.8
0.6.7
0.6.6
0.6.5
0.6.4
0.6.3
0.6.2
0.6.1
0.6.0
0.5.52
0.5.51
0.5.50
0.5.49
0.5.48
0.5.47
0.5.46
0.5.45
0.5.44
0.5.43
0.5.42
0.5.41
0.5.40
0.5.39
0.5.38
0.5.37
0.5.36
0.5.35
0.5.34
0.5.33
0.5.32
0.5.31
0.5.30
0.5.29
0.5.28
0.5.27
0.5.26
0.5.25
0.5.24
0.5.23
0.5.22
0.5.21
0.5.20
0.5.19
0.5.18
0.5.17
0.5.16
0.5.15
0.5.14
0.5.13
0.5.12
0.5.11
0.5.10
0.5.9
0.5.8
0.5.7
0.5.6
0.5.5
0.5.4
0.5.3
0.5.2
0.5.1
0.5.0
0.4.8
0.4.7
0.4.6
0.4.5
0.4.4
0.4.3
0.4.2
0.4.1
0.4.0
0.3.78
0.3.77
0.3.76
0.3.75
0.3.74
0.3.73
0.3.72
0.3.71
0.3.70
0.3.69
0.3.68
0.3.67
0.3.66
0.3.65
0.3.64
0.3.63
0.3.62
0.3.61
0.3.60
0.3.59
0.3.58
0.3.57
0.3.56
0.3.55
0.3.54
0.3.53
0.3.52
0.3.51
0.3.50
0.3.49
0.3.48
0.3.47
0.3.46
0.3.45
0.3.44
0.3.43
0.3.42
0.3.41
0.3.40
0.3.39
0.3.38
0.3.37
0.3.36
0.3.35
0.3.34
0.3.33
0.3.32
0.3.31
0.3.30
0.3.29
0.3.28
0.3.27
0.3.26
0.3.25
0.3.24
0.3.23
0.3.22
0.3.21
0.3.20
0.3.19
0.3.18
0.3.17
0.3.16
0.3.15
0.3.14
0.3.13
0.3.12
0.3.11
0.3.10
0.3.9
0.3.8
0.3.7
0.3.6
0.3.5
0.3.4
0.3.3
0.3.2
0.3.1
0.3.0
0.2.13
0.2.12
0.2.11
0.2.10
0.2.9
0.2.8
0.2.7
0.2.6
0.2.5
0.2.4
0.2.3
0.2.2
0.2.1
0.2.0
0.1.8
0.1.7
0.1.6
0.1.5
0.1.4
0.1.3
0.1.2
0.1.1
0.1.0
A code generation and project patching framework
Current section
Files
Jump to
Current section
Files
lib/igniter/util/backward_compat.ex
defmodule Igniter.Util.BackwardsCompat do
@moduledoc "Contains functions that we need to use that were introduced in newer Elixir versions."
if Version.match?(System.version(), ">= 1.16.0") do
defdelegate relative_to_cwd(path, opts \\ []), to: Path
else
@doc """
Convenience to get the path relative to the current working
directory.
If, for some reason, the current working directory
cannot be retrieved, this function returns the given `path`.
Check `relative_to/3` for the supported options.
"""
@spec relative_to_cwd(Path.t(), keyword) :: binary
def relative_to_cwd(path, opts \\ []) when is_list(opts) do
case :file.get_cwd() do
{:ok, base} -> relative_to(path, IO.chardata_to_string(base), opts)
_ -> path
end
end
@doc """
Returns the direct relative path from `path` in relation to `cwd`.
In other words, this function attempts to return a path such that
`Path.expand(result, cwd)` points to `path`. This function aims
to return a relative path whenever possible, but that's not guaranteed:
* If both paths are relative, a relative path is always returned
* If both paths are absolute, a relative path may be returned if
they share a common prefix. You can pass the `:force` option to
force this function to traverse up, but even then a relative
path is not guaranteed (for example, if the absolute paths
belong to different drives on Windows)
* If a mixture of paths are given, the result will always match
the given `path` (the first argument)
This function expands `.` and `..` entries without traversing the
file system, so it assumes no symlinks between the paths. See
`safe_relative_to/2` for a safer alternative.
## Options
* `:force` - (boolean since v1.16.0) if `true` forces a relative
path to be returned by traversing the path up. Except if the paths
are in different volumes on Windows. Defaults to `false`.
## Examples
### With relative `cwd`
If both paths are relative, a minimum path is computed:
Path.relative_to("tmp/foo/bar", "tmp") #=> "foo/bar"
Path.relative_to("tmp/foo/bar", "tmp/foo") #=> "bar"
Path.relative_to("tmp/foo/bar", "tmp/bat") #=> "../foo/bar"
If an absolute path is given with relative `cwd`, it is returned as:
Path.relative_to("/usr/foo/bar", "tmp/bat") #=> "/usr/foo/bar"
### With absolute `cwd`
If both paths are absolute, a relative is computed if possible,
without traversing up:
Path.relative_to("/usr/local/foo", "/usr/local") #=> "foo"
Path.relative_to("/usr/local/foo", "/") #=> "usr/local/foo"
Path.relative_to("/usr/local/foo", "/etc") #=> "/usr/local/foo"
Path.relative_to("/usr/local/foo", "/usr/local/foo") #=> "."
Path.relative_to("/usr/local/../foo", "/usr/foo") #=> "."
Path.relative_to("/usr/local/../foo/bar", "/usr/foo") #=> "bar"
If `:force` is set to `true` paths are traversed up:
Path.relative_to("/usr", "/usr/local", force: true) #=> ".."
Path.relative_to("/usr/foo", "/usr/local", force: true) #=> "../foo"
Path.relative_to("/usr/../foo/bar", "/etc/foo", force: true) #=> "../../foo/bar"
If a relative path is given, it is assumed to be relative to the
given path, so the path is returned with "." and ".." expanded:
Path.relative_to(".", "/usr/local") #=> "."
Path.relative_to("foo", "/usr/local") #=> "foo"
Path.relative_to("foo/../bar", "/usr/local") #=> "bar"
Path.relative_to("foo/..", "/usr/local") #=> "."
Path.relative_to("../foo", "/usr/local") #=> "../foo"
"""
@spec relative_to(Path.t(), Path.t(), keyword) :: binary
def relative_to(path, cwd, opts \\ []) when is_list(opts) do
os_type = major_os_type()
split_path = Path.split(path)
split_cwd = Path.split(cwd)
force = Keyword.get(opts, :force, false)
case {split_absolute?(split_path, os_type), split_absolute?(split_cwd, os_type)} do
{true, true} ->
split_path = expand_split(split_path)
split_cwd = expand_split(split_cwd)
case force do
true -> relative_to_forced(split_path, split_cwd, split_path)
false -> relative_to_unforced(split_path, split_cwd, split_path)
end
{false, false} ->
split_path = expand_relative(split_path, [], [])
split_cwd = expand_relative(split_cwd, [], [])
relative_to_forced(split_path, split_cwd, [])
{_, _} ->
Path.join(expand_relative(split_path, [], []))
end
end
defp expand_relative([".." | t], [_ | acc], up), do: expand_relative(t, acc, up)
defp expand_relative([".." | t], acc, up), do: expand_relative(t, acc, [".." | up])
defp expand_relative(["." | t], acc, up), do: expand_relative(t, acc, up)
defp expand_relative([h | t], acc, up), do: expand_relative(t, [h | acc], up)
defp expand_relative([], [], []), do: ["."]
defp expand_relative([], acc, up), do: up ++ :lists.reverse(acc)
defp expand_split([head | tail]), do: expand_split(tail, [head])
defp expand_split([".." | t], [_, last | acc]), do: expand_split(t, [last | acc])
defp expand_split([".." | t], acc), do: expand_split(t, acc)
defp expand_split(["." | t], acc), do: expand_split(t, acc)
defp expand_split([h | t], acc), do: expand_split(t, [h | acc])
defp expand_split([], acc), do: :lists.reverse(acc)
defp split_absolute?(split, :win32), do: win32_split_absolute?(split)
defp split_absolute?(split, _), do: match?(["/" | _], split)
defp win32_split_absolute?(["//" | _]), do: true
defp win32_split_absolute?([<<_, ":/">> | _]), do: true
defp win32_split_absolute?(_), do: false
defp relative_to_unforced(path, path, _original), do: "."
defp relative_to_unforced([h | t1], [h | t2], original),
do: relative_to_unforced(t1, t2, original)
defp relative_to_unforced([_ | _] = l1, [], _original), do: Path.join(l1)
defp relative_to_unforced(_, _, original), do: Path.join(original)
defp relative_to_forced(path, path, _original), do: "."
defp relative_to_forced(["."], _path, _original), do: "."
defp relative_to_forced(path, ["."], _original), do: Path.join(path)
defp relative_to_forced([h | t1], [h | t2], original),
do: relative_to_forced(t1, t2, original)
# this should only happen if we have two paths on different drives on windows
defp relative_to_forced(original, _, original), do: Path.join(original)
defp relative_to_forced(l1, l2, _original) do
base = List.duplicate("..", length(l2))
Path.join(base ++ l1)
end
defp major_os_type do
:os.type() |> elem(0)
end
end
end