@@ -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
120176end
0 commit comments