MCPcopy Index your code
hub / github.com/codehamr/codehamr / Apply

Function Apply

internal/update/update.go:133–215  ·  view source on GitHub ↗

Apply downloads the current platform's binary, verifies its sha256 against the published codehamr_checksums.txt, and atomically replaces execPath. The caller is expected to syscall.Exec afterwards so the process becomes the new binary with no user-visible restart. Checksum verification closes the s

(ctx context.Context, execPath string)

Source from the content-addressed store, hash-verified

131// ctx governs both fetches; the binary download sets no http.Client.Timeout, so
132// ctx's deadline is the only budget.
133func Apply(ctx context.Context, execPath string) error {
134 asset, ok := assetName(runtime.GOOS, runtime.GOARCH)
135 if !ok {
136 return fmt.Errorf("unsupported platform: %s/%s", runtime.GOOS, runtime.GOARCH)
137 }
138 expected, err := fetchHash(ctx, asset)
139 if err != nil {
140 return fmt.Errorf("checksum lookup: %w", err)
141 }
142 if expected == "" {
143 return fmt.Errorf("checksum lookup: no entry for %s in published manifest", asset)
144 }
145 tmp, err := os.CreateTemp(filepath.Dir(execPath), ".codehamr-update-*")
146 if err != nil {
147 return err
148 }
149 tmpPath := tmp.Name()
150 // Deferred Close/Remove clean up on any early return below. After a
151 // successful rename tmpPath is gone (Remove's ENOENT ignored); a second
152 // Close on *os.File is harmless.
153 defer os.Remove(tmpPath)
154 defer tmp.Close()
155
156 req, err := http.NewRequestWithContext(ctx, "GET", releaseBase+asset, nil)
157 if err != nil {
158 return err
159 }
160 resp, err := http.DefaultClient.Do(req)
161 if err != nil {
162 return err
163 }
164 defer resp.Body.Close()
165 if resp.StatusCode != http.StatusOK {
166 return fmt.Errorf("download: status %d", resp.StatusCode)
167 }
168 // Stream-hash while writing so verification needs no second read of the
169 // temp file.
170 h := sha256.New()
171 if _, err := io.Copy(io.MultiWriter(tmp, h), resp.Body); err != nil {
172 return err
173 }
174 // Sync before the rename: rename is metadata-only, so without the flush a
175 // power loss right after Apply can journal the rename while the data never
176 // hit disk, leaving a truncated binary at execPath that CleanupOld can
177 // never reach (recoverable only by hand from .old).
178 if err := tmp.Sync(); err != nil {
179 return err
180 }
181 if err := tmp.Close(); err != nil {
182 return err
183 }
184 got := hex.EncodeToString(h.Sum(nil))
185 if !strings.EqualFold(got, expected) {
186 return fmt.Errorf("checksum mismatch: downloaded %s, expected %s", got, expected)
187 }
188 if err := os.Chmod(tmpPath, 0o755); err != nil {
189 return err
190 }

Calls 2

assetNameFunction · 0.85
fetchHashFunction · 0.85