@@ -140,6 +140,14 @@ func (c *UpdaterClient) UpdateToNewVersion(version, edition, changelog string) e
140140 config .Logger ().Info ("Updating UTMStack to version %s-%s..." , version , edition )
141141 config .Updating = true
142142
143+ // Update installer binary first (only in prod branch)
144+ cnf := config .GetConfig ()
145+ if cnf .Branch == "prod" || cnf .Branch == "" {
146+ if err := c .UpdateInstaller (version ); err != nil {
147+ config .Logger ().ErrorF ("error updating installer: %v" , err )
148+ }
149+ }
150+
143151 err := docker .StackUP (version + "-" + edition )
144152 if err != nil {
145153 return fmt .Errorf ("error updating UTMStack: %v" , err )
@@ -153,11 +161,71 @@ func (c *UpdaterClient) UpdateToNewVersion(version, edition, changelog string) e
153161 config .Logger ().Info ("UTMStack updated to version %s-%s" , version , edition )
154162 config .Updating = false
155163
156- err = utils .RunCmd ("docker" , "system" , "prune" , "-f" )
164+ err = utils .RunCmd ("docker" , "image" , "prune" , "-a" , "-f" )
165+ if err != nil {
166+ config .Logger ().ErrorF ("error cleaning up old Docker images after update: %v" , err )
167+ }
168+
169+ // Restart service to load new installer binary
170+ if cnf .Branch == "prod" || cnf .Branch == "" {
171+ config .Logger ().Info ("Restarting service to load new installer binary..." )
172+ go func () {
173+ time .Sleep (5 * time .Second )
174+ utils .RestartService ("UTMStackComponentsUpdater" )
175+ }()
176+ }
177+
178+ return nil
179+ }
180+
181+ func (c * UpdaterClient ) UpdateInstaller (version string ) error {
182+ config .Logger ().Info ("Updating installer to version %s..." , version )
183+
184+ execPath , err := os .Executable ()
185+ if err != nil {
186+ return fmt .Errorf ("error getting executable path: %v" , err )
187+ }
188+
189+ // Download new installer from GitHub
190+ url := fmt .Sprintf (config .GitHubReleasesURL , version )
191+ resp , err := http .Get (url )
192+ if err != nil {
193+ return fmt .Errorf ("error downloading installer from %s: %v" , url , err )
194+ }
195+ defer resp .Body .Close ()
196+
197+ if resp .StatusCode != http .StatusOK {
198+ return fmt .Errorf ("error downloading installer: status %d" , resp .StatusCode )
199+ }
200+
201+ // Create temp file
202+ tmpFile , err := os .CreateTemp ("" , "installer-*" )
157203 if err != nil {
158- config .Logger ().ErrorF ("error cleaning up Docker system after update: %v" , err )
204+ return fmt .Errorf ("error creating temp file: %v" , err )
205+ }
206+ tmpPath := tmpFile .Name ()
207+
208+ // Download to temp file
209+ _ , err = io .Copy (tmpFile , resp .Body )
210+ tmpFile .Close ()
211+ if err != nil {
212+ os .Remove (tmpPath )
213+ return fmt .Errorf ("error writing installer to temp file: %v" , err )
214+ }
215+
216+ // Make executable
217+ if err := os .Chmod (tmpPath , 0755 ); err != nil {
218+ os .Remove (tmpPath )
219+ return fmt .Errorf ("error making installer executable: %v" , err )
220+ }
221+
222+ // Replace current binary
223+ if err := os .Rename (tmpPath , execPath ); err != nil {
224+ os .Remove (tmpPath )
225+ return fmt .Errorf ("error replacing installer binary: %v" , err )
159226 }
160227
228+ config .Logger ().Info ("Installer updated successfully to version %s" , version )
161229 return nil
162230}
163231
0 commit comments