Packages
livebook
0.15.2
0.19.8
0.19.7
0.19.6
0.19.5
0.19.4
0.19.3
0.19.2
0.19.1
0.19.0
0.18.6
0.18.5
0.18.4
0.18.3
0.18.2
0.18.1
0.18.0
0.17.3
0.17.2
0.17.1
0.17.0
0.16.4
0.16.3
0.16.2
0.16.1
0.16.0
0.15.5
0.15.4
0.15.3
0.15.2
0.15.1
0.15.0
0.14.7
0.14.6
0.14.5
0.14.4
0.14.3
0.14.2
0.14.1
0.14.0
0.14.0-rc.1
0.14.0-rc.0
0.13.3
0.13.2
0.13.1
0.13.0
0.12.1
0.12.0
0.11.4
0.11.3
0.11.2
0.11.1
0.11.0
0.10.0
0.9.3
0.9.2
0.9.1
0.9.0
0.8.2
0.8.1
0.8.0
0.7.2
0.7.1
0.7.0
0.6.3
0.6.2
0.6.1
0.6.0
0.5.2
0.5.1
0.5.0
0.4.1
0.4.0
0.3.2
0.3.1
0.3.0
0.2.3
0.2.2
0.2.1
0.2.0
0.1.2
0.1.1
0.1.0
Automate code & data workflows with interactive notebooks
Current section
Files
Jump to
Current section
Files
lib/livebook/teams/app_deployment.ex
defmodule Livebook.Teams.AppDeployment do
use Ecto.Schema
alias Livebook.FileSystem
@max_size 20 * 1024 * 1024
@type t :: %__MODULE__{
id: String.t() | nil,
slug: String.t() | nil,
version: String.t() | nil,
sha: String.t() | nil,
title: String.t() | nil,
multi_session: boolean(),
access_type: Livebook.Notebook.AppSettings.access_type(),
hub_id: String.t() | nil,
deployment_group_id: String.t() | nil,
file: binary() | nil,
deployed_by: String.t() | nil,
deployed_at: DateTime.t() | nil
}
@access_types Livebook.Notebook.AppSettings.access_types()
@primary_key {:id, :string, autogenerate: false}
embedded_schema do
field :slug, :string
field :version, :string
field :sha, :string
field :title, :string
field :multi_session, :boolean
field :access_type, Ecto.Enum, values: @access_types
field :hub_id, :string
field :deployment_group_id, :string
field :file, :string
field :deployed_by, :string
field :deployed_at, :utc_datetime
end
@doc """
Creates a new app deployment from notebook.
"""
@spec new(Livebook.Notebook.t(), Livebook.FileSystem.File.t()) ::
{:ok, t()} | {:warning, list(String.t())} | {:error, FileSystem.error()}
def new(notebook, files_dir) do
with {:ok, source} <- fetch_notebook_source(notebook),
{:ok, files} <- build_and_check_file_entries(notebook, source, files_dir),
{:ok, {_, zip_content}} <- :zip.create(~c"app_deployment.zip", files, [:memory]),
:ok <- validate_size(zip_content) do
md5_hash = :crypto.hash(:md5, zip_content)
shasum = Base.encode16(md5_hash, case: :lower)
{:ok,
%__MODULE__{
slug: notebook.app_settings.slug,
sha: shasum,
title: notebook.name,
multi_session: notebook.app_settings.multi_session,
access_type: notebook.app_settings.access_type,
hub_id: notebook.hub_id,
deployment_group_id: notebook.deployment_group_id,
file: zip_content
}}
end
end
defp fetch_notebook_source(notebook) do
case Livebook.LiveMarkdown.notebook_to_livemd(notebook) do
{source, []} -> {:ok, source}
{_, warnings} -> {:warning, warnings}
end
end
defp build_and_check_file_entries(notebook, source, files_dir) do
notebook.file_entries
|> Enum.filter(&(&1.type == :attachment))
|> Enum.reduce_while({:ok, [{~c"notebook.livemd", source}]}, fn %{name: name}, {:ok, acc} ->
file = Livebook.FileSystem.File.resolve(files_dir, name)
with {:ok, true} <- Livebook.FileSystem.File.exists?(file),
{:ok, content} <- Livebook.FileSystem.File.read(file) do
{:cont, {:ok, [{to_charlist("files/" <> name), content} | acc]}}
else
{:ok, false} -> {:halt, {:error, "files/#{name}: doesn't exist"}}
{:error, reason} -> {:halt, {:error, "files/#{name}: #{reason}"}}
end
end)
end
defp validate_size(data) do
if byte_size(data) <= @max_size do
:ok
else
{:error, "the notebook and its attachments have exceeded the maximum size of 20MB"}
end
end
end