From b5dcc3c7812aa35588584ad4d6f3ca81ecd1942d Mon Sep 17 00:00:00 2001 From: Tiago Ilieve Date: Wed, 27 Dec 2023 06:47:55 -0300 Subject: [PATCH] Add support for user-specific executable files --- main.go | 1 + tools/asset_test.go | 402 ++++++++++++++++++++------------------------ tools/tools.go | 11 +- tools/user.go | 28 +++ tools/user_test.go | 11 ++ 5 files changed, 230 insertions(+), 223 deletions(-) create mode 100644 tools/user.go create mode 100644 tools/user_test.go diff --git a/main.go b/main.go index 2f03c90..d913b1a 100644 --- a/main.go +++ b/main.go @@ -22,6 +22,7 @@ func exit(msg string) { func run(name string) { tool := &tools.Tool{ Name: name, + User: &tools.UserOS{}, } err := tool.SetURL() diff --git a/tools/asset_test.go b/tools/asset_test.go index 0c75675..97ba3d7 100644 --- a/tools/asset_test.go +++ b/tools/asset_test.go @@ -16,325 +16,283 @@ func TestAssetTestSuite(t *testing.T) { func (s *AssetTestSuite) TestDestination() { table := []struct { - tool *Tool + name string dest string }{ { - tool: &Tool{ - Name: Bat, - }, + name: Bat, dest: "/usr/local/bin/bat", }, { - tool: &Tool{ - Name: Bottom, - }, + name: Bottom, dest: "/usr/local/bin/btm", }, { - tool: &Tool{ - Name: Cloudflared, - }, + name: Cloudflared, dest: "/usr/local/bin/cloudflared", }, { - tool: &Tool{ - Name: Flyctl, - }, + name: Flyctl, dest: "/usr/local/bin/flyctl", }, { - tool: &Tool{ - Name: K9s, - }, + name: K9s, dest: "/usr/local/bin/k9s", }, { - tool: &Tool{ - Name: UPX, - }, + name: UPX, dest: "/usr/local/bin/upx", }, { - tool: &Tool{ - Name: Xh, - }, + name: Xh, dest: "/usr/local/bin/xh", }, { - tool: &Tool{ - Name: Yj, - }, + name: Yj, dest: "/usr/local/bin/yj", }, } for _, tt := range table { - tt.tool.SetAsset() - s.Equal(tt.dest, tt.tool.Asset.Destination) + tool := &Tool{ + User: &UserMock{}, + } + tool.Name = tt.name + tool.SetAsset() + s.Equal(tt.dest, tool.Asset.Destination) } } func (s *AssetTestSuite) TestIsBinary() { table := []struct { - tool *Tool - arch string - os string - binary bool + name string + arch string + os string + version string + binary bool }{ { - tool: &Tool{ - Name: Bat, - Version: "v0.18.3", - }, - arch: "amd64", - os: "linux", - binary: false, - }, - { - tool: &Tool{ - Name: Bottom, - Version: "0.6.4", - }, - arch: "amd64", - os: "linux", - binary: false, - }, - { - tool: &Tool{ - Name: Cloudflared, - Version: "2021.11.0", - }, - arch: "amd64", - os: "darwin", - binary: false, - }, - { - tool: &Tool{ - Name: Cloudflared, - Version: "2021.11.0", - }, - arch: "amd64", - os: "linux", - binary: true, - }, - { - tool: &Tool{ - Name: Flyctl, - Version: "v0.0.450", - }, - arch: "amd64", - os: "linux", - binary: false, - }, - { - tool: &Tool{ - Name: K9s, - Version: "v0.25.4", - }, - arch: "amd64", - os: "linux", - binary: false, - }, - { - tool: &Tool{ - Name: UPX, - Version: "v3.96", - }, - arch: "amd64", - os: "linux", - binary: false, - }, - { - tool: &Tool{ - Name: Xh, - Version: "v0.14.0", - }, - arch: "amd64", - os: "linux", - binary: false, - }, - { - tool: &Tool{ - Name: Yj, - Version: "v5.0.0", - }, - arch: "amd64", - os: "linux", - binary: true, + name: Bat, + arch: "amd64", + os: "linux", + version: "v0.18.3", + binary: false, + }, + { + name: Bottom, + arch: "amd64", + os: "linux", + version: "0.6.4", + binary: false, + }, + { + name: Cloudflared, + arch: "amd64", + os: "darwin", + version: "2021.11.0", + binary: false, + }, + { + name: Cloudflared, + arch: "amd64", + os: "linux", + version: "2021.11.0", + binary: true, + }, + { + name: Flyctl, + arch: "amd64", + os: "linux", + version: "v0.0.450", + binary: false, + }, + { + name: K9s, + arch: "amd64", + os: "linux", + version: "v0.25.4", + binary: false, + }, + { + name: UPX, + arch: "amd64", + os: "linux", + version: "v3.96", + binary: false, + }, + { + name: Xh, + arch: "amd64", + os: "linux", + version: "v0.14.0", + binary: false, + }, + { + name: Yj, + arch: "amd64", + os: "linux", + version: "v5.0.0", + binary: true, }, } for _, tt := range table { - tt.tool.SetRuntime(tt.arch, tt.os) - tt.tool.SetAsset() - s.Equal(tt.binary, tt.tool.Asset.IsBinary, "", tt.tool.Name, tt.arch, tt.os) + tool := &Tool{ + User: &UserMock{}, + } + tool.Name = tt.name + tool.Version = tt.version + tool.SetRuntime(tt.arch, tt.os) + tool.SetAsset() + s.Equal(tt.binary, tool.Asset.IsBinary, "", tool.Name, tt.arch, tt.os) } } func (s *AssetTestSuite) TestName() { table := []struct { - tool *Tool - arch string - os string - name string + name string + arch string + os string + version string + filename string }{ { - tool: &Tool{ - Name: Bat, - Version: "v0.18.3", - }, - arch: "amd64", - os: "linux", - name: "bat-v0.18.3-x86_64-unknown-linux-gnu.tar.gz", - }, - { - tool: &Tool{ - Name: Bottom, - Version: "0.6.4", - }, - arch: "amd64", - os: "linux", - name: "bottom_x86_64-unknown-linux-gnu.tar.gz", - }, - { - tool: &Tool{ - Name: Cloudflared, - Version: "2021.11.0", - }, - arch: "amd64", - os: "linux", - name: "cloudflared-linux-amd64", - }, - { - tool: &Tool{ - Name: Flyctl, - Version: "v0.0.450", - }, - arch: "amd64", - os: "linux", - name: "flyctl_0.0.450_Linux_x86_64.tar.gz", - }, - { - tool: &Tool{ - Name: K9s, - Version: "v0.25.4", - }, - arch: "amd64", - os: "linux", - name: "k9s_Linux_x86_64.tar.gz", - }, - { - tool: &Tool{ - Name: UPX, - Version: "v3.96", - }, - arch: "amd64", - os: "linux", - name: "upx-3.96-amd64_linux.tar.xz", - }, - { - tool: &Tool{ - Name: Xh, - Version: "v0.14.0", - }, - arch: "amd64", - os: "linux", - name: "xh-v0.14.0-x86_64-unknown-linux-musl.tar.gz", - }, - { - tool: &Tool{ - Name: Yj, - Version: "v5.0.0", - }, - arch: "amd64", - os: "linux", - name: "yj-linux", + name: Bat, + arch: "amd64", + os: "linux", + version: "v0.18.3", + filename: "bat-v0.18.3-x86_64-unknown-linux-gnu.tar.gz", + }, + { + name: Bottom, + arch: "amd64", + os: "linux", + version: "0.6.4", + filename: "bottom_x86_64-unknown-linux-gnu.tar.gz", + }, + { + name: Cloudflared, + arch: "amd64", + os: "linux", + version: "2021.11.0", + filename: "cloudflared-linux-amd64", + }, + { + name: Flyctl, + arch: "amd64", + os: "linux", + version: "v0.0.450", + filename: "flyctl_0.0.450_Linux_x86_64.tar.gz", + }, + { + name: K9s, + arch: "amd64", + os: "linux", + version: "v0.25.4", + filename: "k9s_Linux_x86_64.tar.gz", + }, + { + name: UPX, + arch: "amd64", + os: "linux", + version: "v3.96", + filename: "upx-3.96-amd64_linux.tar.xz", + }, + { + name: Xh, + arch: "amd64", + os: "linux", + version: "v0.14.0", + filename: "xh-v0.14.0-x86_64-unknown-linux-musl.tar.gz", + }, + { + name: Yj, + version: "v5.0.0", + arch: "amd64", + os: "linux", + filename: "yj-linux", }, } for _, tt := range table { - tt.tool.SetRuntime(tt.arch, tt.os) - tt.tool.SetAsset() - s.Equal(tt.name, tt.tool.Asset.Name) + tool := &Tool{ + User: &UserMock{}, + } + tool.Name = tt.name + tool.Version = tt.version + tool.SetRuntime(tt.arch, tt.os) + tool.SetAsset() + s.Equal(tt.filename, tool.Asset.Name) } } func (s *AssetTestSuite) TestWithinArchive() { table := []struct { - tool *Tool + name string arch string os string + version string withinArchive string }{ { - tool: &Tool{ - Name: Bat, - Version: "v0.18.3", - }, + name: Bat, arch: "amd64", os: "linux", + version: "v0.18.3", withinArchive: "bat-v0.18.3-x86_64-unknown-linux-gnu/bat", }, { - tool: &Tool{ - Name: Bottom, - Version: "0.6.4", - }, + name: Bottom, arch: "amd64", os: "linux", + version: "0.6.4", withinArchive: "btm", }, { - tool: &Tool{ - Name: Cloudflared, - Version: "2021.11.0", - }, + name: Cloudflared, arch: "amd64", os: "linux", + version: "2021.11.0", withinArchive: "cloudflared", }, { - tool: &Tool{ - Name: Flyctl, - Version: "v0.0.450", - }, + name: Flyctl, arch: "amd64", os: "linux", + version: "v0.0.450", withinArchive: "flyctl", }, { - tool: &Tool{ - Name: K9s, - Version: "v0.25.4", - }, + name: K9s, arch: "amd64", os: "linux", + version: "v0.25.4", withinArchive: "k9s", }, { - tool: &Tool{ - Name: UPX, - Version: "v3.96", - }, + name: UPX, arch: "amd64", os: "linux", + version: "v3.96", withinArchive: "upx-3.96-amd64_linux/upx", }, { - tool: &Tool{ - Name: Xh, - Version: "v0.14.0", - }, + name: Xh, arch: "amd64", os: "linux", + version: "v0.14.0", withinArchive: "xh-v0.14.0-x86_64-unknown-linux-musl/xh", }, } for _, tt := range table { - tt.tool.SetRuntime(tt.arch, tt.os) - tt.tool.SetAsset() - s.Equal(tt.withinArchive, tt.tool.Asset.WithinArchive) + tool := &Tool{ + User: &UserMock{}, + } + tool.Name = tt.name + tool.Version = tt.version + tool.SetRuntime(tt.arch, tt.os) + tool.SetAsset() + s.Equal(tt.withinArchive, tool.Asset.WithinArchive) } } diff --git a/tools/tools.go b/tools/tools.go index 1349c13..9a00d4f 100644 --- a/tools/tools.go +++ b/tools/tools.go @@ -37,9 +37,18 @@ type Tool struct { Name string OS string URL string + User User Version string } +func (t *Tool) BaseDir() string { + if t.User.IsRoot() { + return "/usr/local/bin/" + } + + return path.Join(t.User.HomeDir(), ".local", "bin") +} + func (t *Tool) Download() error { resp, err := http.Get(fmt.Sprintf("%v/download/%v/%v", t.URL, t.Version, t.Asset.Name)) if err != nil { @@ -128,7 +137,7 @@ func (t *Tool) GetVersion() error { } func (t *Tool) SetAsset() error { - t.Asset.Destination = path.Join("/usr/local/bin/", t.Name) + t.Asset.Destination = path.Join(t.BaseDir(), t.Name) t.Asset.WithinArchive = t.Name switch t.Name { diff --git a/tools/user.go b/tools/user.go new file mode 100644 index 0000000..d9a978b --- /dev/null +++ b/tools/user.go @@ -0,0 +1,28 @@ +package tools + +import "os/user" + +type User interface { + HomeDir() string + IsRoot() bool +} + +type UserOS struct{} + +func (u *UserOS) HomeDir() string { + whoami, err := user.Current() + if err != nil { + return "/tmp/" + } + + return whoami.HomeDir +} + +func (u *UserOS) IsRoot() bool { + whoami, err := user.Current() + if err != nil { + return false + } + + return whoami.Uid == "0" +} diff --git a/tools/user_test.go b/tools/user_test.go new file mode 100644 index 0000000..56a614a --- /dev/null +++ b/tools/user_test.go @@ -0,0 +1,11 @@ +package tools + +type UserMock struct{} + +func (u *UserMock) HomeDir() string { + return "/root/" +} + +func (u *UserMock) IsRoot() bool { + return true +}