Skip to content

Commit 7524603

Browse files
Jean Parpaillonjohngiffin
authored andcommitted
firmware.patch handles FAT resources
With the following patch fwup-home/fwup#202 , fwup is able to apply delta updates on FAT resources. This patch update firmware.patch mix task to create firmware patches including FAT resources delta updates.
1 parent f7887a6 commit 7524603

File tree

1 file changed

+79
-23
lines changed

1 file changed

+79
-23
lines changed

lib/mix/tasks/firmware.patch.ex

Lines changed: 79 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ defmodule Mix.Tasks.Firmware.Patch do
55
Generate a firmware patch from a source and target firmware and output a new
66
firmware file with the patch contents. The source firmware file
77
8-
This requires fwup >= 1.6.0
8+
This requires fwup >= 1.10.0
99
1010
## Command line options
1111
@@ -21,7 +21,7 @@ defmodule Mix.Tasks.Firmware.Patch do
2121
alias Mix.Nerves.Preflight
2222
alias Nerves.Utils.Shell
2323

24-
@fwup_semver "~> 1.6 or ~> 1.6.0-dev"
24+
@fwup_semver ">= 1.10.0"
2525

2626
@switches [source: :string, target: :string, output: :string]
2727

@@ -56,27 +56,7 @@ defmodule Mix.Tasks.Firmware.Patch do
5656

5757
target_stats = File.stat!(target)
5858

59-
source_work_dir = Path.join(work_dir, "source")
60-
target_work_dir = Path.join(work_dir, "target")
61-
output_work_dir = Path.join(work_dir, "output")
62-
63-
File.mkdir_p!(source_work_dir)
64-
File.mkdir_p!(target_work_dir)
65-
File.mkdir_p!(Path.join(output_work_dir, "data"))
66-
67-
{_, 0} = shell("unzip", ["-qq", source, "-d", source_work_dir])
68-
{_, 0} = shell("unzip", ["-qq", target, "-d", target_work_dir])
69-
70-
source_rootfs = Path.join([source_work_dir, "data", "rootfs.img"])
71-
target_rootfs = Path.join([target_work_dir, "data", "rootfs.img"])
72-
out_rootfs = Path.join([output_work_dir, "data", "rootfs.img"])
73-
74-
{_, 0} = shell("xdelta3", ["-A", "-S", "-f", "-s", source_rootfs, target_rootfs, out_rootfs])
75-
76-
File.mkdir_p!(Path.dirname(output))
77-
File.cp!(target, output)
78-
79-
{_, 0} = shell("zip", ["-qq", output, "data/rootfs.img"], cd: output_work_dir)
59+
_ = create(source, target, output, work_dir)
8060

8161
output_stats = File.stat!(output)
8262

@@ -117,4 +97,80 @@ defmodule Mix.Tasks.Firmware.Patch do
11797
Mix.Tasks.Firmware.run(["--output", out_fw])
11898
out_fw
11999
end
100+
101+
defp create(source_path, target_path, output_path, work_dir) do
102+
source_work_dir = Path.join(work_dir, "source")
103+
target_work_dir = Path.join(work_dir, "target")
104+
output_work_dir = Path.join(work_dir, "output")
105+
106+
_ = File.mkdir_p(source_work_dir)
107+
_ = File.mkdir_p(target_work_dir)
108+
_ = File.mkdir_p(output_work_dir)
109+
110+
{_, 0} = shell("unzip", ["-qq", source_path, "-d", source_work_dir])
111+
{_, 0} = shell("unzip", ["-qq", target_path, "-d", target_work_dir])
112+
113+
for path <- Path.wildcard(target_work_dir <> "/**") do
114+
path = Regex.replace(~r/^#{target_work_dir}\//, path, "")
115+
116+
unless File.dir?(Path.join(target_work_dir, path)) do
117+
:ok = handle_content(path, source_work_dir, target_work_dir, output_work_dir)
118+
end
119+
end
120+
121+
# firmware archive files order matters:
122+
# 1. meta.conf.ed25519 (optional)
123+
# 2. meta.conf
124+
# 3. other...
125+
[
126+
"meta.conf.*",
127+
"meta.conf",
128+
"data"
129+
]
130+
|> Enum.each(&add_to_zip(&1, output_work_dir, output_path))
131+
132+
output_path
133+
end
134+
135+
defp handle_content("meta." <> _ = path, _source_dir, target_dir, out_dir) do
136+
do_copy(Path.join(target_dir, path), Path.join(out_dir, path))
137+
end
138+
139+
defp handle_content(path, source_dir, target_dir, out_dir) do
140+
do_delta(Path.join(source_dir, path), Path.join(target_dir, path), Path.join(out_dir, path))
141+
end
142+
143+
defp do_copy(source, target) do
144+
target |> Path.dirname() |> File.mkdir_p!()
145+
File.cp(source, target)
146+
end
147+
148+
defp do_delta(source, target, out) do
149+
out |> Path.dirname() |> File.mkdir_p!()
150+
151+
case shell("xdelta3", ["-A", "-S", "-f", "-s", source, target, out]) do
152+
{_, 0} -> :ok
153+
{_, code} -> {:error, code}
154+
end
155+
end
156+
157+
defp add_to_zip(glob, workdir, output) do
158+
workdir
159+
|> Path.join(glob)
160+
|> Path.wildcard()
161+
|> case do
162+
[] ->
163+
:ok
164+
165+
paths ->
166+
{_, 0} =
167+
System.cmd(
168+
"zip",
169+
["-r", "-qq", output | Enum.map(paths, &Path.relative_to(&1, workdir))],
170+
cd: workdir
171+
)
172+
173+
:ok
174+
end
175+
end
120176
end

0 commit comments

Comments
 (0)