Skip to content

Commit

Permalink
VIP - Completing the installer function without testing
Browse files Browse the repository at this point in the history
delete some functions to clear the code, maybe I will add them again
  • Loading branch information
shahryarjb committed Jun 26, 2024
1 parent 321229c commit 5020a91
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 13 deletions.
28 changes: 25 additions & 3 deletions lib/installer/installer.ex
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ defmodule MishkaInstaller.Installer.Installer do
:ok <- allowed_extract_path(data.path),
ext_path <- LibraryHandler.extensions_path(),
:ok <- rename_dir(data.path, "#{ext_path}/#{app.app}-#{app.version}"),
:ok <- LibraryHandler.do_compile(data) do
:ok <- install_and_compile_steps(data) do
{:ok, %{download: nil, extensions: data, dir: "#{ext_path}/#{app.app}-#{app.version}"}}
end
after
Expand All @@ -95,7 +95,7 @@ defmodule MishkaInstaller.Installer.Installer do
{:ok, path} <- LibraryHandler.move(app, archived_file),
:ok <- LibraryHandler.extract(:tar, path, "#{app.app}-#{app.version}"),
ext_path <- LibraryHandler.extensions_path(),
:ok <- LibraryHandler.do_compile(data) do
:ok <- install_and_compile_steps(data) do
{:ok, %{download: path, extensions: data, dir: "#{ext_path}/#{app.app}-#{app.version}"}}
end

Expand All @@ -110,7 +110,19 @@ defmodule MishkaInstaller.Installer.Installer do
def update() do
end

def uninstall(%__MODULE__{} = _app) do
def uninstall(app) do
Application.stop(app.app)
Application.unload(app.app)
info = MishkaInstaller.__information__()
File.rm_rf!("#{info.path}/_build/#{info.env}/lib/#{app.app}")
:ok
end

def uninstall(app, custom_path) do
Application.stop(app)
Application.unload(app)
File.rm_rf!(custom_path)
:ok
end

####################################################################################
Expand Down Expand Up @@ -286,4 +298,14 @@ defmodule MishkaInstaller.Installer.Installer do
{:error, [%{message: message, field: :path, action: :rename_dir, allowed: allowed}]}
end
end

defp install_and_compile_steps(data) do
with :ok <- LibraryHandler.do_compile(data),
{:ok, moved_files} <- LibraryHandler.move_and_replace_build_files(data),
:ok <- LibraryHandler.prepend_compiled_apps(moved_files),
:ok <- LibraryHandler.unload(String.to_atom(data.app)),
:ok <- LibraryHandler.application_ensure(String.to_atom(data.app)) do
:ok
end
end
end
103 changes: 93 additions & 10 deletions lib/installer/library_handler.ex
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,20 @@ defmodule MishkaInstaller.Installer.LibraryHandler do
####################################################################################
######################### (▰˘◡˘▰) Functions (▰˘◡˘▰) ##########################
####################################################################################
@spec compare_dependencies([String.t()]) :: [String.t()]
def compare_dependencies(files_list) do
installed_apps =
Application.loaded_applications()
|> Map.new(fn {app, _des, _ver} = item -> {Atom.to_string(app), item} end)

Enum.reduce(files_list, [], fn app_name, acc ->
if Map.fetch(installed_apps, app_name) == :error, do: acc ++ [app_name], else: acc
end)
def prepend_compiled_apps(files_list) do
prepend =
Enum.reduce(files_list, [], fn {app_name, path}, acc ->
if Code.prepend_path(path), do: acc, else: acc ++ [{app_name, path}]
end)

if prepend == [] do
:ok
else
message = "Some routes cannot be prepended."

{:error,
[%{message: message, field: :path, action: :prepend_compiled_apps, source: prepend}]}
end
end

def get_basic_information_from_mix_ast(ast, selection, extra \\ []) do
Expand Down Expand Up @@ -123,7 +128,7 @@ defmodule MishkaInstaller.Installer.LibraryHandler do
end
end

@spec move(Installer.t(), binary()) :: okey_return() | error_return()
@spec move(Installer.t(), binary() | Path.t()) :: okey_return() | error_return()
def move(app, archived_file) do
with {:mkdir_p, :ok} <- {:mkdir_p, File.mkdir_p(extensions_path())},
{:ok, path} <- write_downloaded_lib(app, archived_file) do
Expand All @@ -138,6 +143,35 @@ defmodule MishkaInstaller.Installer.LibraryHandler do
end
end

# 1. delete and unload old app
# 2. move new app
# 3. return list of moved apps
def move_and_replace_build_files(app) do
path = extensions_path()
info = MishkaInstaller.__information__()
build_path = "#{path}/#{app.app}-#{app.version}/_build/#{info.env}/lib"

moved_files =
File.ls!(build_path)
|> Enum.reduce([], fn sub_app, acc ->
with app_build <- "#{build_path}/#{sub_app}/ebin/#{sub_app}.app",
{:ok, properties} <- read_app(String.to_atom(sub_app), app_build),
:ok <- compare_version_with_installed_app(String.to_atom(sub_app), properties[:vsn]),
sub_path <- "#{info.path}/_build/#{info.env}/lib/#{sub_app}",
:ok <- Installer.uninstall(String.to_atom(sub_app), sub_path) do
File.cp_r("#{build_path}/#{sub_app}", "#{info.path}/_build/#{info.env}/lib")
acc ++ [{String.to_atom(sub_app), "#{build_path}/#{sub_app}"}]
end
end)

if length(moved_files) > 0 do
{:ok, moved_files}
else
message = "There is no app to be replicated in the requested path."
{:error, [%{message: message, field: :app, action: :move_and_replace_build_files}]}
end
end

# Ref: https://hexdocs.pm/elixir/Port.html#module-spawn_executable
# Ref: https://elixirforum.com/t/48336/
@spec command_execution(:cmd | :port, String.t(), String.t()) :: :ok | error_return()
Expand Down Expand Up @@ -238,6 +272,37 @@ defmodule MishkaInstaller.Installer.LibraryHandler do
end
end

def application_ensure(app_name) do
with {:load, :ok} <- {:load, Application.load(app_name)},
{:all, {:ok, _apps}} <- {:all, Application.ensure_all_started(app_name)} do
:ok
else
{:load, error} ->
message = "There was an error loading the application you are looking for."
{:error, [%{message: message, field: :app, action: :application_ensure, source: error}]}

{:all, {:error, error}} ->
message =
"An error occurred in loading the application in the sub-set and related to the application you sent."

{:error, [%{message: message, field: :app, action: :application_ensure, source: error}]}
end
end

def unload(app) do
case Application.unload(app) do
{:error, {:not_loaded, ^app}} ->
:ok

{:error, error} ->
message = "An error occurred in deactivating the app."
{:error, [%{message: message, field: :app, action: :unload, source: error}]}

_ ->
:ok
end
end

####################################################################################
########################## (▰˘◡˘▰) Callback (▰˘◡˘▰) ##########################
####################################################################################
Expand Down Expand Up @@ -339,4 +404,22 @@ defmodule MishkaInstaller.Installer.LibraryHandler do
return_exist
end
end

defp compare_version_with_installed_app(app, version) do
ver = Application.spec(app, :vsn)

cond do
is_nil(ver) ->
:ok

Version.compare("#{version}", "#{ver}") == :gt ->
:ok

true ->
message =
"In the path of installed apps, there is an app of the same name with the same or higher version."

{:error, [%{message: message, field: :app, action: :compare_version_with_installed_app}]}
end
end
end

0 comments on commit 5020a91

Please sign in to comment.