Skip to content

Commit

Permalink
Fix broken delta generation for new files
Browse files Browse the repository at this point in the history
Co-authored-by: Eric Oestrich <[email protected]>
  • Loading branch information
lawik and oestrich committed Oct 10, 2024
1 parent 31a9acf commit e485f75
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 58 deletions.
23 changes: 6 additions & 17 deletions lib/nerves_hub/deployments.ex
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ defmodule NervesHub.Deployments do

case result do
{:ok, {deployment, changeset}} ->
maybe_trigger_delta_generation(deployment, changeset)
_ = maybe_trigger_delta_generation(deployment, changeset)
broadcast_deployment_updates(deployment, changeset)

{:ok, deployment}
Expand Down Expand Up @@ -318,22 +318,11 @@ defmodule NervesHub.Deployments do
end

defp trigger_delta_generation_for_deployment(deployment) do
case NervesHub.Devices.get_device_firmware_for_delta_generation_by_deployment(deployment.id) do
{:ok, %{rows: rows}} ->
rows
|> Enum.map(fn [source_id, target_id] ->
{source_id, target_id}
end)
|> Enum.uniq()
|> Enum.each(fn {source_id, target_id} ->
NervesHub.Workers.FirmwareDeltaBuilder.start(source_id, target_id)
end)

:ok

error ->
error
end
NervesHub.Devices.get_device_firmware_for_delta_generation_by_deployment(deployment.id)
|> Enum.uniq()
|> Enum.each(fn {source_id, target_id} ->
NervesHub.Workers.FirmwareDeltaBuilder.start(source_id, target_id)
end)
end

@doc """
Expand Down
32 changes: 20 additions & 12 deletions lib/nerves_hub/devices.ex
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,12 @@ defmodule NervesHub.Devices do
Repo.delete(ca_certificate)
end

@type firmware_id :: binary()
@type source_firmware_id() :: firmware_id()
@type target_firmware_id() :: firmware_id()

@spec get_device_firmware_for_delta_generation_by_product(binary()) ::
list({source_firmware_id(), target_firmware_id()})
def get_device_firmware_for_delta_generation_by_product(product_id) do
Deployment
|> where([dep], dep.product_id == ^product_id)
Expand All @@ -601,22 +607,24 @@ defmodule NervesHub.Devices do
)
# Exclude the current firmware, we don't need to generate that one
|> where([dep, dev, f], f.id != dep.firmware_id)
|> select([dep, dev, f], [f.id, dep.firmware_id])
|> select([dep, dev, f], {f.id, dep.firmware_id})
|> Repo.all()
end

@spec get_device_firmware_for_delta_generation_by_deployment(binary()) ::
list({source_firmware_id(), target_firmware_id()})
def get_device_firmware_for_delta_generation_by_deployment(deployment_id) do
Deployment
|> where([dep], dep.id == ^deployment_id)
|> join(:inner, [dep], dev in Device, on: dev.deployment_id == dep.id)
|> join(:inner, [dep, dev], f in Firmware,
on: f.uuid == fragment("d1.firmware_metadata->>'uuid'")
)
# Exclude the current firmware, we don't need to generate that one
|> where([dep, dev, f], f.id != dep.firmware_id)
|> select([dep, dev, f], [f.id, dep.firmware_id])
|> Repo.all()
end
Deployment
|> where([dep], dep.id == ^deployment_id)
|> join(:inner, [dep], dev in Device, on: dev.deployment_id == dep.id)
|> join(:inner, [dep, dev], f in Firmware,
on: f.uuid == fragment("d1.firmware_metadata->>'uuid'")
)
# Exclude the current firmware, we don't need to generate that one
|> where([dep, dev, f], f.id != dep.firmware_id)
|> select([dep, dev, f], {f.id, dep.firmware_id})
|> Repo.all()
end

def device_connected(device) do
device
Expand Down
31 changes: 20 additions & 11 deletions lib/nerves_hub/firmwares/delta_updater/default.ex
Original file line number Diff line number Diff line change
Expand Up @@ -82,17 +82,26 @@ defmodule NervesHub.Firmwares.DeltaUpdater.Default do
|> Path.dirname()
|> File.mkdir_p!()

args = [
"-A",
"-S",
"-f",
"-s",
Path.join(source_work_dir, path),
Path.join(target_work_dir, path),
output_path
]

{_, 0} = System.cmd("xdelta3", args, stderr_to_stdout: true)
source_filepath = Path.join(source_work_dir, path)
target_filepath = Path.join(target_work_dir, path)

case File.stat(source_filepath) do
{:ok, _} ->
args = [
"-A",
"-S",
"-f",
"-s",
source_filepath,
target_filepath,
output_path
]

{_, 0} = System.cmd("xdelta3", args, stderr_to_stdout: true)

{:error, :enoent} ->
File.cp!(target_filepath, output_path)
end
end
end

Expand Down
23 changes: 6 additions & 17 deletions lib/nerves_hub/products.ex
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ defmodule NervesHub.Products do

case result do
{:ok, %{delta_updatable: true} = new_product} when product.delta_updatable == false ->
trigger_delta_generation_for_product(new_product)
:ok = trigger_delta_generation_for_product(new_product)
result

_ ->
Expand All @@ -132,22 +132,11 @@ defmodule NervesHub.Products do
end

defp trigger_delta_generation_for_product(product) do
case NervesHub.Devices.get_device_firmware_for_delta_generation_by_product(product.id) do
{:ok, %{rows: rows}} ->
rows
|> Enum.map(fn [source_id, target_id] ->
{source_id, target_id}
end)
|> Enum.uniq()
|> Enum.each(fn {source_id, target_id} ->
NervesHub.Workers.FirmwareDeltaBuilder.start(source_id, target_id)
end)

:ok

error ->
error
end
NervesHub.Devices.get_device_firmware_for_delta_generation_by_product(product.id)
|> Enum.uniq()
|> Enum.each(fn {source_id, target_id} ->
NervesHub.Workers.FirmwareDeltaBuilder.start(source_id, target_id)
end)
end

@doc """
Expand Down
9 changes: 8 additions & 1 deletion test/support/channel_case.ex
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ defmodule NervesHubWeb.ChannelCase do
# Import conveniences for testing with channels
import Phoenix.ChannelTest
use DefaultMocks
use Oban.Testing, repo: NervesHub.ObanRepo

# The default endpoint for testing
@endpoint NervesHubWeb.DeviceEndpoint
Expand All @@ -29,11 +30,17 @@ defmodule NervesHubWeb.ChannelCase do
setup do
# Explicitly get a connection before each test
:ok = Ecto.Adapters.SQL.Sandbox.checkout(NervesHub.Repo)
:ok = Ecto.Adapters.SQL.Sandbox.checkout(NervesHub.ObanRepo)
end

setup tags do
pid = Ecto.Adapters.SQL.Sandbox.start_owner!(NervesHub.Repo, shared: not tags[:async])
on_exit(fn -> Ecto.Adapters.SQL.Sandbox.stop_owner(pid) end)
pid2 = Ecto.Adapters.SQL.Sandbox.start_owner!(NervesHub.ObanRepo, shared: not tags[:async])

on_exit(fn ->
Ecto.Adapters.SQL.Sandbox.stop_owner(pid)
Ecto.Adapters.SQL.Sandbox.stop_owner(pid2)
end)

:ok
end
Expand Down

0 comments on commit e485f75

Please sign in to comment.