Current section
Files
Jump to
Current section
Files
core/util/path.ex
# Copyright(c) 2015-2018 ACCESS CO., LTD. All rights reserved.
use Croma
defmodule AntikytheraCore.Path do
alias Antikythera.{Env, GearName, TenantId, SecondsSinceEpoch}
#
# paths under antikythera root directory
#
if Env.compiling_for_cloud?() do
# Use compile-time application config
@antikythera_root_dir Application.fetch_env!(:antikythera, :antikythera_root_dir)
defun antikythera_root_dir() :: Path.t, do: @antikythera_root_dir
defun compiled_core_dir() :: Path.t, do: Path.join(antikythera_root_dir(), "releases")
else
# Use runtime application config
defun antikythera_root_dir() :: Path.t, do: Application.fetch_env!(:antikythera, :antikythera_root_dir)
defun compiled_core_dir() :: Path.t do
parent_dir = Path.join([__DIR__, "..", "..", ".."]) |> Path.expand()
release_generating_project_dir =
case Path.basename(parent_dir) do
"deps" -> Path.join([parent_dir, ".."]) # from antikythera instance or gear projects
_ -> Path.join([__DIR__, "..", ".."]) # as a standalone project
end
|> Path.expand()
Path.join([release_generating_project_dir, "rel_local_erlang-#{:erlang.system_info(:otp_release)}", "#{Env.antikythera_instance_name()}", "releases"])
end
end
defun core_config_file_path() :: Path.t, do: Path.join([antikythera_root_dir(), "config", "antikythera"])
defun gear_config_dir() :: Path.t, do: Path.join(antikythera_root_dir(), "gear_config")
defun history_dir() :: Path.t, do: Path.join(antikythera_root_dir(), "history")
defun compiled_gears_dir() :: Path.t, do: Path.join(antikythera_root_dir(), "compiled_gears_erlang-#{:erlang.system_info(:otp_release)}")
defunp tenant_dir() :: Path.t, do: Path.join(antikythera_root_dir(), "tenant")
defun tenant_ids_file_path() :: Path.t, do: Path.join(tenant_dir(), "ids.gz")
defun tenant_setting_dir() :: Path.t, do: Path.join(tenant_dir(), "setting")
defun tenant_setting_file_path(id :: v[TenantId.t]) :: Path.t, do: Path.join(tenant_setting_dir(), id)
defun gear_config_file_path(gear_name :: v[GearName.t]) :: Path.t do
Path.join(gear_config_dir(), Atom.to_string(gear_name))
end
#
# paths under unpacked release directory
#
defun gear_log_dir(gear_name :: v[GearName.t]) :: Path.t do
Path.join([Application.app_dir(:antikythera), "..", "..", "log", Atom.to_string(gear_name)]) |> Path.expand()
end
defun gear_log_file_path(gear_name :: v[GearName.t]) :: Path.t do
Path.join(gear_log_dir(gear_name), "#{gear_name}.log.gz")
end
#
# paths under "secret" directory in each node
#
defunp secret_dir() :: Path.t do
if Env.running_in_cloud?() do
# At runtime `:code.root_dir/0` returns the unpacked "release" directory; "secret" is placed next to "release"
Path.join([:code.root_dir(), "..", "secret"]) |> Path.expand()
else
case System.get_env("ANTIKYTHERA_SECRET_DIR") do
nil -> Path.join([antikythera_root_dir(), "..", "secret"]) |> Path.expand()
dir -> dir
end
end
end
defun config_encryption_key_path() :: Path.t do
Path.join(secret_dir(), "config_encryption_key")
end
defun system_info_access_token_path() :: Path.t do
Path.join(secret_dir(), "system_info_access_token")
end
#
# path for Antikythera.Tmpdir
#
defun gear_tmp_dir() :: Path.t do
# This must be fetched at runtime at least in non-cloud environment in order to use
# path with the current OS pid, not with the OS pid of `$ mix compile` command.
Application.fetch_env!(:antikythera, :gear_tmp_dir)
end
#
# path for RaftedValue & RaftFleet
#
defun raft_persistence_dir_parent() :: Path.t do
# This must be fetched at runtime at least in non-cloud environment in order to use
# path with the current OS pid, not with the OS pid of `$ mix compile` command.
Application.fetch_env!(:antikythera, :raft_persistence_dir_parent)
end
#
# utilities
#
@file_modification_time_margin_in_seconds (if Env.compiling_for_cloud?(), do: 2, else: 0)
defun list_modified_files(dir :: Path.t, since :: v[SecondsSinceEpoch.t]) :: [String.t] do
# In order not to miss file changes (due to clock skew and/or NFS delay),
# we make margin by shifting `since` by a few seconds
since_with_margin = max(0, since - @file_modification_time_margin_in_seconds)
Path.wildcard(Path.join(dir, "*"))
|> Enum.filter(fn path -> modified_regular_file?(path, since_with_margin) end)
|> Enum.sort()
end
defunp modified_regular_file?(path :: Path.t, since :: v[SecondsSinceEpoch.t]) :: boolean do
case File.stat(path, [time: :posix]) do
{:ok, %File.Stat{type: :regular, mtime: t}} when t >= since -> true
{:ok, _unchanged_or_not_regular} -> false
{:error, :enoent} -> false # removed between `Path.wildcard/1` and `File.stat/2`
end
end
end