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/components/client/main.go b/components/client/main.go index 1e03eb0560..a12d68ac2e 100644 --- a/components/client/main.go +++ b/components/client/main.go @@ -23,6 +23,7 @@ import ( "os/user" "path" + "github.com/go-git/go-billy/v5/osfs" ui "github.com/gizak/termui/v3" "github.com/gizak/termui/v3/widgets" "github.com/pingcap/tiup/pkg/environment" @@ -95,11 +96,12 @@ func connect(target string) error { if err != nil { return fmt.Errorf("can't get current user: %s", err.Error()) } - l, err := rline.New(false, "", env.HistoryFile(u)) + l, err := rline.New(false, false, false, "", env.HistoryFile(u)) if err != nil { return fmt.Errorf("can't open history file: %s", err.Error()) } - h := handler.New(l, u, os.Getenv(localdata.EnvNameInstanceDataDir), true) + dataDir := os.Getenv(localdata.EnvNameInstanceDataDir) + h := handler.New(l, u, dataDir, osfs.New(dataDir), true) if err = h.Open(context.TODO(), ep.dsn); err != nil { return fmt.Errorf("can't open connection to %s: %s", ep.dsn, err.Error()) } diff --git a/debian/.gitignore b/debian/.gitignore new file mode 100644 index 0000000000..0ba5eb5c3e --- /dev/null +++ b/debian/.gitignore @@ -0,0 +1,9 @@ +*.debhelper +*.log +*.substvars +/.debhelper/ +/.build/ +/debhelper-build-stamp +/files +/tiup/ +!/vendor/ diff --git a/debian/README.source.md b/debian/README.source.md new file mode 100644 index 0000000000..ba1788e288 --- /dev/null +++ b/debian/README.source.md @@ -0,0 +1,7 @@ +# README for Debian source package maintainers + +The file root.json was manually fetched with: + + curl -LO https://tiup-mirrors.pingcap.com/root.json + +It will need to be updated if upstream signing keys change. diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 0000000000..256428ae7f --- /dev/null +++ b/debian/changelog @@ -0,0 +1,5 @@ +tiup (1.16.3+20250909~e769cc5c) unstable; urgency=medium + + * Initial native packaging + + -- Otto Kekäläinen Wed, 19 Mar 2025 23:31:49 +0000 diff --git a/debian/ci/extra_repository.list b/debian/ci/extra_repository.list new file mode 100644 index 0000000000..dd2dca3e37 --- /dev/null +++ b/debian/ci/extra_repository.list @@ -0,0 +1,11 @@ +# These packages are still in the NEW queue +# (https://ftp-master.debian.org/new.html) and not yet in Debian. Meanwhile, get +# them from a the PPA they were uploaded to in parallel to the official Debian +# upload. +# - golang-github-asaskevich-eventbus +# - golang-github-dchest-bcrypt-pbkdf +# - golang-github-gohxs-readline +# - golang-github-jeremywohl-flatten +# - golang-github-lorenzosaino-go-sysctl +# - golang-github-pingcap-kvproto +deb [trusted=yes] https://ppa.launchpadcontent.net/otto/tidb/ubuntu questing main diff --git a/debian/control b/debian/control new file mode 100644 index 0000000000..d01dfe8fd3 --- /dev/null +++ b/debian/control @@ -0,0 +1,96 @@ +Source: tiup +Section: golang +Priority: optional +Maintainer: Debian Go Packaging Team +Uploaders: + Otto Kekäläinen , +Build-Depends: + debhelper-compat (= 13), + dh-golang, + dh-sequence-golang, + golang-any, + golang-etcd-server-dev, + golang-github-alecthomas-chroma-dev, + golang-github-appleboy-easyssh-proxy-dev, + golang-github-asaskevich-eventbus-dev, + golang-github-astroprofundis-sysinfo-dev, + golang-github-cavaliergopher-grab-dev, + golang-github-cheggaaa-pb.v3-dev, + golang-github-creasty-defaults-dev, + golang-github-dchest-bcrypt-pbkdf-dev, + golang-github-docker-go-units-dev, + golang-github-fatih-color-dev, + golang-github-gibson042-canonicaljson-go-dev, + golang-github-gizak-termui-dev, + golang-github-go-git-go-billy-dev, + golang-github-go-sql-driver-mysql-dev, + golang-github-gofrs-flock-dev, + golang-github-gohxs-readline-dev, + golang-github-golang-protobuf-1-5-dev, + golang-github-google-shlex-dev, + golang-github-google-uuid-dev, + golang-github-gorilla-mux-dev, + golang-github-jedib0t-go-pretty-dev, + golang-github-jeremywohl-flatten-dev, + golang-github-joomcode-errorx-dev, + golang-github-lorenzosaino-go-sysctl-dev, + golang-github-mattn-go-runewidth-dev, + golang-github-mattn-go-sixel-dev, + golang-github-minio-minio-go-v7-dev, + golang-github-mitchellh-colorstring-dev, + golang-github-pingcap-errors-dev, + golang-github-pingcap-failpoint-dev, + golang-github-pingcap-fn-dev, + golang-github-pingcap-kvproto-dev, + golang-github-pkg-errors-dev, + golang-github-prometheus-client-model-dev, + golang-github-prometheus-common-dev, + golang-github-prometheus-prom2json-dev, + golang-github-r3labs-diff-dev, + golang-github-relex-aini-dev, + golang-github-scaleft-sshkeys-dev, + golang-github-sergi-go-diff-dev, + golang-github-sethvargo-go-password-dev, + golang-github-shirou-gopsutil-dev, + golang-github-spf13-cobra-dev, + golang-github-spf13-pflag-dev, + golang-github-stretchr-testify-dev, + golang-github-vishvananda-netlink-dev, + golang-github-xo-dburl-dev, + golang-github-xo-tblfmt-dev, + golang-github-xo-terminfo-dev, + golang-github-xo-usql-dev, + golang-go.uber-atomic-dev, + golang-go.uber-zap-dev, + golang-golang-x-crypto-dev, + golang-golang-x-mod-dev, + golang-golang-x-sync-dev, + golang-golang-x-sys-dev, + golang-golang-x-term-dev, + golang-google-grpc-dev, + golang-gopkg-ini.v1-dev, + golang-gopkg-vmihailenco-msgpack.v2-dev, + golang-gopkg-yaml.v3-dev, + golang-sslmate-src-go-pkcs12-dev, + golang-toml-dev, +Testsuite: autopkgtest-pkg-go +Standards-Version: 4.7.2 +Vcs-Browser: https://salsa.debian.org/go-team/packages/tiup +Vcs-Git: https://salsa.debian.org/go-team/packages/tiup.git +Homepage: https://github.com/pingcap/tiup +XS-Go-Import-Path: github.com/pingcap/tiup + +Package: tiup +Section: utils +Architecture: any +Depends: + ${misc:Depends}, + ${shlibs:Depends}, +Static-Built-Using: + ${misc:Static-Built-Using}, +Description: Component manager for TiDB + TiUP is a tool designed to manage TiDB components, providing an easy way to + install, update, and maintain various components of the TiDB ecosystem. It + simplifies the process of setting up and managing TiDB clusters, making it + accessible for both developers and administrators. With TiUP, you can quickly + deploy and scale TiDB clusters, ensuring high availability and performance. diff --git a/debian/copyright b/debian/copyright new file mode 100644 index 0000000000..f49ad96221 --- /dev/null +++ b/debian/copyright @@ -0,0 +1,60 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Source: https://github.com/pingcap/tiup +Upstream-Name: PingCAP +Upstream-Contact: https://github.com/pingcap/tiup/issues + +Files: * +Copyright: 2020-2025 PingCAP +License: Apache-2.0 + +Files: debian/* +Copyright: + 2025 Otto Kekäläinen +License: Apache-2.0 +Comment: Debian packaging is licensed under the same terms as upstream + +Files: debian/vendor/github.com/zaf/temp/* +Copyright: 2012 The Go Authors, 2017 Lefteris Zafiris +License: BSD-3-Clause + +License: Apache-2.0 + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + . + http://www.apache.org/licenses/LICENSE-2.0 + . + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +Comment: + On Debian systems, the complete text of the Apache version 2.0 license + can be found in "/usr/share/common-licenses/Apache-2.0". + +License: BSD-3-Clause + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + . + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + . + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + . + 3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + . + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/debian/gitlab-ci.yml b/debian/gitlab-ci.yml new file mode 100644 index 0000000000..8296696509 --- /dev/null +++ b/debian/gitlab-ci.yml @@ -0,0 +1,21 @@ +# This is a template from +# https://salsa.debian.org/salsa-ci-team/pipeline/-/raw/master/recipes/salsa-ci.yml +# +# If this pipeline is not running at after committing and pushing this file, +# ensure that https://salsa.debian.org/%{project_path}/-/settings/ci_cd has in +# field "CI/CD configuration file" filename "debian/salsa-ci.yml", the filename +# is the same as of this file, and duplicate files with similar contents but +# different filenames have been cleaned away. +# +# Feel free disable and enable tests to find a good balance between extensive +# coverage and having a consistently green pipeline where failures are rare +# enough that they are always investigated and addressed. For documentation +# please read https://salsa.debian.org/salsa-ci-team/pipeline +--- +include: + - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/recipes/debian.yml + +# @TODO: Remove this before finalizing MR and uploading +variables: + SALSA_CI_EXTRA_REPOSITORY: debian/ci/extra_repository.list + SALSA_CI_DISABLE_REPROTEST: 1 diff --git a/debian/lrc.config b/debian/lrc.config new file mode 100644 index 0000000000..702432c848 --- /dev/null +++ b/debian/lrc.config @@ -0,0 +1,2 @@ +# Use license name and identified 'MIT* instead of 'Expat' +--spdx diff --git a/debian/root.json b/debian/root.json new file mode 100644 index 0000000000..78e85862f0 --- /dev/null +++ b/debian/root.json @@ -0,0 +1 @@ +{"signatures":[{"keyid":"a61b695e2b86097d993e94e99fd15ec6d8fc8e9522948c9ff21c2f2c881093ae","sig":"jDFZCtE+VfJtpXJk5m5/TwIOpvkJe08+HWKCfPAhERKlqrGPAAdgLnXqftzZhcmDSR3uP2qxwqAZSO/ZUrWsie7XT5Xutva9SL//UXIk2N7RwS/PjN4AcaJydm4+V37h/sowlFz3nxeKobj21wpUAw/KxcY7mqu+XhLiPM2f5yhuGBC6MeoqBN5tlqCGoadHkGYibqXNS/1aBAtk/vCrCv86PRL3yzpfpKUB3ElyJJaQR2zUr5bqPNen31/qM2xxGp/amN7UxXddtAPGfZ2CNI959puyoTXwRULXS8J74BM8Lg7TAkDr+n9hkjmXi3MNhulPb5luPJ/eGQYw9l/vnw=="},{"keyid":"b128ee6a42e2665bd45aa2fa4a7b6e098cfedb3911154f300634b2c056214b9e","sig":"sa9m4ftMfe9PsnLA2pgUsTdv48tyJlSo2g0NYAnGBt81P5Ky+dYdWoplsJIgsvgF5rjd1JDt6eybh/ozlWKvyAG+ge8yWQkiaBMVofSTVpm1OovuLQ015NP78lfVSqUb4MaFBgfoqChszAk7Kx/av0DymLSiN7qhFsxf68naau9R83Ao2RSTc8QxJeTqoiJvgVRc9ILHoaVjhqEixGfcLPUKG3gLEyYglZSk3F1ixIa29/QHj2B7ICzS4Hceyk1RKKIUCcX3zF+eh29tZdGU7sZPnKlt2svzAfy1xiMUJikugQBucvvFox/txU2Tp2+rP3qgP6poZ/j1uxI9JaDaUQ=="},{"keyid":"9b3cea98f6f23cc11813b12d0526a1b6cfb3761008f0882c9caa8db742d63002","sig":"Bsn2hbGAZH9kpEJx5za7XMdtJI/QSlKDy00JDo8/Jdnjqp1AVMhKbbl6KedNHfwb5OPmohJzT6ukASUqTzCcMPjJAZCKPJWDS9vrrtc9Nqvdfn2kIYj41pLNOdFBiKa79x6Rio+jLdL81Nt8T0d/izMfGO2vJ+LkZElUGG8VDj19UWRKKZPp/V3oFBfGIRemJWbDBsTt9cVwNa9ed3OXS01qS4/asrd9l19BQ+tZfZ+dXzDuMlv1THJNWB5UAdv0Ku7lSeV87oGOVMD4gkfdWAzFioT+hwXF8f3JUobNskyZIJTMqNPHST+ACJgQjgLH0FkN8xjw+YYv/ktgoZrSIA=="},{"keyid":"2001b18089c9a865cebee793dbc23f9b1f5ce457f96b8d0b2c0909c26b00c643","sig":"Ca+w4Cf7avansD74a014IUJBobcCz+X8aIbmWma9Ch8Ccdksedgf6MEWi0fHUJXloLauLP/I56PzhzfvB+0+YgO9lMkECkEcjed2NC0YCuRDZ07q8ndsZPQ94KKg7BWXo+1xXkDz5W7AKpFYdxYnAWfVSpvc/iceTd3bX+3vz4bs/FiyZtFig6rTWdS+gKrGTqFJ//AOP+9iC3kheSEZXlXV2HS0EB8s461PqSpdMLcXBughRSIzbFHPid+5Nch0zJzCIuLXjZE7n2w1M+9j5eyF9USga5cjQiXIJ0LTINSzFkPjuUk3PzWYkNobGr9fxlrePzUHlzFEGHz8kxG0gQ=="},{"keyid":"545c31fd615bbaa4c5424509a9305eb280e019996b043a576dc12b758aa0890a","sig":"ftsm8N54OgIHhFrIKDnCrocY+rxCzZBgjyX37Ixm2vJifk3RhXA2cUEQepqFcRKH1oEmt90lzV6VWqy1EUUzYJSGA6edq2tix6nntcRgDJkIqCAPViBgaR1OCKFhf/2ldRvnjtuOkG6h+5qAmuAB51DdDHGjHW+DKvxflTK7p59cSZLvmJImPWYTz2qF1U+IKMSb7glYVqXUsFKUq5GP7gawE8Ez/2N0bMkD9s6GPtErCGxIkH2x1/5eYLVlbdGwy/PsW1/cE2uRAGCsPC6NknlWXYHFXYVgJWJ16H9H7Ih2NfkizBOwhWkVr+VPLkXllo9HutxSkNl2dEk4rAzzDQ=="}],"signed":{"_type":"root","expires":"2022-05-26T11:18:30+08:00","roles":{"index":{"keys":{"7fce7ec4f9c36d51dec7ec96065bb64958b743e46ea8141da668cd2ce58a9e61":{"keytype":"rsa","keyval":{"public":"-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAn5kVA7MlBfSe7EBaExjl\nKbwoDkn1aYi74s29mFgtRo8nejbrVvZQMCIUhvKc0pFa/l9JD/QY6/nAOCE1lpzi\nwwNkSntfOo3p3HQIR+Ut7hZ4Sxfe/5JagGo3LQ+Hd3EJWUxyEfQ/Bff07F3XAbqM\n5+cKNrdsKWZJcPiJDW621qGwCx52f+gzl9bnFe4/hx34OUgirwqh5DS+LhIO+/yt\nbOiN1AyjQKlnb8lUnblElS4Njd+F4io5VzSrZYi2+4AbTkO6wLwbsWHMzXfv9qwn\nvllufOHpB6EwiQ/xBOMuvJJymHnZvs8AH4SuydQIXLaJuv1ysFaBs0KB/ktbakSK\nLwIDAQAB\n-----END PUBLIC KEY-----\n"},"scheme":"rsassa-pss-sha256"}},"threshold":1,"url":"/index.json"},"root":{"keys":{"2001b18089c9a865cebee793dbc23f9b1f5ce457f96b8d0b2c0909c26b00c643":{"keytype":"rsa","keyval":{"public":"-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1LB2sQGelCEaKTKPzdim\n5V0RrdDOyZTSsZlWjzqZQn7lIRKG9Yjah//ReBdy3gmTwbZWUYzGFeclS+1+H05f\nvvxJUN1ttNgy6xsKql6s1ZhdwoBLbkjTqHjbRRQ2+fMJQdhusb1TXEP5Vut2jlyo\nSoGSa9mDC0VbGW9Xs/4HqfyH6m4dV6GeFYwDUX0ok6l6DHk28UIFyieKITFNkrKv\n5xoUPS3P49tX7wprXiFBKiP1Tr72O+GSTBFXuUhPASBVCXoxj7g5fB024P464ku/\nTHECfX1F5q7htz2zkgn7V9A9kedASwoqbrC5glHXfrfiQOctHkyKaGLswWe+8OAp\n5wIDAQAB\n-----END PUBLIC KEY-----\n"},"scheme":"rsassa-pss-sha256"},"545c31fd615bbaa4c5424509a9305eb280e019996b043a576dc12b758aa0890a":{"keytype":"rsa","keyval":{"public":"-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxzlxJStPfdjMERTUs2GH\nMKMPAflgMTId3rhKsyLGAoRraAE3+crZEkXz+sEgCSW7590qDofcZYFeS9QOebD2\nI1/PYbDqMOwWkRSta6BRJyhgGKmG8QuxiYQQEQSgBhTQap3jnxiduXiZ+6uTiNkS\n44/Z12GN+vXLDLCVBlxFZx2Am9QFVCyP7f9Dxj0EkaVKRGu6+utjaWGyQLq5splk\nNbFvMLYJLkzrk8dzLwr1E85NRCAVLnRJR4fYllglJmJi6laHdOgXf9GOL1vQ/qUh\nRXqYkGiZ/15vurMMyUaIdzLY95XHw6vsjOwV9kBs8z/cxBVLxpNWUiOBsfDpmBc3\nCwIDAQAB\n-----END PUBLIC KEY-----\n"},"scheme":"rsassa-pss-sha256"},"9b3cea98f6f23cc11813b12d0526a1b6cfb3761008f0882c9caa8db742d63002":{"keytype":"rsa","keyval":{"public":"-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsOgQkwLOh31QV9OpbO9v\n6o83durJFGPOnVXZiab83pKaSk7HEK9WzXBq0BaPvtFwSfROVdpgtopri5lZi+uH\naMKLUn5F8XRnSMl/7m5vM4XpZZYa4aQId4TWdbFtTu31eHGZ3eEC5nDRJ5NhZOJd\nKLFBu/xmxrh/eNZt4QbdWLZayjHnzyoy5AnfNTR6nJgPAv+rBOqyqT/r14q4Pngh\n3z0I3pNFr5qmxsp013XV+kgOW1F7zT7IMU8xRIgo85UWUNhax0/bjY/2NI1Z+WjR\nyhZmUBMVYWvfw97xDUrvBvrJxZPgg0lGvxJC6LF2dM7wgLaNx9khT6HMBVxjxLMs\nDQIDAQAB\n-----END PUBLIC KEY-----\n"},"scheme":"rsassa-pss-sha256"},"a61b695e2b86097d993e94e99fd15ec6d8fc8e9522948c9ff21c2f2c881093ae":{"keytype":"rsa","keyval":{"public":"-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnayxhw6KeoKK+Ax9RW6v\n66YjrpRpGLewLmSSAzJGX8nL5/a2nEbXbeF9po265KcBSFWol8jLBsmG56ruwwxp\noWWhJPncqGqy8wMeRMmTf7ATGa+tk+To7UAQD0MYzt7rRlIdpqi9Us3J6076Z83k\n2sxFnX9sVflhOsotGWL7hmrn/CJWxKsO6OVCoqbIlnJV8xFazE2eCfaDTIEEEgnh\nLIGDsmv1AN8ImUIn/hyKcm1PfhDZrF5qhEVhfz5D8aX3cUcEJw8BvCaNloXyHf+y\nDKjqO/dJ7YFWVt7nPqOvaEkBQGMd54ETJ/BbO9r3WTsjXKleoPovBSQ/oOxApypb\nNQIDAQAB\n-----END PUBLIC KEY-----\n"},"scheme":"rsassa-pss-sha256"},"b128ee6a42e2665bd45aa2fa4a7b6e098cfedb3911154f300634b2c056214b9e":{"keytype":"rsa","keyval":{"public":"-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0kgU3v3SxYzm5J6P+GPP\nmy6toBnKYtTViAVmpUJiIEjdZ9NLpoJU0na9q0CD8sIgo2Js/W/owJUvSj6rm8us\nsu/Ve5KsoJN6zca2am1uZ5IKnc48i0mCv76WXawCxM+NFGqSCMJcltlhj3fC/GDS\ngu+BiIbrgR1PgJf6Jk6l7uMJdN3TL6JJQcEC4lz+2hj5zoVNYkq06ZC79j2tPDCI\nkTAYGF/TAAVLH08/kGH5ZeRPlVKJ7cwW3OniLM5NeFnS8+shRNb6AYr7xju3Ikbw\nDo14ipIghBI0iAxn6Lvr/iilc7TM7RWJ4OiTrmK3SQSJ+U6H2N2/I5OGEHBEKzbA\nOQIDAQAB\n-----END PUBLIC KEY-----\n"},"scheme":"rsassa-pss-sha256"}},"threshold":3,"url":"/root.json"},"snapshot":{"keys":{"8660a9f40687fb33e6f8ad563f21ee81b9ce7b91c90827cc7ae2416c5e0e94e9":{"keytype":"rsa","keyval":{"public":"-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqTZx29eJR5EumjqM4YTb\nFlKbim1GNYmtbCLH51BbU2lt46ddmfGvtGsxTD3mIZ/GEHVFv6Aei3xx5nIfhGP0\nrG78JRz394uU8Pd62DiIFWYizr5o+ZBZu29D2YK5ZtxoLFpgt0ibnINK2NcesDC8\nSqfIUbMiQFT6yB/MYD275SjfRGHOeYTPmKdjMJrhLL2cfIPYnQ0QFYIyMvXBG1Fj\nU0rc9UclYQHh9YheIDVYI9YCo/DWP3KFfRJpoTjQRGoPSK9TXcpCAEzQpEG3jOek\n9PdV9Ol6/O8JbrFwXWF3LhkUThg+zCjV4qHtP4oqp5QCqzTQTXGQ9qxWUSlHi4Eu\nIwIDAQAB\n-----END PUBLIC KEY-----\n"},"scheme":"rsassa-pss-sha256"}},"threshold":1,"url":"/snapshot.json"},"timestamp":{"keys":{"66d4ea1da00076c822a6e1b4df5eb1e529eb38f6edcedff323e62f2bfe3eaddd":{"keytype":"rsa","keyval":{"public":"-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzTgV5iKhMnunUDxt4PB\npYqTMPaJN/ZdOOsP6cS3DeCE/EcYGfgCjvP7KD3gjG98VDBTVcuwZClSy+/zvHhV\nIq7VWu+yxQL5c6oa1xpCyHoA96JiLIDPhmqEdscdRybcRQ2CYywzKA8jSwEQCnEK\nc8a74ceY352l/MEcOem0+AtKrOjqcjbXCayDwC9yTg/c78bkp+4T8AhSWgt6Tlrt\nY8jLE7zwojFtIYtMwobWRIW2O3nJDXiSBbTPG3M9kF1G43INshSdBcuq5Tmy8lpE\n/XiG/E7+hP63Hm+KAcdvl553Zs7pLhAZxV0kqlApqRRwhscw+JQci8sVONun5t9t\nNwIDAQAB\n-----END PUBLIC KEY-----\n"},"scheme":"rsassa-pss-sha256"}},"threshold":1,"url":"/timestamp.json"}},"spec_version":"0.1.0","version":2}} \ No newline at end of file diff --git a/debian/rules b/debian/rules new file mode 100755 index 0000000000..f87d67bede --- /dev/null +++ b/debian/rules @@ -0,0 +1,31 @@ +#!/usr/bin/make -f + +export DH_VERBOSE = 1 + +# Generic hardening of binaries +export DEB_BUILD_MAINT_OPTIONS = hardening=+all +DPKG_EXPORT_BUILDFLAGS = 1 +include /usr/share/dpkg/buildflags.mk + +export DH_GOLANG_INSTALL_EXTRA := embed/examples/ embed/templates/ + +# Extend GOPATH to include the vendor directory from usql package +export GOPATH := $(CURDIR)/debian/.build/upstream:/usr/share/gocode/src/github.com/xo/usql/vendor + +# @TODO: Ideally all dependencies would be Debian packages and this source +# package would not need to vend any of its dependencies like this +execute_before_dh_auto_configure: + cp -av debian/vendor ./ + +execute_after_dh_clean: + rm -rfv vendor/ + +override_dh_auto_test: + @echo "Skipping post-build Go tests because of too many failures" + +override_dh_auto_install: + dh_auto_install -- --no-source + (cd debian/tiup/usr/bin/ && for x in *; do mv $$x tiup-$$x; done; mv tiup-tiup tiup) + +%: + dh $@ --builddirectory=debian/.build/upstream --buildsystem=golang diff --git a/debian/source/format b/debian/source/format new file mode 100644 index 0000000000..89ae9db8f8 --- /dev/null +++ b/debian/source/format @@ -0,0 +1 @@ +3.0 (native) diff --git a/debian/tiup.install b/debian/tiup.install new file mode 100644 index 0000000000..b4b232138b --- /dev/null +++ b/debian/tiup.install @@ -0,0 +1 @@ +debian/root.json usr/share/tiup/ diff --git a/debian/tiup.lintian-overrides b/debian/tiup.lintian-overrides new file mode 100644 index 0000000000..b2e31e04fc --- /dev/null +++ b/debian/tiup.lintian-overrides @@ -0,0 +1,20 @@ +# All of these spelling errors are inherited from dependencies and not issues in +# this TiUP package itself: +# grep -r -i -w -E 'hexidecimal|octects|userA|wtH|ment' +# golang.org/x/crypto@v0.23.0/cryptobyte/asn1.go: b.err = fmt.Errorf("cryptobyte: high-tag number identifier octects not supported: 0x%x", tag) +# golang.org/x/net@v0.25.0/html/testdata/webkit/tests1.dat: +# golang.org/x/net@v0.25.0/webdav/internal/xml/marshal_test.go: Directive("DOCTYPE doc [ '> ]"), +# golang.org/x/text@v0.15.0/unicode/runenames/tables9.0.0.go: "MENT-WALLPLANE BEND LARGESIGNWRITING MOVEMENT-WALLPLANE CORNER SMALLSIGN" + +# github.com/gorilla/mux@v1.8.0/doc.go: amw.tokenUsers["aaaaaaaa"] = "userA" +# github.com/gorilla/mux@v1.8.0/README.md: amw.tokenUsers["aaaaaaaa"] = "userA" +# github.com/gorilla/mux@v1.8.0/example_authentication_middleware_test.go: amw.tokenUsers["aaaaaaaa"] = "userA" +# github.com/!burnt!sushi/toml@v1.2.1/lex.go: lx.errorf("not a hexidecimal number: '%s%c'", lx.current(), r) +# google.golang.org/genproto@v0.0.0-20240401170217-c3f982113cda/googleapis/genomics/v1/references.pb.go: // checksum is computed by sorting all lower case hexidecimal string +# google.golang.org/genproto@v0.0.0-20240401170217-c3f982113cda/googleapis/devtools/containeranalysis/v1beta1/attestation/attestation.pb.go: // 160-bit fingerprint, expressed as a 40 character hexidecimal string. See +tiup: spelling-error-in-binary hexidecimal hexadecimal [usr/bin/*] +tiup: spelling-error-in-binary ment meant [usr/bin/*] +tiup: spelling-error-in-binary octects octets [usr/bin/*] +tiup: spelling-error-in-binary userA users [usr/bin/*] +tiup: spelling-error-in-binary wtH with [usr/bin/*] +# Prevent Lintian from nagging about typos in this file itself +spelling-in-override-comment spelling-error-in-binary * [usr/share/lintian/overrides/tiup:*] diff --git a/debian/vendor/README.md b/debian/vendor/README.md new file mode 100644 index 0000000000..059468caef --- /dev/null +++ b/debian/vendor/README.md @@ -0,0 +1,32 @@ +# Vendoring dependencies + +Debian builds are hermetic and run offline, so all dependencies need to be +available in Debian archives or vendored in the package sources. + +Ideally all dependencies would be available from the Debian archives. For those +rare cases when they are not, and assuming the extra dependencies are small, +rare and obscure enough, they may be vended as part of the Debian source package +itself. + +The list below used to be much longer, but as more and more Go libraries get +into Debian the list has shrunk to just one. + +```bash +# Run this from project root directory +go mod vendor -v + +# Download only the dependencies that are not yet available in Debian +# +# Do not package zaf/temp, as it will be removed completely as soon as upstream +# updates their usql dependency: https://github.com/pingcap/tiup/issues/2588 +MODULES=( + "github.com/zaf/temp" +) + +# Loop through each module +for MODULE in "${MODULES[@]}" +do + mkdir -p debian/vendor/"$MODULE" + cp --archive --update --verbose vendor/"$MODULE"/* debian/vendor/"$MODULE"/ +done +``` diff --git a/debian/vendor/github.com/zaf/temp/LICENSE b/debian/vendor/github.com/zaf/temp/LICENSE new file mode 100644 index 0000000000..4bb10cad30 --- /dev/null +++ b/debian/vendor/github.com/zaf/temp/LICENSE @@ -0,0 +1,29 @@ +Copyright (c) 2012 The Go Authors. +Copyright (c) 2017 Lefteris Zafiris. + All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/debian/vendor/github.com/zaf/temp/Readme.md b/debian/vendor/github.com/zaf/temp/Readme.md new file mode 100644 index 0000000000..7ec137534d --- /dev/null +++ b/debian/vendor/github.com/zaf/temp/Readme.md @@ -0,0 +1,31 @@ +# temp +A package to create temporary files and directories based on the ioutil Go package +-- + import "github.com/zaf/temp" + + +## Usage + +#### func Dir + +```go +func Dir(dir, prefix string) (name string, err error) +``` +Dir creates a new temporary directory in the directory dir with a name beginning +with prefix and returns the path of the new directory. If dir is the empty +string, Dir uses the default directory for temporary files (see os.TempDir). +Multiple programs calling Dir simultaneously will not choose the same directory. +It is the caller's responsibility to remove the directory when no longer needed. + +#### func File + +```go +func File(dir, prefix, extension string) (f *os.File, err error) +``` +File creates a new temporary file with the provided extension in the directory +dir with a name beginning with prefix, opens the file for reading and writing, +and returns the resulting *os.File. If dir is the empty string, File uses the +default directory for temporary files (see os.TempDir). Multiple programs +calling File simultaneously will not choose the same file. The caller can use +f.Name() to find the pathname of the file. It is the caller's responsibility to +remove the file when no longer needed. diff --git a/debian/vendor/github.com/zaf/temp/temp.go b/debian/vendor/github.com/zaf/temp/temp.go new file mode 100644 index 0000000000..3803d1e9e4 --- /dev/null +++ b/debian/vendor/github.com/zaf/temp/temp.go @@ -0,0 +1,111 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Based on ioutil Go package, modified to add +// file extension option to File() and renamed to temp +// Lefteris Zafiris 2017 + +package temp + +import ( + "os" + "path/filepath" + "strconv" + "sync" + "time" +) + +// Random number state. +// We generate random temporary file names so that there's a good +// chance the file doesn't exist yet - keeps the number of tries in +// TempFile to a minimum. +var rand uint32 +var randmu sync.Mutex + +func reseed() uint32 { + return uint32(time.Now().UnixNano() + int64(os.Getpid())) +} + +func nextSuffix() string { + randmu.Lock() + r := rand + if r == 0 { + r = reseed() + } + r = r*1664525 + 1013904223 // constants from Numerical Recipes + rand = r + randmu.Unlock() + return strconv.Itoa(int(1e9 + r%1e9))[1:] +} + +// File creates a new temporary file with the provided extension +// in the directory dir with a name beginning with prefix, +// opens the file for reading and writing, and returns the resulting *os.File. +// If dir is the empty string, File uses the default directory +// for temporary files (see os.TempDir). +// Multiple programs calling File simultaneously +// will not choose the same file. The caller can use f.Name() +// to find the pathname of the file. It is the caller's responsibility +// to remove the file when no longer needed. +func File(dir, prefix, extension string) (f *os.File, err error) { + if dir == "" { + dir = os.TempDir() + } + + nconflict := 0 + for i := 0; i < 10000; i++ { + name := filepath.Join(dir, prefix+nextSuffix()) + if extension != "" { + name += "." + extension + } + f, err = os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600) + if os.IsExist(err) { + if nconflict++; nconflict > 10 { + randmu.Lock() + rand = reseed() + randmu.Unlock() + } + continue + } + break + } + return +} + +// Dir creates a new temporary directory in the directory dir +// with a name beginning with prefix and returns the path of the +// new directory. If dir is the empty string, Dir uses the +// default directory for temporary files (see os.TempDir). +// Multiple programs calling Dir simultaneously +// will not choose the same directory. It is the caller's responsibility +// to remove the directory when no longer needed. +func Dir(dir, prefix string) (name string, err error) { + if dir == "" { + dir = os.TempDir() + } + + nconflict := 0 + for i := 0; i < 10000; i++ { + try := filepath.Join(dir, prefix+nextSuffix()) + err = os.Mkdir(try, 0700) + if os.IsExist(err) { + if nconflict++; nconflict > 10 { + randmu.Lock() + rand = reseed() + randmu.Unlock() + } + continue + } + if os.IsNotExist(err) { + if _, err := os.Stat(dir); os.IsNotExist(err) { + return "", err + } + } + if err == nil { + name = try + } + break + } + return +} diff --git a/pkg/cluster/manager/upgrade.go b/pkg/cluster/manager/upgrade.go index f56b61dde7..100dfa9442 100644 --- a/pkg/cluster/manager/upgrade.go +++ b/pkg/cluster/manager/upgrade.go @@ -334,7 +334,7 @@ This operation will upgrade %s %s cluster %s (with a concurrency of %d) to %s:%s }() select { case <-time.After(restartTimeout): - fmt.Printf("\nTimeout, continueing\n") + fmt.Printf("\nTimeout, continuing\n") case <-ch: } } diff --git a/pkg/environment/env.go b/pkg/environment/env.go index 69d01363dc..0ee67885f7 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 ) // Mirror return mirror of tiup. @@ -81,6 +85,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() @@ -148,6 +159,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 7cce7a49c4..a6d82afb78 100644 --- a/pkg/exec/run.go +++ b/pkg/exec/run.go @@ -173,6 +173,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/insight/process.go b/pkg/insight/process.go index 82fd71780d..24c9fe56d5 100644 --- a/pkg/insight/process.go +++ b/pkg/insight/process.go @@ -162,7 +162,10 @@ func (proc_stat *ProcessStat) getProcessStat(proc *process.Process) { proc_stat.Name, _ = proc.Name() proc_stat.Exec, _ = proc.Exe() proc_stat.Cmdline, _ = proc.Cmdline() - proc_stat.Status, _ = proc.Status() + statuses, _ := proc.Status() + if len(statuses) > 0 { + proc_stat.Status = statuses[0] + } proc_stat.StartTime, _ = getProcStartTime(proc) proc_stat.CPUTimes, _ = proc.Times() proc_stat.Memory, _ = proc.MemoryInfo() diff --git a/pkg/insight/process_linux.go b/pkg/insight/process_linux.go index 9c8083c3ab..9bea4c2f69 100644 --- a/pkg/insight/process_linux.go +++ b/pkg/insight/process_linux.go @@ -5,23 +5,15 @@ package insight import ( "log" - "os" - "strconv" - "strings" "github.com/shirou/gopsutil/process" ) func getProcStartTime(proc *process.Process) (float64, error) { - statPath := GetProcPath(strconv.Itoa(int(proc.Pid)), "stat") - contents, err := os.ReadFile(statPath) + createTimeMs, err := proc.CreateTime() if err != nil { - log.Fatal(err) + log.Fatal(err) // Matches existing error handling behavior return 0, err } - fields := strings.Fields(string(contents)) - if startTime, err := strconv.ParseFloat(fields[21], 64); err == nil { - return startTime / float64(process.ClockTicks), err - } - return 0, err + return float64(createTimeMs) / 1000.0, nil // Convert milliseconds to seconds } diff --git a/pkg/repository/mirror.go b/pkg/repository/mirror.go index 90309a29f2..a0a381a109 100644 --- a/pkg/repository/mirror.go +++ b/pkg/repository/mirror.go @@ -420,7 +420,7 @@ func (l *httpMirror) Publish(manifest *v1manifest.Manifest, info model.Component defer resp.Body.Close() if resp.StatusCode >= 300 { - return errors.Errorf("error on uplaod tarball, server returns %d", resp.StatusCode) + return errors.Errorf("error on upload tarball, server returns %d", resp.StatusCode) } } diff --git a/pkg/repository/v1_repository.go b/pkg/repository/v1_repository.go index e5fd6588c3..877285be3a 100644 --- a/pkg/repository/v1_repository.go +++ b/pkg/repository/v1_repository.go @@ -541,6 +541,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) }