Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package zvm for openSUSE:Factory checked in at 2026-09-04 12:39:18 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/zvm (Old) and /work/SRC/openSUSE:Factory/.zvm.new.1265 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "zvm" Fri Sep 4 12:39:18 2026 rev:13 rq:1375489 version:0.8.27 Changes: -------- --- /work/SRC/openSUSE:Factory/zvm/zvm.changes 2026-05-25 22:00:33.778244688 +0200 +++ /work/SRC/openSUSE:Factory/.zvm.new.1265/zvm.changes 2026-09-04 12:40:09.409050945 +0200 @@ -1,0 +2,6 @@ +Sat Jul 18 14:06:45 UTC 2026 - Andrea Manzini <[email protected]> + +- Update to 0.8.27: + * added support for http.timeout + +------------------------------------------------------------------- Old: ---- zvm-0.8.22.tar.gz New: ---- zvm-0.8.27.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ zvm.spec ++++++ --- /var/tmp/diff_new_pack.AJQTKW/_old 2026-09-04 12:40:10.103075317 +0200 +++ /var/tmp/diff_new_pack.AJQTKW/_new 2026-09-04 12:40:10.105075387 +0200 @@ -17,14 +17,14 @@ Name: zvm -Version: 0.8.22 +Version: 0.8.27 Release: 0 Summary: Easily install/upgrade between different versions of Zig License: MIT URL: https://github.com/tristanisham/zvm Source: https://github.com/tristanisham/zvm/archive/refs/tags/v%{version}.tar.gz#/%{name}-%{version}.tar.gz Source1: vendor.tar.xz -BuildRequires: golang(API) >= 1.22 +BuildRequires: golang(API) >= 1.26 %description Zig Version Manager (zvm) is a tool for managing your Zig installs. With std ++++++ vendor.tar.xz ++++++ ++++++ zvm-0.8.22.tar.gz -> zvm-0.8.27.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/zvm-0.8.22/.vscode/launch.json new/zvm-0.8.27/.vscode/launch.json --- old/zvm-0.8.22/.vscode/launch.json 2026-05-24 15:55:19.000000000 +0200 +++ new/zvm-0.8.27/.vscode/launch.json 1970-01-01 01:00:00.000000000 +0100 @@ -1,15 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "name": "Launch Package", - "type": "go", - "request": "launch", - "mode": "auto", - "program": "${fileDirname}" - } - ] -} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/zvm-0.8.22/.vscode/settings.json new/zvm-0.8.27/.vscode/settings.json --- old/zvm-0.8.22/.vscode/settings.json 2026-05-24 15:55:19.000000000 +0200 +++ new/zvm-0.8.27/.vscode/settings.json 1970-01-01 01:00:00.000000000 +0100 @@ -1,4 +0,0 @@ -{ - "deno.enable": true, - "deno.unstable": true -} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/zvm-0.8.22/README.md new/zvm-0.8.27/README.md --- old/zvm-0.8.22/README.md 2026-05-24 15:55:19.000000000 +0200 +++ new/zvm-0.8.27/README.md 2026-06-09 20:25:04.000000000 +0200 @@ -134,7 +134,7 @@ it, and install it on your `$PATH`. Or, you could install ZVM and run `zvm i master` every time you want to update. `zvm` is a static binary under a permissive license. It supports more platforms than any other Zig version -manager. Its only dependency is `tar` on Unix-based systems. Whether you're on +manager. ZVM has no system dependencies. Whether you're on Windows, MacOS, Linux, a flavor of BSD, or Plan 9 `zvm` will let you install, switch between, and run multiple versions of Zig. @@ -232,6 +232,13 @@ You can also enable the old behavior by setting the new `alwaysForceInstall` field to `true` in `~/.zvm/settings.json`. +### Customize HTTP Timeout +You can pass a custom HTTP timeout (in seconds) for `zvm i` using the `--http.timeout` flag or by setting the `ZVM_HTTP_TIMEOUT` environment variable. + +```sh +zvm i --http.timeout 30 +``` + ### Install ZLS with ZVM You can now install ZLS with your Zig download! To install ZLS with ZVM, simply diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/zvm-0.8.22/cli/install.go new/zvm-0.8.27/cli/install.go --- old/zvm-0.8.22/cli/install.go 2026-05-24 15:55:19.000000000 +0200 +++ new/zvm-0.8.27/cli/install.go 2026-06-09 20:25:04.000000000 +0200 @@ -7,6 +7,7 @@ import ( "archive/tar" "archive/zip" + "bufio" "crypto/sha256" "crypto/tls" "encoding/hex" @@ -23,6 +24,7 @@ "path/filepath" "runtime" "slices" + "strconv" "strings" "time" @@ -36,14 +38,16 @@ "github.com/tristanisham/clr" ) +const httpDefaultTimeout = (60 * 3) * time.Second + // Install downloads and installs the specified Zig version. // It handles checking for existing installations, verifying checksums, // and extracting the downloaded bundle. func (z *ZVM) Install(version string, force bool, mirror bool) (string, error) { - err := os.MkdirAll(z.baseDir, 0755) - if err != nil { + if err := os.MkdirAll(z.baseDir, 0755); err != nil { return version, err } + rawVersionStructure, err := z.fetchVersionMap() if err != nil { return version, err @@ -107,11 +111,28 @@ var tarResp *http.Response var minisig minisign.Signature - mirror = mirror && z.Settings.UseMirrorList() && z.Settings.VersionMapUrl == DefaultSettings.VersionMapUrl + var verifyMinisig bool + + // Only the official version map serves builds signed with the pinned + // minisign key; custom version maps distribute their own builds, so + // signature verification can't apply to them. + isOfficialVMUSet := z.Settings.VersionMapUrl == DefaultSettings.VersionMapUrl + mirror = mirror && z.Settings.UseMirrorList() && isOfficialVMUSet if mirror { tarResp, minisig, err = attemptMirrorDownload(z.Settings.MirrorListUrl, tarPath) + verifyMinisig = err == nil } else { - tarResp, err = attemptDownload(tarPath) + tarResp, err = attemptDownload(tarPath, nil) + if err == nil && isOfficialVMUSet { + // ziglang.org publishes a .minisig for every build, so a missing + // signature is a failed download, not a reason to skip verification. + minisig, err = attemptMinisigDownload(tarPath, nil) + if err != nil { + tarResp.Body.Close() + err = fmt.Errorf("minisign signature download failed: %w", err) + } + verifyMinisig = err == nil + } } if err != nil { @@ -176,7 +197,7 @@ log.Warnf("No shasum provided by host") } - if mirror { + if verifyMinisig { fmt.Println("Checking minisign signature...") pubkey, err := minisign.NewPublicKey(z.Settings.MinisignPubKey) if err != nil { @@ -266,7 +287,7 @@ } tarName := path.Base(tarURLParsed.Path) - resp, err := attemptDownload(mirrorListURL) + resp, err := attemptDownload(mirrorListURL, nil) if err != nil { return nil, minisign.Signature{}, fmt.Errorf("%w: %w", ErrDownloadFail, err) } @@ -292,13 +313,13 @@ } log.Debug("attemptMirrorDownload", "mirror", i, "mirrorURL", mirrorTarURL) - tarResp, err := attemptDownload(mirrorTarURL) + tarResp, err := attemptDownload(mirrorTarURL, nil) if err != nil { log.Debug("mirror tar error", "mirror", mirror, "error", err) continue } - minisig, err := attemptMinisigDownload(mirrorTarURL) + minisig, err := attemptMinisigDownload(mirrorTarURL, nil) if err != nil { log.Debug("mirror minisig error", "mirror", mirror, "error", err) tarResp.Body.Close() @@ -312,8 +333,8 @@ } // attemptMinisigDownload downloads the minisign signature for a given tarball URL. -func attemptMinisigDownload(tarURL string) (minisign.Signature, error) { - minisigResp, err := attemptDownload(tarURL + ".minisig") +func attemptMinisigDownload(tarURL string, client *http.Client) (minisign.Signature, error) { + minisigResp, err := attemptDownload(tarURL+".minisig", client) if err != nil { return minisign.Signature{}, err } @@ -328,13 +349,29 @@ } // attemptDownload creates a generic http request for ZVM. -func attemptDownload(url string) (*http.Response, error) { +func attemptDownload(url string, client *http.Client) (*http.Response, error) { req, err := createDownloadReq(url) if err != nil { return nil, fmt.Errorf("%w: %w", ErrDownloadFail, err) } - client := http.DefaultClient + if client == nil { + client = &http.Client{} + } + + envTimeout := os.Getenv("ZVM_HTTP_TIMEOUT") + if envTimeout != "" { + timeout, err := strconv.Atoi(envTimeout) + if err == nil { + client.Timeout = time.Duration(timeout) * time.Second + } else { + client.Timeout = httpDefaultTimeout + } + } else { + client.Timeout = httpDefaultTimeout + } + + log.Debug("using client", "timeout", client.Timeout.String()) // Checks the ZVM_SKIP_TLS_VERIFY environment variable and // toggles verifying a secure connection. @@ -345,10 +382,8 @@ } log.Debug("ZVM_SKIP_TLS_VERIFY", "enabled", true) - client = &http.Client{ - Transport: &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, - }, + client.Transport = &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, } } else { // Yeah, yeah. Just an easy way to do the call. @@ -360,7 +395,8 @@ return nil, fmt.Errorf("%w: %w", ErrDownloadFail, err) } - if resp.StatusCode != 200 { + if resp.StatusCode != http.StatusOK { + resp.Body.Close() return nil, fmt.Errorf("%w: %s", ErrDownloadFail, resp.Status) } @@ -497,7 +533,7 @@ log.Debug("tarPath", "url", tarPath) - tarResp, err := attemptDownload(tarPath) + tarResp, err := attemptDownload(tarPath, nil) if err != nil { return err } @@ -760,7 +796,9 @@ } defer file.Close() - xzReader, err := xz.NewReader(file) + bufferedReader := bufio.NewReaderSize(file, 256*1024) + + xzReader, err := xz.NewReader(bufferedReader) if err != nil { return fmt.Errorf("failed to initalize xz reader %w", err) } @@ -831,72 +869,104 @@ // unzipSource extracts a .zip file to the specified destination directory. func unzipSource(source, destination string) error { - // 1. Open the zip file + var timer time.Time + if meta.Debug { + timer = time.Now() + } + reader, err := zip.OpenReader(source) if err != nil { return err } - defer reader.Close() - // 2. Get the absolute destination path destination, err = filepath.Abs(destination) if err != nil { return err } - os.MkdirAll(destination, 0755) + if err := os.MkdirAll(destination, 0755); err != nil { + return fmt.Errorf("failed to create destination directory: %w", err) + } - extractAndWriteFile := func(f *zip.File) error { - rc, err := f.Open() - if err != nil { - return err - } + root, err := os.OpenRoot(destination) + if err != nil { + return fmt.Errorf("failed to open root %w", err) + } + defer root.Close() + + for _, f := range reader.File { + name := filepath.Clean(f.Name) + mode := f.Mode() + perm := mode.Perm() - defer func() { - if err := rc.Close(); err != nil { - panic(err) + if mode.IsDir() { + if perm == 0 { + perm = 0755 } - }() - path := filepath.Join(destination, f.Name) - // TODO look into how to make this more efficient and to trim excess calls. - root, err := os.OpenRoot(path) - if err != nil { - return fmt.Errorf("failed to open root %w", err) + if err := root.MkdirAll(name, perm); err != nil { + return fmt.Errorf("failed to create directory %q: %w", f.Name, err) + } + continue } - if f.FileInfo().IsDir() { - root.MkdirAll(path, f.Mode()) - } else { - root.MkdirAll(filepath.Dir(path), f.Mode()) - f, err := root.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode()) + if err := root.MkdirAll(filepath.Dir(name), 0755); err != nil { + return fmt.Errorf("failed to create parent directory for %q: %w", f.Name, err) + } + + if mode&os.ModeSymlink != 0 { + src, err := f.Open() if err != nil { - return fmt.Errorf("failed to open file %w", err) + return fmt.Errorf("failed to open symlink %q: %w", f.Name, err) } - defer func() { - if err := f.Close(); err != nil { - panic(err) - } - }() + targetBytes, readErr := io.ReadAll(src) + closeErr := src.Close() + if readErr != nil { + return fmt.Errorf("failed to read symlink %q: %w", f.Name, readErr) + } + if closeErr != nil { + return fmt.Errorf("failed to close symlink %q: %w", f.Name, closeErr) + } - _, err = io.Copy(f, rc) - if err != nil { - return fmt.Errorf("failed to copy zip archive %w", err) + if err := root.Symlink(string(targetBytes), name); err != nil { + return fmt.Errorf("failed to create symlink %q: %w", f.Name, err) } + continue } - return nil - } + if perm == 0 { + perm = 0644 + } - // 3. Iterate over zip files inside the archive and unzip each of them - for _, f := range reader.File { - err := extractAndWriteFile(f) + src, err := f.Open() if err != nil { - return err + return fmt.Errorf("failed to open file %q: %w", f.Name, err) + } + + outFile, err := root.OpenFile(name, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, perm) + if err != nil { + src.Close() + return fmt.Errorf("failed to create file %q: %w", f.Name, err) } + _, copyErr := io.Copy(outFile, src) + closeOutErr := outFile.Close() + closeSrcErr := src.Close() + if copyErr != nil { + return fmt.Errorf("failed to write file %q: %w", f.Name, copyErr) + } + if closeOutErr != nil { + return fmt.Errorf("failed to close file %q: %w", f.Name, closeOutErr) + } + if closeSrcErr != nil { + return fmt.Errorf("failed to close zip entry %q: %w", f.Name, closeSrcErr) + } + } + + if meta.Debug { + log.Debug("unzipSource", "duration", time.Since(timer)) } return nil diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/zvm-0.8.22/cli/meta/version.go new/zvm-0.8.27/cli/meta/version.go --- old/zvm-0.8.22/cli/meta/version.go 2026-05-24 15:55:19.000000000 +0200 +++ new/zvm-0.8.27/cli/meta/version.go 2026-06-09 20:25:04.000000000 +0200 @@ -10,7 +10,7 @@ ) const ( - VERSION = "v0.8.22" + VERSION = "v0.8.25" // VERSION = "v0.0.0" // For testing zvm upgrade diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/zvm-0.8.22/main.go new/zvm-0.8.27/main.go --- old/zvm-0.8.22/main.go 2026-05-24 15:55:19.000000000 +0200 +++ new/zvm-0.8.27/main.go 2026-06-09 20:25:04.000000000 +0200 @@ -9,6 +9,7 @@ "errors" "fmt" "os" + "strconv" "strings" "time" @@ -101,6 +102,11 @@ Usage: "override the target architecture (e.g., x86_64, aarch64, arm, riscv64)", Sources: opts.EnvVars("ZVM_TARGET_ARCH"), }, + &opts.IntFlag{ + Name: "http.timeout", + Usage: "set a custom timeout for http requests", + Sources: opts.EnvVars("ZVM_HTTP_TIMEOUT"), + }, }, Description: "To install the latest version, use `master`", // Args: true, @@ -129,10 +135,16 @@ if v := cmd.String("target-os"); v != "" { os.Setenv("ZVM_TARGET_OS", v) } + if v := cmd.String("target-arch"); v != "" { os.Setenv("ZVM_TARGET_ARCH", v) } + // HTTP Settings + if v := cmd.Int64("http.timeout"); v != 0 { + os.Setenv("ZVM_HTTP_TIMEOUT", strconv.FormatInt(v, 10)) + } + // Install Zig resolvedVersion, err := zvm.Install(req.Package, force, !cmd.Bool("nomirror")) if err != nil {
