From 746b40e56dd8894ebc8519c92c73ffd1f0a1c979 Mon Sep 17 00:00:00 2001 From: Shunsuke Suzuki Date: Sun, 19 Jun 2022 07:58:19 +0900 Subject: [PATCH 1/3] feat: replace symbolic links to executable proxy file on Windows --- pkg/installpackage/installer.go | 11 +++++++++ pkg/installpackage/link.go | 42 +++++++++++++++++++++++++++++++++ pkg/installpackage/proxy.go | 6 ++--- 3 files changed, 56 insertions(+), 3 deletions(-) diff --git a/pkg/installpackage/installer.go b/pkg/installpackage/installer.go index e4d1e202b..deabb016a 100644 --- a/pkg/installpackage/installer.go +++ b/pkg/installpackage/installer.go @@ -32,6 +32,10 @@ type installer struct { executor exec.Executor } +func isWindows(goos string) bool { + return goos == "windows" +} + func (inst *installer) InstallPackages(ctx context.Context, cfg *aqua.Config, registries map[string]*registry.Config, binDir string, onlyLink, isTest bool, logE *logrus.Entry) error { pkgs, failed := inst.createLinks(cfg, registries, binDir, logE) if onlyLink { @@ -186,6 +190,13 @@ func (inst *installer) createLinks(cfg *aqua.Config, registries map[string]*regi PackageInfo: pkgInfo, }) for _, file := range pkgInfo.GetFiles() { + if isWindows(inst.runtime.GOOS) { + if err := inst.createLinkWindows(filepath.Join(binDir, file.Name+".bat"), file.Name, logE); err != nil { + logerr.WithError(logE, err).Error("create the proxy file") + failed = true + } + continue + } if err := inst.createLink(filepath.Join(binDir, file.Name), proxyName, logE); err != nil { logerr.WithError(logE, err).Error("create the symbolic link") failed = true diff --git a/pkg/installpackage/link.go b/pkg/installpackage/link.go index 70fe73b70..b2213a9a0 100644 --- a/pkg/installpackage/link.go +++ b/pkg/installpackage/link.go @@ -3,8 +3,10 @@ package installpackage import ( "fmt" "os" + "strings" "github.com/sirupsen/logrus" + "github.com/spf13/afero" ) func (inst *installer) createLink(linkPath, linkDest string, logE *logrus.Entry) error { @@ -58,3 +60,43 @@ func (inst *installer) recreateLink(linkPath, linkDest string, logE *logrus.Entr } return nil } + +const proxyTemplate = `@echo off +aqua exec -- %* +` +const proxyPermission os.FileMode = 0o755 + +func (inst *installer) createLinkWindows(proxyPath, binName string, logE *logrus.Entry) error { + if fileInfo, err := inst.linker.Lstat(proxyPath); err == nil { + switch mode := fileInfo.Mode(); { + case mode.IsDir(): + // if file is a directory, raise error + return fmt.Errorf("%s has already existed and is a directory", proxyPath) + case mode&os.ModeNamedPipe != 0: + // if file is a pipe, raise error + return fmt.Errorf("%s has already existed and is a named pipe", proxyPath) + case mode.IsRegular(): + // TODO check content + return nil + case mode&os.ModeSymlink != 0: + if err := inst.fs.Remove(proxyPath); err != nil { + return fmt.Errorf("remove a symbolic link (%s): %w", proxyPath, err) + } + return inst.createProxyWindows(proxyPath, binName, logE) + default: + return fmt.Errorf("unexpected file mode %s: %s", proxyPath, mode.String()) + } + } + + return inst.createProxyWindows(proxyPath, binName, logE) +} + +func (inst *installer) createProxyWindows(proxyPath, binName string, logE *logrus.Entry) error { + logE.WithFields(logrus.Fields{ + "proxy_path": proxyPath, + }).Info("create a proxy file") + if err := afero.WriteFile(inst.fs, proxyPath, []byte(strings.Replace(proxyTemplate, "", binName, 1)), proxyPermission); err != nil { + return fmt.Errorf("create a proxy file (%s): %w", proxyPath, err) + } + return nil +} diff --git a/pkg/installpackage/proxy.go b/pkg/installpackage/proxy.go index 27875a61f..1dcf9ec10 100644 --- a/pkg/installpackage/proxy.go +++ b/pkg/installpackage/proxy.go @@ -14,6 +14,9 @@ import ( const ProxyVersion = "v1.1.2" // renovate: depName=aquaproj/aqua-proxy func (inst *installer) InstallProxy(ctx context.Context, logE *logrus.Entry) error { + if isWindows(inst.runtime.GOOS) { + return nil + } proxyAssetTemplate := `aqua-proxy_{{.OS}}_{{.Arch}}.tar.gz` pkg := &config.Package{ Package: &aqua.Package{ @@ -63,9 +66,6 @@ func (inst *installer) InstallProxy(ctx context.Context, logE *logrus.Entry) err // create a symbolic link binName := proxyName - if inst.runtime.GOOS == "windows" { - binName += ".exe" - } a, err := filepath.Rel(filepath.Join(inst.rootDir, "bin"), filepath.Join(pkgPath, binName)) if err != nil { return fmt.Errorf("get a relative path: %w", err) From 222ef65705ea1c9d6b26aec21da51e50f6f95474 Mon Sep 17 00:00:00 2001 From: Shunsuke Suzuki Date: Sun, 19 Jun 2022 16:58:57 +0900 Subject: [PATCH 2/3] feat: add bat directory --- pkg/controller/install/install.go | 10 +++++- pkg/controller/install/install_test.go | 2 +- pkg/controller/wire_gen.go | 2 +- pkg/installpackage/installer.go | 2 +- pkg/installpackage/link.go | 42 ++++++++++++++++++-------- 5 files changed, 41 insertions(+), 17 deletions(-) diff --git a/pkg/controller/install/install.go b/pkg/controller/install/install.go index fba292b21..d9d157aa6 100644 --- a/pkg/controller/install/install.go +++ b/pkg/controller/install/install.go @@ -12,6 +12,7 @@ import ( "github.com/aquaproj/aqua/pkg/config/aqua" registry "github.com/aquaproj/aqua/pkg/install-registry" "github.com/aquaproj/aqua/pkg/installpackage" + "github.com/aquaproj/aqua/pkg/runtime" "github.com/sirupsen/logrus" "github.com/spf13/afero" ) @@ -27,9 +28,10 @@ type Controller struct { configReader reader.ConfigReader registryInstaller registry.Installer fs afero.Fs + runtime *runtime.Runtime } -func New(param *config.Param, configFinder finder.ConfigFinder, configReader reader.ConfigReader, registInstaller registry.Installer, pkgInstaller installpackage.Installer, fs afero.Fs) *Controller { +func New(param *config.Param, configFinder finder.ConfigFinder, configReader reader.ConfigReader, registInstaller registry.Installer, pkgInstaller installpackage.Installer, fs afero.Fs, rt *runtime.Runtime) *Controller { return &Controller{ rootDir: param.RootDir, configFinder: configFinder, @@ -37,6 +39,7 @@ func New(param *config.Param, configFinder finder.ConfigFinder, configReader rea registryInstaller: registInstaller, packageInstaller: pkgInstaller, fs: fs, + runtime: rt, } } @@ -46,6 +49,11 @@ func (ctrl *Controller) Install(ctx context.Context, param *config.Param, logE * if err := ctrl.fs.MkdirAll(rootBin, dirPermission); err != nil { return fmt.Errorf("create the directory: %w", err) } + if ctrl.runtime.GOOS == "windows" { + if err := ctrl.fs.MkdirAll(filepath.Join(ctrl.rootDir, "bat"), dirPermission); err != nil { + return fmt.Errorf("create the directory: %w", err) + } + } if err := ctrl.packageInstaller.InstallProxy(ctx, logE); err != nil { return err //nolint:wrapcheck diff --git a/pkg/controller/install/install_test.go b/pkg/controller/install/install_test.go index 3dbc20fd6..8e1922758 100644 --- a/pkg/controller/install/install_test.go +++ b/pkg/controller/install/install_test.go @@ -90,7 +90,7 @@ packages: downloader := download.NewPackageDownloader(nil, d.rt, download.NewHTTPDownloader(http.DefaultClient)) executor := exec.NewMock(0, nil) pkgInstaller := installpackage.New(d.param, downloader, d.rt, fs, linker, executor) - ctrl := install.New(d.param, finder.NewConfigFinder(fs), reader.New(fs), registry.New(d.param, registryDownloader, fs), pkgInstaller, fs) + ctrl := install.New(d.param, finder.NewConfigFinder(fs), reader.New(fs), registry.New(d.param, registryDownloader, fs), pkgInstaller, fs, d.rt) if err := ctrl.Install(ctx, d.param, logE); err != nil { if d.isErr { return diff --git a/pkg/controller/wire_gen.go b/pkg/controller/wire_gen.go index c797d30c0..beacc4c1e 100644 --- a/pkg/controller/wire_gen.go +++ b/pkg/controller/wire_gen.go @@ -75,7 +75,7 @@ func InitializeInstallCommandController(ctx context.Context, param *config.Param linker := link.New() executor := exec.New() installpackageInstaller := installpackage.New(param, packageDownloader, rt, fs, linker, executor) - controller := install.New(param, configFinder, configReader, installer, installpackageInstaller, fs) + controller := install.New(param, configFinder, configReader, installer, installpackageInstaller, fs, rt) return controller } diff --git a/pkg/installpackage/installer.go b/pkg/installpackage/installer.go index deabb016a..62ca16f5a 100644 --- a/pkg/installpackage/installer.go +++ b/pkg/installpackage/installer.go @@ -191,7 +191,7 @@ func (inst *installer) createLinks(cfg *aqua.Config, registries map[string]*regi }) for _, file := range pkgInfo.GetFiles() { if isWindows(inst.runtime.GOOS) { - if err := inst.createLinkWindows(filepath.Join(binDir, file.Name+".bat"), file.Name, logE); err != nil { + if err := inst.createProxyWindows(file.Name, logE); err != nil { logerr.WithError(logE, err).Error("create the proxy file") failed = true } diff --git a/pkg/installpackage/link.go b/pkg/installpackage/link.go index b2213a9a0..5458976ed 100644 --- a/pkg/installpackage/link.go +++ b/pkg/installpackage/link.go @@ -3,6 +3,7 @@ package installpackage import ( "fmt" "os" + "path/filepath" "strings" "github.com/sirupsen/logrus" @@ -61,41 +62,56 @@ func (inst *installer) recreateLink(linkPath, linkDest string, logE *logrus.Entr return nil } -const proxyTemplate = `@echo off +const ( + batTemplate = `@echo off aqua exec -- %* ` -const proxyPermission os.FileMode = 0o755 + scrTemplate = `#!/usr/bin/env bash +aqua exec -- $0 $@ +` + proxyPermission os.FileMode = 0o755 +) + +func (inst *installer) createProxyWindows(binName string, logE *logrus.Entry) error { + if err := inst.createBinWindows(filepath.Join(inst.rootDir, "bin", binName), scrTemplate, logE); err != nil { + return err + } + if err := inst.createBinWindows(filepath.Join(inst.rootDir, "bat", binName+".bat"), strings.Replace(batTemplate, "", binName, 1), logE); err != nil { + return err + } + return nil +} -func (inst *installer) createLinkWindows(proxyPath, binName string, logE *logrus.Entry) error { - if fileInfo, err := inst.linker.Lstat(proxyPath); err == nil { +func (inst *installer) createBinWindows(binPath, binTxt string, logE *logrus.Entry) error { + if fileInfo, err := inst.linker.Lstat(binPath); err == nil { switch mode := fileInfo.Mode(); { case mode.IsDir(): // if file is a directory, raise error - return fmt.Errorf("%s has already existed and is a directory", proxyPath) + return fmt.Errorf("%s has already existed and is a directory", binPath) case mode&os.ModeNamedPipe != 0: // if file is a pipe, raise error - return fmt.Errorf("%s has already existed and is a named pipe", proxyPath) + return fmt.Errorf("%s has already existed and is a named pipe", binPath) case mode.IsRegular(): // TODO check content return nil case mode&os.ModeSymlink != 0: - if err := inst.fs.Remove(proxyPath); err != nil { - return fmt.Errorf("remove a symbolic link (%s): %w", proxyPath, err) + if err := inst.fs.Remove(binPath); err != nil { + return fmt.Errorf("remove a symbolic link (%s): %w", binPath, err) } - return inst.createProxyWindows(proxyPath, binName, logE) + return inst.writeBinWindows(binPath, binTxt, logE) default: - return fmt.Errorf("unexpected file mode %s: %s", proxyPath, mode.String()) + return fmt.Errorf("unexpected file mode %s: %s", binPath, mode.String()) } } - return inst.createProxyWindows(proxyPath, binName, logE) + return inst.writeBinWindows(binPath, binTxt, logE) } -func (inst *installer) createProxyWindows(proxyPath, binName string, logE *logrus.Entry) error { +func (inst *installer) writeBinWindows(proxyPath, binTxt string, logE *logrus.Entry) error { logE.WithFields(logrus.Fields{ "proxy_path": proxyPath, }).Info("create a proxy file") - if err := afero.WriteFile(inst.fs, proxyPath, []byte(strings.Replace(proxyTemplate, "", binName, 1)), proxyPermission); err != nil { + if err := afero.WriteFile(inst.fs, proxyPath, []byte(binTxt), proxyPermission); err != nil { return fmt.Errorf("create a proxy file (%s): %w", proxyPath, err) } return nil From 52a010aa9f12c9582f760d9591da684a8e132ec7 Mon Sep 17 00:00:00 2001 From: Shunsuke Suzuki Date: Sun, 19 Jun 2022 17:49:45 +0900 Subject: [PATCH 3/3] fix: use exec command on Git Bash --- pkg/installpackage/link.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/installpackage/link.go b/pkg/installpackage/link.go index 5458976ed..aaac3435a 100644 --- a/pkg/installpackage/link.go +++ b/pkg/installpackage/link.go @@ -67,7 +67,7 @@ const ( aqua exec -- %* ` scrTemplate = `#!/usr/bin/env bash -aqua exec -- $0 $@ +exec aqua exec -- $0 $@ ` proxyPermission os.FileMode = 0o755 )