1
1
defmodule Mix.Tasks.Burn do
2
2
use Mix.Task
3
3
import Mix.Nerves.Utils
4
- alias Mix.Nerves.Preflight
4
+ alias Mix.Nerves . { FwupStream , Preflight }
5
5
alias Nerves.Utils.WSL
6
6
7
- @ switches [ device: :string , task: :string , firmware: :string ]
7
+ @ switches [ device: :string , task: :string , firmware: :string , overwrite: :boolean ]
8
8
@ aliases [ d: :device , t: :task , i: :firmware ]
9
9
10
10
@ shortdoc "Write a firmware image to an SDCard"
@@ -13,8 +13,9 @@ defmodule Mix.Tasks.Burn do
13
13
Writes the generated firmware image to an attached SDCard or file.
14
14
15
15
By default, this task detects attached SDCards and then invokes `fwup`
16
- to overwrite the contents of the selected SDCard with the new image.
17
- Data on the SDCard will be lost, so be careful.
16
+ to upgrade the contents of the selected SDCard with the new image.
17
+ If the upgrade to the next parition fails, it will then attempt to
18
+ completely overwrite the SDCard with the new image.
18
19
19
20
## Command line options
20
21
@@ -29,10 +30,14 @@ defmodule Mix.Tasks.Burn do
29
30
convention, the `complete` task writes everything to the SDCard including
30
31
bootloader and application data partitions. The `upgrade` task only
31
32
modifies the parts of the SDCard required to run the new software.
33
+ Defaults to `upgrade`
32
34
33
35
* `--firmware <name>` - (Optional) The path to the fw file to use.
34
36
Defaults to `<image_path>/<otp_app>.fw`
35
37
38
+ * `--overwrite` - (Optional) Overwrite the contents of the SDCard by
39
+ forcing the `complete` task. Defaults to `false`
40
+
36
41
## Examples
37
42
38
43
```
@@ -71,56 +76,39 @@ defmodule Mix.Tasks.Burn do
71
76
dev -> dev
72
77
end
73
78
79
+ task = if opts [ :overwrite ] , do: "complete" , else: opts [ :task ] || "upgrade"
80
+
74
81
set_provisioning ( firmware_config [ :provisioning ] )
75
- burn ( fw , dev , opts , argv )
82
+
83
+ burn ( fw , dev , task , argv )
76
84
77
85
# Remove the temporary .fw file
78
86
WSL . cleanup_file ( fw , firmware_location )
79
87
end
80
88
81
- defp burn ( fw , dev , opts , argv ) do
82
- task = opts [ :task ] || "complete"
89
+ defp burn ( fw , dev , task , argv ) do
83
90
args = [ "-a" , "-i" , fw , "-t" , task , "-d" , dev ] ++ argv
84
91
85
- { cmd , args } =
86
- case :os . type ( ) do
87
- { _ , :darwin } ->
88
- { "fwup" , args }
89
-
90
- { _ , :linux } ->
91
- if WSL . running_on_wsl? ( ) do
92
- WSL . admin_powershell_command ( "fwup" , Enum . join ( args , " " ) )
93
- else
94
- fwup = System . find_executable ( "fwup" )
95
-
96
- case File . stat ( dev ) do
97
- { :ok , % File.Stat { access: :read_write } } ->
98
- { "fwup" , args }
99
-
100
- { :error , :enoent } ->
101
- case File . touch ( dev , System . os_time ( :second ) ) do
102
- :ok ->
103
- { "fwup" , args }
104
-
105
- { :error , :eacces } ->
106
- elevate_user ( )
107
- { "sudo" , provision_env ( ) ++ [ fwup ] ++ args }
108
- end
109
-
110
- _ ->
111
- elevate_user ( )
112
- { "sudo" , provision_env ( ) ++ [ fwup ] ++ args }
113
- end
114
- end
115
-
116
- { _ , :nt } ->
117
- { "fwup" , args }
118
-
119
- { _ , type } ->
120
- raise "Unable to burn firmware on your host #{ inspect ( type ) } "
121
- end
92
+ os = get_os! ( )
122
93
123
- shell ( cmd , args )
94
+ { cmd , args } = cmd_and_args_for_os ( os , args , dev )
95
+
96
+ shell ( cmd , args , stream: FwupStream . new ( ) )
97
+ |> format_result ( task )
98
+ |> case do
99
+ :failed_not_upgradable ->
100
+ Mix . shell ( ) . info ( """
101
+ #{ IO.ANSI . yellow ( ) }
102
+ Device #{ dev } either doesn't have firmware on it or has incompatible firmware.
103
+ Going to burn the whole MicroSD card so that it's in a factory-default state.
104
+ #{ IO.ANSI . default_color ( ) }
105
+ """ )
106
+
107
+ burn ( fw , dev , "complete" , argv )
108
+
109
+ result ->
110
+ result
111
+ end
124
112
end
125
113
126
114
# Requests an elevation of user through askpass
@@ -157,4 +145,58 @@ defmodule Mix.Tasks.Burn do
157
145
Nerves.Env . firmware_path ( )
158
146
end
159
147
end
148
+
149
+ defp get_os! ( ) do
150
+ case :os . type ( ) do
151
+ { _ , :linux } ->
152
+ if WSL . running_on_wsl? ( ) , do: :wsl , else: :linux
153
+
154
+ { _ , os } when os in [ :darwin , :nt ] ->
155
+ os
156
+
157
+ { _ , os } ->
158
+ raise "Unable to burn firmware on your host #{ inspect ( os ) } "
159
+ end
160
+ end
161
+
162
+ defp cmd_and_args_for_os ( :linux , args , dev ) do
163
+ fwup = System . find_executable ( "fwup" )
164
+
165
+ case File . stat ( dev ) do
166
+ { :ok , % File.Stat { access: :read_write } } ->
167
+ { "fwup" , args }
168
+
169
+ { :error , :enoent } ->
170
+ case File . touch ( dev , System . os_time ( :second ) ) do
171
+ :ok ->
172
+ { "fwup" , args }
173
+
174
+ { :error , :eacces } ->
175
+ elevate_user ( )
176
+ { "sudo" , provision_env ( ) ++ [ fwup ] ++ args }
177
+ end
178
+
179
+ _ ->
180
+ elevate_user ( )
181
+ { "sudo" , provision_env ( ) ++ [ fwup ] ++ args }
182
+ end
183
+ end
184
+
185
+ defp cmd_and_args_for_os ( :wsl , args , _dev ) do
186
+ WSL . admin_powershell_command ( "fwup" , Enum . join ( args , " " ) )
187
+ end
188
+
189
+ defp cmd_and_args_for_os ( _os , args , _dev ) , do: { "fwup" , args }
190
+
191
+ defp format_result ( { _ , 0 } , _task ) , do: :ok
192
+
193
+ defp format_result ( { % FwupStream { output: o } , _ } , "upgrade" ) do
194
+ if o =~ ~r/ fwup: Expecting platform=#{ mix_target ( ) } and/ do
195
+ :failed_not_upgradable
196
+ else
197
+ :failed
198
+ end
199
+ end
200
+
201
+ defp format_result ( _result , _task ) , do: :failed
160
202
end
0 commit comments