livebook/lib/livebook_cli.ex
2025-07-24 17:26:15 -03:00

93 lines
2.7 KiB
Elixir

defmodule LivebookCLI do
alias LivebookCLI.{Task, Utils}
@help_args ["--help", "-h"]
@version_args ["--version", "-v"]
def usage,
do: """
Usage: livebook [command] [options]
Available commands:
livebook server Starts the Livebook web application
livebook deploy Deploys a notebook to Livebook Teams
The --help and --version options can be given instead of a command for usage and versioning information.\
"""
def main(args) do
{:ok, _} = Application.ensure_all_started(:elixir)
extract_priv!()
:ok = Application.load(:livebook)
if unix?() do
Application.put_env(:elixir, :ansi_enabled, true)
end
case args do
[arg] when arg in @help_args -> display_help()
[arg] when arg in @version_args -> display_version()
[name, arg] when arg in @help_args -> Task.usage(name)
[name | args] -> Task.call(name, List.delete(args, name))
_args -> Utils.log_info(usage())
end
end
defp unix?(), do: match?({:unix, _}, :os.type())
defp display_help() do
Utils.log_info("""
Livebook is an interactive notebook system for Elixir
#{usage()}\
""")
end
defp display_version() do
Utils.log_info("""
#{:erlang.system_info(:system_version)}
Elixir #{System.build_info()[:build]}
Livebook #{Livebook.Config.app_version()}\
""")
end
import Record
defrecord(:zip_file, extract(:zip_file, from_lib: "stdlib/include/zip.hrl"))
defp extract_priv!() do
archive_dir = Path.join(Livebook.Config.tmp_path(), "escript")
extracted_path = Path.join(archive_dir, "extracted")
in_archive_priv_path = ~c"livebook/priv"
# In dev we want to extract fresh directory on every boot
if Livebook.Config.app_version() =~ "-dev" do
File.rm_rf!(archive_dir)
end
# When temporary directory is cleaned by the OS, the directories
# may be left in place, so we use a regular file (extracted) to
# check if the extracted archive is already available
if not File.exists?(extracted_path) do
{:ok, sections} = :escript.extract(:escript.script_name(), [])
archive = Keyword.fetch!(sections, :archive)
file_filter = fn zip_file(name: name) ->
List.starts_with?(name, in_archive_priv_path)
end
opts = [cwd: String.to_charlist(archive_dir), file_filter: file_filter]
with {:error, error} <- :zip.extract(archive, opts) do
raise "Livebook failed to extract archive files, reason: #{inspect(error)}"
end
File.touch!(extracted_path)
end
priv_dir = Path.join(archive_dir, in_archive_priv_path)
Application.put_env(:livebook, :priv_dir, priv_dir, persistent: true)
end
end