diff --git a/cmd/list.go b/cmd/list.go index a2c48c94c7..f1f78729f4 100644 --- a/cmd/list.go +++ b/cmd/list.go @@ -90,7 +90,8 @@ func (lr *listResult) print() { } func showComponentList(env *environment.Environment, opt listOptions) (*listResult, error) { - if !opt.installedOnly { + // Skip online update in packaged builds + if !opt.installedOnly && !environment.IsPackagedBuild { err := env.V1Repository().UpdateComponentManifests() if err != nil { tui.ColorWarningMsg.Fprint(os.Stderr, "Warn: Update component manifest failed, err_msg=[", err.Error(), "]\n") @@ -182,8 +183,16 @@ func showComponentList(env *environment.Environment, opt listOptions) (*listResu } func showComponentVersions(env *environment.Environment, component string, opt listOptions) (*listResult, error) { + versions, err := env.Profile().InstalledVersions(component) + if err != nil { + return nil, err + } + installed := set.NewStringSet(versions...) + + var cmpTable [][]string + cmpTable = append(cmpTable, []string{"Version", "Installed", "Release", "Platforms"}) + var comp *v1manifest.Component - var err error if opt.installedOnly { comp, err = env.V1Repository().LocalComponentManifest(component, false) } else { @@ -193,15 +202,6 @@ func showComponentVersions(env *environment.Environment, component string, opt l return nil, errors.Annotate(err, "failed to fetch component") } - versions, err := env.Profile().InstalledVersions(component) - if err != nil { - return nil, err - } - installed := set.NewStringSet(versions...) - - var cmpTable [][]string - cmpTable = append(cmpTable, []string{"Version", "Installed", "Release", "Platforms"}) - platforms := make(map[string][]string) released := make(map[string]string) diff --git a/pkg/environment/env.go b/pkg/environment/env.go index 8ea388cc3e..53b300fd71 100644 --- a/pkg/environment/env.go +++ b/pkg/environment/env.go @@ -33,6 +33,10 @@ import ( var ( // ErrInstallFirst indicates that a component/version is not installed ErrInstallFirst = errors.New("component not installed") + + // IsPackagedBuild is hard-coded to 'true' in binaries produced by packaged builds + // (e.g., Debian, RPM, Homebrew) to change their behavior to be more like real system programs. + IsPackagedBuild = true ) // EnvList is the canonical allowlist of environment variables TiUP will print or expose. @@ -127,6 +131,13 @@ func InitEnv(options repository.Options, mOpt repository.MirrorOptions) (*Enviro return env, nil } + // Always initialize the repository. In packaged builds, + // specific functions (like automatic updates) will check IsPackagedBuild + // and adapt their behavior. Explicit install/list should work. + if IsPackagedBuild { + fmt.Fprintln(os.Stderr, "Online version check and repository interaction skipped in packaged build.") + } + initRepo := time.Now() profile := localdata.InitProfile() @@ -203,6 +214,9 @@ func (env *Environment) UpdateComponents(specs []string, nightly, force bool) er // SelfUpdate updates TiUP. func (env *Environment) SelfUpdate() error { + if IsPackagedBuild { + return errors.New("tiup self-update is disabled in this packaged build") + } if err := env.v1Repo.DownloadTiUP(env.LocalPath("bin")); err != nil { return err } diff --git a/pkg/exec/run.go b/pkg/exec/run.go index 7ef82b5973..2a52de55a1 100644 --- a/pkg/exec/run.go +++ b/pkg/exec/run.go @@ -175,6 +175,11 @@ func PrepareCommand(p *PrepareCommandParams) (*exec.Cmd, error) { } func cmdCheckUpdate(component string, version utils.Version) { + // Skip online check in binaries installed by a package manager + if environment.IsPackagedBuild { + return + } + const ( slowTimeout = 1 * time.Second // Timeout to display checking message cancelTimeout = 2 * time.Second // Timeout to cancel the check diff --git a/pkg/repository/v1_repository.go b/pkg/repository/v1_repository.go index 1df59145cd..216ebc2051 100644 --- a/pkg/repository/v1_repository.go +++ b/pkg/repository/v1_repository.go @@ -538,6 +538,11 @@ func (r *V1Repository) PurgeTimestamp() { // has the same value of our local one. (not hashing the snapshot file itself) // Return weather the manifest is changed compared to the one in local ts and the FileHash of snapshot. func (r *V1Repository) fetchTimestamp() (changed bool, manifest *v1manifest.Manifest, err error) { + // Ideally a repository check was not mandatory to simply run a program, but as it is, + // an uninitialized repository would cause a nil pointer dereference, so return an error. + if r == nil { + return false, nil, errors.New("repo is nil") + } // check cache first if r.timestamp != nil { return false, r.timestamp, nil diff --git a/pkg/repository/v1manifest/local_manifests.go b/pkg/repository/v1manifest/local_manifests.go index a7c32396b5..0d50a04224 100644 --- a/pkg/repository/v1manifest/local_manifests.go +++ b/pkg/repository/v1manifest/local_manifests.go @@ -198,9 +198,9 @@ func (ms *FsManifests) load(filename string) (string, error) { file, err := os.Open(fullPath) if err != nil { if os.IsNotExist(err) { - // Use the hardcode root.json if there is no root.json currently + // Use system root.json if none was found in the local profile directory if filename == ManifestFilenameRoot { - initRoot, err := filepath.Abs(filepath.Join(ms.profile.Root(), "bin/root.json")) + initRoot, err := filepath.Abs(filepath.Join("/usr/share/tiup/root.json")) if err != nil { return "", errors.Trace(err) }