refactor: generate plugin executors
This commit is contained in:
		| @@ -176,25 +176,6 @@ type ScriptResolverExecutor interface { | ||||
| 	ResolveScript(ctx context.Context, pkg *alrsh.Package) *ScriptInfo | ||||
| } | ||||
|  | ||||
| type ScriptExecutor interface { | ||||
| 	ReadScript(ctx context.Context, scriptPath string) (*alrsh.ScriptFile, error) | ||||
| 	ExecuteFirstPass(ctx context.Context, input *BuildInput, sf *alrsh.ScriptFile) (string, []*alrsh.Package, error) | ||||
| 	PrepareDirs( | ||||
| 		ctx context.Context, | ||||
| 		input *BuildInput, | ||||
| 		basePkg string, | ||||
| 	) error | ||||
| 	ExecuteSecondPass( | ||||
| 		ctx context.Context, | ||||
| 		input *BuildInput, | ||||
| 		sf *alrsh.ScriptFile, | ||||
| 		varsOfPackages []*alrsh.Package, | ||||
| 		repoDeps []string, | ||||
| 		builtDeps []*BuiltDep, | ||||
| 		basePkg string, | ||||
| 	) ([]*BuiltDep, error) | ||||
| } | ||||
|  | ||||
| type CacheExecutor interface { | ||||
| 	CheckForBuiltPackage(ctx context.Context, input *BuildInput, vars *alrsh.Package) (string, bool, error) | ||||
| } | ||||
| @@ -211,14 +192,6 @@ type CheckerExecutor interface { | ||||
| 	) (bool, error) | ||||
| } | ||||
|  | ||||
| type InstallerExecutor interface { | ||||
| 	InstallLocal(paths []string, opts *manager.Opts) error | ||||
| 	Install(pkgs []string, opts *manager.Opts) error | ||||
| 	Remove(pkgs []string, opts *manager.Opts) error | ||||
|  | ||||
| 	RemoveAlreadyInstalled(pkgs []string) ([]string, error) | ||||
| } | ||||
|  | ||||
| type SourcesInput struct { | ||||
| 	Sources   []string | ||||
| 	Checksums []string | ||||
| @@ -499,6 +472,7 @@ func (b *Builder) removeBuildDeps(ctx context.Context, input interface { | ||||
|  | ||||
| 		if remove { | ||||
| 			err = b.installerExecutor.Remove( | ||||
| 				ctx, | ||||
| 				deps, | ||||
| 				&manager.Opts{ | ||||
| 					NoConfirm: !input.BuildOpts().Interactive, | ||||
| @@ -545,6 +519,7 @@ func (b *Builder) InstallALRPackages( | ||||
| 		} | ||||
|  | ||||
| 		err = b.installerExecutor.InstallLocal( | ||||
| 			ctx, | ||||
| 			GetBuiltPaths(res), | ||||
| 			&manager.Opts{ | ||||
| 				NoConfirm: !input.BuildOpts().Interactive, | ||||
| @@ -645,7 +620,7 @@ func (i *Builder) installBuildDeps( | ||||
| 	var deps []string | ||||
| 	var err error | ||||
| 	if len(pkgs) > 0 { | ||||
| 		deps, err = i.installerExecutor.RemoveAlreadyInstalled(pkgs) | ||||
| 		deps, err = i.installerExecutor.RemoveAlreadyInstalled(ctx, pkgs) | ||||
| 		if err != nil { | ||||
| 			return nil, nil, err | ||||
| 		} | ||||
| @@ -668,7 +643,7 @@ func (i *Builder) installOptDeps( | ||||
| 	pkgs []string, | ||||
| ) ([]*BuiltDep, error) { | ||||
| 	var builtDeps []*BuiltDep | ||||
| 	optDeps, err := i.installerExecutor.RemoveAlreadyInstalled(pkgs) | ||||
| 	optDeps, err := i.installerExecutor.RemoveAlreadyInstalled(ctx, pkgs) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| @@ -710,7 +685,7 @@ func (i *Builder) InstallPkgs( | ||||
| 	} | ||||
|  | ||||
| 	if len(builtDeps) > 0 { | ||||
| 		err = i.installerExecutor.InstallLocal(GetBuiltPaths(builtDeps), &manager.Opts{ | ||||
| 		err = i.installerExecutor.InstallLocal(ctx, GetBuiltPaths(builtDeps), &manager.Opts{ | ||||
| 			NoConfirm: !input.BuildOpts().Interactive, | ||||
| 		}) | ||||
| 		if err != nil { | ||||
| @@ -719,7 +694,7 @@ func (i *Builder) InstallPkgs( | ||||
| 	} | ||||
|  | ||||
| 	if len(repoDeps) > 0 { | ||||
| 		err = i.installerExecutor.Install(repoDeps, &manager.Opts{ | ||||
| 		err = i.installerExecutor.Install(ctx, repoDeps, &manager.Opts{ | ||||
| 			NoConfirm: !input.BuildOpts().Interactive, | ||||
| 		}) | ||||
| 		if err != nil { | ||||
|   | ||||
| @@ -17,6 +17,8 @@ | ||||
| package build | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
|  | ||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/manager" | ||||
| ) | ||||
|  | ||||
| @@ -28,19 +30,19 @@ func NewInstaller(mgr manager.Manager) *Installer { | ||||
|  | ||||
| type Installer struct{ mgr manager.Manager } | ||||
|  | ||||
| func (i *Installer) InstallLocal(paths []string, opts *manager.Opts) error { | ||||
| func (i *Installer) InstallLocal(ctx context.Context, paths []string, opts *manager.Opts) error { | ||||
| 	return i.mgr.InstallLocal(opts, paths...) | ||||
| } | ||||
|  | ||||
| func (i *Installer) Install(pkgs []string, opts *manager.Opts) error { | ||||
| func (i *Installer) Install(ctx context.Context, pkgs []string, opts *manager.Opts) error { | ||||
| 	return i.mgr.Install(opts, pkgs...) | ||||
| } | ||||
|  | ||||
| func (i *Installer) Remove(pkgs []string, opts *manager.Opts) error { | ||||
| func (i *Installer) Remove(ctx context.Context, pkgs []string, opts *manager.Opts) error { | ||||
| 	return i.mgr.Remove(opts, pkgs...) | ||||
| } | ||||
|  | ||||
| func (i *Installer) RemoveAlreadyInstalled(pkgs []string) ([]string, error) { | ||||
| func (i *Installer) RemoveAlreadyInstalled(ctx context.Context, pkgs []string) ([]string, error) { | ||||
| 	filteredPackages := []string{} | ||||
|  | ||||
| 	for _, dep := range pkgs { | ||||
|   | ||||
							
								
								
									
										125
									
								
								internal/build/plugins.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										125
									
								
								internal/build/plugins.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,125 @@ | ||||
| // ALR - Any Linux Repository | ||||
| // Copyright (C) 2025 The ALR Authors | ||||
| // | ||||
| // This program is free software: you can redistribute it and/or modify | ||||
| // it under the terms of the GNU General Public License as published by | ||||
| // the Free Software Foundation, either version 3 of the License, or | ||||
| // (at your option) any later version. | ||||
| // | ||||
| // This program is distributed in the hope that it will be useful, | ||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
| // GNU General Public License for more details. | ||||
| // | ||||
| // You should have received a copy of the GNU General Public License | ||||
| // along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
|  | ||||
| package build | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"log/slog" | ||||
| 	"os" | ||||
| 	"os/exec" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/hashicorp/go-plugin" | ||||
|  | ||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/logger" | ||||
| ) | ||||
|  | ||||
| var pluginMap = map[string]plugin.Plugin{ | ||||
| 	"script-executor": &ScriptExecutorPlugin{}, | ||||
| 	"installer":       &InstallerExecutorPlugin{}, | ||||
| } | ||||
|  | ||||
| var HandshakeConfig = plugin.HandshakeConfig{ | ||||
| 	ProtocolVersion:  1, | ||||
| 	MagicCookieKey:   "ALR_PLUGIN", | ||||
| 	MagicCookieValue: "-", | ||||
| } | ||||
|  | ||||
| func setCommonCmdEnv(cmd *exec.Cmd) { | ||||
| 	cmd.Env = []string{ | ||||
| 		"HOME=/var/cache/alr", | ||||
| 		"LOGNAME=alr", | ||||
| 		"USER=alr", | ||||
| 		"PATH=/usr/bin:/bin:/usr/local/bin", | ||||
| 	} | ||||
| 	for _, env := range os.Environ() { | ||||
| 		if strings.HasPrefix(env, "LANG=") || | ||||
| 			strings.HasPrefix(env, "LANGUAGE=") || | ||||
| 			strings.HasPrefix(env, "LC_") || | ||||
| 			strings.HasPrefix(env, "ALR_LOG_LEVEL=") { | ||||
| 			cmd.Env = append(cmd.Env, env) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func GetSafeInstaller() (InstallerExecutor, func(), error) { | ||||
| 	return getSafeExecutor[InstallerExecutor]("_internal-installer", "installer") | ||||
| } | ||||
|  | ||||
| func GetSafeScriptExecutor() (ScriptExecutor, func(), error) { | ||||
| 	return getSafeExecutor[ScriptExecutor]("_internal-safe-script-executor", "script-executor") | ||||
| } | ||||
|  | ||||
| func getSafeExecutor[T any](subCommand, pluginName string) (T, func(), error) { | ||||
| 	var err error | ||||
|  | ||||
| 	executable, err := os.Executable() | ||||
| 	if err != nil { | ||||
| 		var zero T | ||||
| 		return zero, nil, err | ||||
| 	} | ||||
|  | ||||
| 	cmd := exec.Command(executable, subCommand) | ||||
| 	setCommonCmdEnv(cmd) | ||||
|  | ||||
| 	client := plugin.NewClient(&plugin.ClientConfig{ | ||||
| 		HandshakeConfig: HandshakeConfig, | ||||
| 		Plugins:         pluginMap, | ||||
| 		Cmd:             cmd, | ||||
| 		Logger:          logger.GetHCLoggerAdapter(), | ||||
| 		SkipHostEnv:     true, | ||||
| 		UnixSocketConfig: &plugin.UnixSocketConfig{ | ||||
| 			Group: "alr", | ||||
| 		}, | ||||
| 		SyncStderr: os.Stderr, | ||||
| 	}) | ||||
| 	rpcClient, err := client.Client() | ||||
| 	if err != nil { | ||||
| 		var zero T | ||||
| 		return zero, nil, err | ||||
| 	} | ||||
|  | ||||
| 	var cleanupOnce sync.Once | ||||
| 	cleanup := func() { | ||||
| 		cleanupOnce.Do(func() { | ||||
| 			client.Kill() | ||||
| 		}) | ||||
| 	} | ||||
|  | ||||
| 	defer func() { | ||||
| 		if err != nil { | ||||
| 			slog.Debug("close executor") | ||||
| 			cleanup() | ||||
| 		} | ||||
| 	}() | ||||
|  | ||||
| 	raw, err := rpcClient.Dispense(pluginName) | ||||
| 	if err != nil { | ||||
| 		var zero T | ||||
| 		return zero, nil, err | ||||
| 	} | ||||
|  | ||||
| 	executor, ok := raw.(T) | ||||
| 	if !ok { | ||||
| 		var zero T | ||||
| 		err = fmt.Errorf("dispensed object is not a %T (got %T)", zero, raw) | ||||
| 		return zero, nil, err | ||||
| 	} | ||||
|  | ||||
| 	return executor, cleanup, nil | ||||
| } | ||||
							
								
								
									
										55
									
								
								internal/build/plugins_executors.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								internal/build/plugins_executors.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,55 @@ | ||||
| // ALR - Any Linux Repository | ||||
| // Copyright (C) 2025 The ALR Authors | ||||
| // | ||||
| // This program is free software: you can redistribute it and/or modify | ||||
| // it under the terms of the GNU General Public License as published by | ||||
| // the Free Software Foundation, either version 3 of the License, or | ||||
| // (at your option) any later version. | ||||
| // | ||||
| // This program is distributed in the hope that it will be useful, | ||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
| // GNU General Public License for more details. | ||||
| // | ||||
| // You should have received a copy of the GNU General Public License | ||||
| // along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
|  | ||||
| package build | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
|  | ||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/manager" | ||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/alrsh" | ||||
| ) | ||||
|  | ||||
| //go:generate go run ../../generators/plugin-generator InstallerExecutor ScriptExecutor | ||||
|  | ||||
| // The Executors interfaces must use context.Context as the first parameter, | ||||
| // because the plugin-generator cannot generate code without it. | ||||
|  | ||||
| type InstallerExecutor interface { | ||||
| 	InstallLocal(ctx context.Context, paths []string, opts *manager.Opts) error | ||||
| 	Install(ctx context.Context, pkgs []string, opts *manager.Opts) error | ||||
| 	Remove(ctx context.Context, pkgs []string, opts *manager.Opts) error | ||||
| 	RemoveAlreadyInstalled(ctx context.Context, pkgs []string) ([]string, error) | ||||
| } | ||||
|  | ||||
| type ScriptExecutor interface { | ||||
| 	ReadScript(ctx context.Context, scriptPath string) (*alrsh.ScriptFile, error) | ||||
| 	ExecuteFirstPass(ctx context.Context, input *BuildInput, sf *alrsh.ScriptFile) (string, []*alrsh.Package, error) | ||||
| 	PrepareDirs( | ||||
| 		ctx context.Context, | ||||
| 		input *BuildInput, | ||||
| 		basePkg string, | ||||
| 	) error | ||||
| 	ExecuteSecondPass( | ||||
| 		ctx context.Context, | ||||
| 		input *BuildInput, | ||||
| 		sf *alrsh.ScriptFile, | ||||
| 		varsOfPackages []*alrsh.Package, | ||||
| 		repoDeps []string, | ||||
| 		builtDeps []*BuiltDep, | ||||
| 		basePkg string, | ||||
| 	) ([]*BuiltDep, error) | ||||
| } | ||||
							
								
								
									
										318
									
								
								internal/build/plugins_executors_gen.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										318
									
								
								internal/build/plugins_executors_gen.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,318 @@ | ||||
| // DO NOT EDIT MANUALLY. This file is generated. | ||||
|  | ||||
| // ALR - Any Linux Repository | ||||
| // Copyright (C) 2025 The ALR Authors | ||||
| // | ||||
| // This program is free software: you can redistribute it and/or modify | ||||
| // it under the terms of the GNU General Public License as published by | ||||
| // the Free Software Foundation, either version 3 of the License, or | ||||
| // (at your option) any later version. | ||||
| // | ||||
| // This program is distributed in the hope that it will be useful, | ||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
| // GNU General Public License for more details. | ||||
| // | ||||
| // You should have received a copy of the GNU General Public License | ||||
| // along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
|  | ||||
| package build | ||||
|  | ||||
| import ( | ||||
| 	"net/rpc" | ||||
|  | ||||
| 	"context" | ||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/manager" | ||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/alrsh" | ||||
| 	"github.com/hashicorp/go-plugin" | ||||
| ) | ||||
|  | ||||
| type InstallerExecutorPlugin struct { | ||||
| 	Impl InstallerExecutor | ||||
| } | ||||
|  | ||||
| type InstallerExecutorRPCServer struct { | ||||
| 	Impl InstallerExecutor | ||||
| } | ||||
|  | ||||
| type InstallerExecutorRPC struct { | ||||
| 	client *rpc.Client | ||||
| } | ||||
|  | ||||
| func (p *InstallerExecutorPlugin) Client(b *plugin.MuxBroker, c *rpc.Client) (interface{}, error) { | ||||
| 	return &InstallerExecutorRPC{client: c}, nil | ||||
| } | ||||
|  | ||||
| func (p *InstallerExecutorPlugin) Server(*plugin.MuxBroker) (interface{}, error) { | ||||
| 	return &InstallerExecutorRPCServer{Impl: p.Impl}, nil | ||||
| } | ||||
|  | ||||
| type ScriptExecutorPlugin struct { | ||||
| 	Impl ScriptExecutor | ||||
| } | ||||
|  | ||||
| type ScriptExecutorRPCServer struct { | ||||
| 	Impl ScriptExecutor | ||||
| } | ||||
|  | ||||
| type ScriptExecutorRPC struct { | ||||
| 	client *rpc.Client | ||||
| } | ||||
|  | ||||
| func (p *ScriptExecutorPlugin) Client(b *plugin.MuxBroker, c *rpc.Client) (interface{}, error) { | ||||
| 	return &ScriptExecutorRPC{client: c}, nil | ||||
| } | ||||
|  | ||||
| func (p *ScriptExecutorPlugin) Server(*plugin.MuxBroker) (interface{}, error) { | ||||
| 	return &ScriptExecutorRPCServer{Impl: p.Impl}, nil | ||||
| } | ||||
|  | ||||
| type InstallerExecutorInstallLocalArgs struct { | ||||
| 	Paths []string | ||||
| 	Opts  *manager.Opts | ||||
| } | ||||
|  | ||||
| type InstallerExecutorInstallLocalResp struct { | ||||
| } | ||||
|  | ||||
| func (s *InstallerExecutorRPC) InstallLocal(ctx context.Context, paths []string, opts *manager.Opts) error { | ||||
| 	var resp *InstallerExecutorInstallLocalResp | ||||
| 	err := s.client.Call("Plugin.InstallLocal", &InstallerExecutorInstallLocalArgs{ | ||||
| 		Paths: paths, | ||||
| 		Opts:  opts, | ||||
| 	}, &resp) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (s *InstallerExecutorRPCServer) InstallLocal(args *InstallerExecutorInstallLocalArgs, resp *InstallerExecutorInstallLocalResp) error { | ||||
| 	err := s.Impl.InstallLocal(context.Background(), args.Paths, args.Opts) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	*resp = InstallerExecutorInstallLocalResp{} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| type InstallerExecutorInstallArgs struct { | ||||
| 	Pkgs []string | ||||
| 	Opts *manager.Opts | ||||
| } | ||||
|  | ||||
| type InstallerExecutorInstallResp struct { | ||||
| } | ||||
|  | ||||
| func (s *InstallerExecutorRPC) Install(ctx context.Context, pkgs []string, opts *manager.Opts) error { | ||||
| 	var resp *InstallerExecutorInstallResp | ||||
| 	err := s.client.Call("Plugin.Install", &InstallerExecutorInstallArgs{ | ||||
| 		Pkgs: pkgs, | ||||
| 		Opts: opts, | ||||
| 	}, &resp) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (s *InstallerExecutorRPCServer) Install(args *InstallerExecutorInstallArgs, resp *InstallerExecutorInstallResp) error { | ||||
| 	err := s.Impl.Install(context.Background(), args.Pkgs, args.Opts) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	*resp = InstallerExecutorInstallResp{} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| type InstallerExecutorRemoveArgs struct { | ||||
| 	Pkgs []string | ||||
| 	Opts *manager.Opts | ||||
| } | ||||
|  | ||||
| type InstallerExecutorRemoveResp struct { | ||||
| } | ||||
|  | ||||
| func (s *InstallerExecutorRPC) Remove(ctx context.Context, pkgs []string, opts *manager.Opts) error { | ||||
| 	var resp *InstallerExecutorRemoveResp | ||||
| 	err := s.client.Call("Plugin.Remove", &InstallerExecutorRemoveArgs{ | ||||
| 		Pkgs: pkgs, | ||||
| 		Opts: opts, | ||||
| 	}, &resp) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (s *InstallerExecutorRPCServer) Remove(args *InstallerExecutorRemoveArgs, resp *InstallerExecutorRemoveResp) error { | ||||
| 	err := s.Impl.Remove(context.Background(), args.Pkgs, args.Opts) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	*resp = InstallerExecutorRemoveResp{} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| type InstallerExecutorRemoveAlreadyInstalledArgs struct { | ||||
| 	Pkgs []string | ||||
| } | ||||
|  | ||||
| type InstallerExecutorRemoveAlreadyInstalledResp struct { | ||||
| 	Result0 []string | ||||
| } | ||||
|  | ||||
| func (s *InstallerExecutorRPC) RemoveAlreadyInstalled(ctx context.Context, pkgs []string) ([]string, error) { | ||||
| 	var resp *InstallerExecutorRemoveAlreadyInstalledResp | ||||
| 	err := s.client.Call("Plugin.RemoveAlreadyInstalled", &InstallerExecutorRemoveAlreadyInstalledArgs{ | ||||
| 		Pkgs: pkgs, | ||||
| 	}, &resp) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return resp.Result0, nil | ||||
| } | ||||
|  | ||||
| func (s *InstallerExecutorRPCServer) RemoveAlreadyInstalled(args *InstallerExecutorRemoveAlreadyInstalledArgs, resp *InstallerExecutorRemoveAlreadyInstalledResp) error { | ||||
| 	result0, err := s.Impl.RemoveAlreadyInstalled(context.Background(), args.Pkgs) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	*resp = InstallerExecutorRemoveAlreadyInstalledResp{ | ||||
| 		Result0: result0, | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| type ScriptExecutorReadScriptArgs struct { | ||||
| 	ScriptPath string | ||||
| } | ||||
|  | ||||
| type ScriptExecutorReadScriptResp struct { | ||||
| 	Result0 *alrsh.ScriptFile | ||||
| } | ||||
|  | ||||
| func (s *ScriptExecutorRPC) ReadScript(ctx context.Context, scriptPath string) (*alrsh.ScriptFile, error) { | ||||
| 	var resp *ScriptExecutorReadScriptResp | ||||
| 	err := s.client.Call("Plugin.ReadScript", &ScriptExecutorReadScriptArgs{ | ||||
| 		ScriptPath: scriptPath, | ||||
| 	}, &resp) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return resp.Result0, nil | ||||
| } | ||||
|  | ||||
| func (s *ScriptExecutorRPCServer) ReadScript(args *ScriptExecutorReadScriptArgs, resp *ScriptExecutorReadScriptResp) error { | ||||
| 	result0, err := s.Impl.ReadScript(context.Background(), args.ScriptPath) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	*resp = ScriptExecutorReadScriptResp{ | ||||
| 		Result0: result0, | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| type ScriptExecutorExecuteFirstPassArgs struct { | ||||
| 	Input *BuildInput | ||||
| 	Sf    *alrsh.ScriptFile | ||||
| } | ||||
|  | ||||
| type ScriptExecutorExecuteFirstPassResp struct { | ||||
| 	Result0 string | ||||
| 	Result1 []*alrsh.Package | ||||
| } | ||||
|  | ||||
| func (s *ScriptExecutorRPC) ExecuteFirstPass(ctx context.Context, input *BuildInput, sf *alrsh.ScriptFile) (string, []*alrsh.Package, error) { | ||||
| 	var resp *ScriptExecutorExecuteFirstPassResp | ||||
| 	err := s.client.Call("Plugin.ExecuteFirstPass", &ScriptExecutorExecuteFirstPassArgs{ | ||||
| 		Input: input, | ||||
| 		Sf:    sf, | ||||
| 	}, &resp) | ||||
| 	if err != nil { | ||||
| 		return "", nil, err | ||||
| 	} | ||||
| 	return resp.Result0, resp.Result1, nil | ||||
| } | ||||
|  | ||||
| func (s *ScriptExecutorRPCServer) ExecuteFirstPass(args *ScriptExecutorExecuteFirstPassArgs, resp *ScriptExecutorExecuteFirstPassResp) error { | ||||
| 	result0, result1, err := s.Impl.ExecuteFirstPass(context.Background(), args.Input, args.Sf) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	*resp = ScriptExecutorExecuteFirstPassResp{ | ||||
| 		Result0: result0, | ||||
| 		Result1: result1, | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| type ScriptExecutorPrepareDirsArgs struct { | ||||
| 	Input   *BuildInput | ||||
| 	BasePkg string | ||||
| } | ||||
|  | ||||
| type ScriptExecutorPrepareDirsResp struct { | ||||
| } | ||||
|  | ||||
| func (s *ScriptExecutorRPC) PrepareDirs(ctx context.Context, input *BuildInput, basePkg string) error { | ||||
| 	var resp *ScriptExecutorPrepareDirsResp | ||||
| 	err := s.client.Call("Plugin.PrepareDirs", &ScriptExecutorPrepareDirsArgs{ | ||||
| 		Input:   input, | ||||
| 		BasePkg: basePkg, | ||||
| 	}, &resp) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (s *ScriptExecutorRPCServer) PrepareDirs(args *ScriptExecutorPrepareDirsArgs, resp *ScriptExecutorPrepareDirsResp) error { | ||||
| 	err := s.Impl.PrepareDirs(context.Background(), args.Input, args.BasePkg) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	*resp = ScriptExecutorPrepareDirsResp{} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| type ScriptExecutorExecuteSecondPassArgs struct { | ||||
| 	Input          *BuildInput | ||||
| 	Sf             *alrsh.ScriptFile | ||||
| 	VarsOfPackages []*alrsh.Package | ||||
| 	RepoDeps       []string | ||||
| 	BuiltDeps      []*BuiltDep | ||||
| 	BasePkg        string | ||||
| } | ||||
|  | ||||
| type ScriptExecutorExecuteSecondPassResp struct { | ||||
| 	Result0 []*BuiltDep | ||||
| } | ||||
|  | ||||
| func (s *ScriptExecutorRPC) ExecuteSecondPass(ctx context.Context, input *BuildInput, sf *alrsh.ScriptFile, varsOfPackages []*alrsh.Package, repoDeps []string, builtDeps []*BuiltDep, basePkg string) ([]*BuiltDep, error) { | ||||
| 	var resp *ScriptExecutorExecuteSecondPassResp | ||||
| 	err := s.client.Call("Plugin.ExecuteSecondPass", &ScriptExecutorExecuteSecondPassArgs{ | ||||
| 		Input:          input, | ||||
| 		Sf:             sf, | ||||
| 		VarsOfPackages: varsOfPackages, | ||||
| 		RepoDeps:       repoDeps, | ||||
| 		BuiltDeps:      builtDeps, | ||||
| 		BasePkg:        basePkg, | ||||
| 	}, &resp) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return resp.Result0, nil | ||||
| } | ||||
|  | ||||
| func (s *ScriptExecutorRPCServer) ExecuteSecondPass(args *ScriptExecutorExecuteSecondPassArgs, resp *ScriptExecutorExecuteSecondPassResp) error { | ||||
| 	result0, err := s.Impl.ExecuteSecondPass(context.Background(), args.Input, args.Sf, args.VarsOfPackages, args.RepoDeps, args.BuiltDeps, args.BasePkg) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	*resp = ScriptExecutorExecuteSecondPassResp{ | ||||
| 		Result0: result0, | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| @@ -1,40 +0,0 @@ | ||||
| // ALR - Any Linux Repository | ||||
| // Copyright (C) 2025 The ALR Authors | ||||
| // | ||||
| // This program is free software: you can redistribute it and/or modify | ||||
| // it under the terms of the GNU General Public License as published by | ||||
| // the Free Software Foundation, either version 3 of the License, or | ||||
| // (at your option) any later version. | ||||
| // | ||||
| // This program is distributed in the hope that it will be useful, | ||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
| // GNU General Public License for more details. | ||||
| // | ||||
| // You should have received a copy of the GNU General Public License | ||||
| // along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
|  | ||||
| package build | ||||
|  | ||||
| import ( | ||||
| 	"os" | ||||
| 	"os/exec" | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| func setCommonCmdEnv(cmd *exec.Cmd) { | ||||
| 	cmd.Env = []string{ | ||||
| 		"HOME=/var/cache/alr", | ||||
| 		"LOGNAME=alr", | ||||
| 		"USER=alr", | ||||
| 		"PATH=/usr/bin:/bin:/usr/local/bin", | ||||
| 	} | ||||
| 	for _, env := range os.Environ() { | ||||
| 		if strings.HasPrefix(env, "LANG=") || | ||||
| 			strings.HasPrefix(env, "LANGUAGE=") || | ||||
| 			strings.HasPrefix(env, "LC_") || | ||||
| 			strings.HasPrefix(env, "ALR_LOG_LEVEL=") { | ||||
| 			cmd.Env = append(cmd.Env, env) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @@ -1,161 +0,0 @@ | ||||
| // ALR - Any Linux Repository | ||||
| // Copyright (C) 2025 The ALR Authors | ||||
| // | ||||
| // This program is free software: you can redistribute it and/or modify | ||||
| // it under the terms of the GNU General Public License as published by | ||||
| // the Free Software Foundation, either version 3 of the License, or | ||||
| // (at your option) any later version. | ||||
| // | ||||
| // This program is distributed in the hope that it will be useful, | ||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
| // GNU General Public License for more details. | ||||
| // | ||||
| // You should have received a copy of the GNU General Public License | ||||
| // along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
|  | ||||
| package build | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"log/slog" | ||||
| 	"net/rpc" | ||||
| 	"os" | ||||
| 	"os/exec" | ||||
| 	"sync" | ||||
| 	"syscall" | ||||
|  | ||||
| 	"github.com/hashicorp/go-plugin" | ||||
|  | ||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/logger" | ||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/manager" | ||||
| ) | ||||
|  | ||||
| type InstallerPlugin struct { | ||||
| 	Impl InstallerExecutor | ||||
| } | ||||
|  | ||||
| type InstallerRPC struct { | ||||
| 	client *rpc.Client | ||||
| } | ||||
|  | ||||
| type InstallerRPCServer struct { | ||||
| 	Impl InstallerExecutor | ||||
| } | ||||
|  | ||||
| type InstallArgs struct { | ||||
| 	PackagesOrPaths []string | ||||
| 	Opts            *manager.Opts | ||||
| } | ||||
|  | ||||
| func (r *InstallerRPC) InstallLocal(paths []string, opts *manager.Opts) error { | ||||
| 	return r.client.Call("Plugin.InstallLocal", &InstallArgs{ | ||||
| 		PackagesOrPaths: paths, | ||||
| 		Opts:            opts, | ||||
| 	}, nil) | ||||
| } | ||||
|  | ||||
| func (s *InstallerRPCServer) InstallLocal(args *InstallArgs, reply *struct{}) error { | ||||
| 	return s.Impl.InstallLocal(args.PackagesOrPaths, args.Opts) | ||||
| } | ||||
|  | ||||
| func (r *InstallerRPC) Install(pkgs []string, opts *manager.Opts) error { | ||||
| 	return r.client.Call("Plugin.Install", &InstallArgs{ | ||||
| 		PackagesOrPaths: pkgs, | ||||
| 		Opts:            opts, | ||||
| 	}, nil) | ||||
| } | ||||
|  | ||||
| func (s *InstallerRPCServer) Install(args *InstallArgs, reply *struct{}) error { | ||||
| 	return s.Impl.Install(args.PackagesOrPaths, args.Opts) | ||||
| } | ||||
|  | ||||
| func (r *InstallerRPC) Remove(pkgs []string, opts *manager.Opts) error { | ||||
| 	return r.client.Call("Plugin.Remove", &InstallArgs{ | ||||
| 		PackagesOrPaths: pkgs, | ||||
| 		Opts:            opts, | ||||
| 	}, nil) | ||||
| } | ||||
|  | ||||
| func (s *InstallerRPCServer) Remove(args *InstallArgs, reply *struct{}) error { | ||||
| 	return s.Impl.Remove(args.PackagesOrPaths, args.Opts) | ||||
| } | ||||
|  | ||||
| func (r *InstallerRPC) RemoveAlreadyInstalled(paths []string) ([]string, error) { | ||||
| 	var val []string | ||||
| 	err := r.client.Call("Plugin.RemoveAlreadyInstalled", paths, &val) | ||||
| 	return val, err | ||||
| } | ||||
|  | ||||
| func (s *InstallerRPCServer) RemoveAlreadyInstalled(pkgs []string, res *[]string) error { | ||||
| 	vars, err := s.Impl.RemoveAlreadyInstalled(pkgs) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	*res = vars | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (p *InstallerPlugin) Client(b *plugin.MuxBroker, c *rpc.Client) (interface{}, error) { | ||||
| 	return &InstallerRPC{client: c}, nil | ||||
| } | ||||
|  | ||||
| func (p *InstallerPlugin) Server(*plugin.MuxBroker) (interface{}, error) { | ||||
| 	return &InstallerRPCServer{Impl: p.Impl}, nil | ||||
| } | ||||
|  | ||||
| func GetSafeInstaller() (InstallerExecutor, func(), error) { | ||||
| 	var err error | ||||
|  | ||||
| 	executable, err := os.Executable() | ||||
| 	if err != nil { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
| 	cmd := exec.Command(executable, "_internal-installer") | ||||
| 	setCommonCmdEnv(cmd) | ||||
|  | ||||
| 	slog.Debug("safe installer setup", "uid", syscall.Getuid(), "gid", syscall.Getgid()) | ||||
|  | ||||
| 	client := plugin.NewClient(&plugin.ClientConfig{ | ||||
| 		HandshakeConfig: HandshakeConfig, | ||||
| 		Plugins:         pluginMap, | ||||
| 		Cmd:             cmd, | ||||
| 		Logger:          logger.GetHCLoggerAdapter(), | ||||
| 		SkipHostEnv:     true, | ||||
| 		UnixSocketConfig: &plugin.UnixSocketConfig{ | ||||
| 			Group: "alr", | ||||
| 		}, | ||||
| 		SyncStderr: os.Stderr, | ||||
| 	}) | ||||
| 	rpcClient, err := client.Client() | ||||
| 	if err != nil { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
|  | ||||
| 	var cleanupOnce sync.Once | ||||
| 	cleanup := func() { | ||||
| 		cleanupOnce.Do(func() { | ||||
| 			client.Kill() | ||||
| 		}) | ||||
| 	} | ||||
|  | ||||
| 	defer func() { | ||||
| 		if err != nil { | ||||
| 			slog.Debug("close installer") | ||||
| 			cleanup() | ||||
| 		} | ||||
| 	}() | ||||
|  | ||||
| 	raw, err := rpcClient.Dispense("installer") | ||||
| 	if err != nil { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
|  | ||||
| 	executor, ok := raw.(InstallerExecutor) | ||||
| 	if !ok { | ||||
| 		err = fmt.Errorf("dispensed object is not a ScriptExecutor (got %T)", raw) | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
|  | ||||
| 	return executor, cleanup, nil | ||||
| } | ||||
| @@ -1,273 +0,0 @@ | ||||
| // ALR - Any Linux Repository | ||||
| // Copyright (C) 2025 The ALR Authors | ||||
| // | ||||
| // This program is free software: you can redistribute it and/or modify | ||||
| // it under the terms of the GNU General Public License as published by | ||||
| // the Free Software Foundation, either version 3 of the License, or | ||||
| // (at your option) any later version. | ||||
| // | ||||
| // This program is distributed in the hope that it will be useful, | ||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
| // GNU General Public License for more details. | ||||
| // | ||||
| // You should have received a copy of the GNU General Public License | ||||
| // along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
|  | ||||
| package build | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"fmt" | ||||
| 	"log/slog" | ||||
| 	"net/rpc" | ||||
| 	"os" | ||||
| 	"os/exec" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/hashicorp/go-plugin" | ||||
|  | ||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/internal/logger" | ||||
| 	"gitea.plemya-x.ru/Plemya-x/ALR/pkg/alrsh" | ||||
| ) | ||||
|  | ||||
| var HandshakeConfig = plugin.HandshakeConfig{ | ||||
| 	ProtocolVersion:  1, | ||||
| 	MagicCookieKey:   "ALR_PLUGIN", | ||||
| 	MagicCookieValue: "-", | ||||
| } | ||||
|  | ||||
| type ScriptExecutorPlugin struct { | ||||
| 	Impl ScriptExecutor | ||||
| } | ||||
|  | ||||
| type ScriptExecutorRPCServer struct { | ||||
| 	Impl ScriptExecutor | ||||
| } | ||||
|  | ||||
| // ============================= | ||||
| // | ||||
| // ReadScript | ||||
| // | ||||
|  | ||||
| func (s *ScriptExecutorRPC) ReadScript(ctx context.Context, scriptPath string) (*alrsh.ScriptFile, error) { | ||||
| 	var resp *alrsh.ScriptFile | ||||
| 	err := s.client.Call("Plugin.ReadScript", scriptPath, &resp) | ||||
| 	return resp, err | ||||
| } | ||||
|  | ||||
| func (s *ScriptExecutorRPCServer) ReadScript(scriptPath string, resp *alrsh.ScriptFile) error { | ||||
| 	file, err := s.Impl.ReadScript(context.Background(), scriptPath) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	*resp = *file | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // ============================= | ||||
| // | ||||
| // ExecuteFirstPass | ||||
| // | ||||
|  | ||||
| type ExecuteFirstPassArgs struct { | ||||
| 	Input *BuildInput | ||||
| 	Sf    *alrsh.ScriptFile | ||||
| } | ||||
|  | ||||
| type ExecuteFirstPassResp struct { | ||||
| 	BasePkg        string | ||||
| 	VarsOfPackages []*alrsh.Package | ||||
| } | ||||
|  | ||||
| func (s *ScriptExecutorRPC) ExecuteFirstPass(ctx context.Context, input *BuildInput, sf *alrsh.ScriptFile) (string, []*alrsh.Package, error) { | ||||
| 	var resp *ExecuteFirstPassResp | ||||
| 	err := s.client.Call("Plugin.ExecuteFirstPass", &ExecuteFirstPassArgs{ | ||||
| 		Input: input, | ||||
| 		Sf:    sf, | ||||
| 	}, &resp) | ||||
| 	if err != nil { | ||||
| 		return "", nil, err | ||||
| 	} | ||||
| 	return resp.BasePkg, resp.VarsOfPackages, nil | ||||
| } | ||||
|  | ||||
| func (s *ScriptExecutorRPCServer) ExecuteFirstPass(args *ExecuteFirstPassArgs, resp *ExecuteFirstPassResp) error { | ||||
| 	basePkg, varsOfPackages, err := s.Impl.ExecuteFirstPass(context.Background(), args.Input, args.Sf) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	*resp = ExecuteFirstPassResp{ | ||||
| 		BasePkg:        basePkg, | ||||
| 		VarsOfPackages: varsOfPackages, | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // ============================= | ||||
| // | ||||
| // PrepareDirs | ||||
| // | ||||
|  | ||||
| type PrepareDirsArgs struct { | ||||
| 	Input   *BuildInput | ||||
| 	BasePkg string | ||||
| } | ||||
|  | ||||
| func (s *ScriptExecutorRPC) PrepareDirs( | ||||
| 	ctx context.Context, | ||||
| 	input *BuildInput, | ||||
| 	basePkg string, | ||||
| ) error { | ||||
| 	err := s.client.Call("Plugin.PrepareDirs", &PrepareDirsArgs{ | ||||
| 		Input:   input, | ||||
| 		BasePkg: basePkg, | ||||
| 	}, nil) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| func (s *ScriptExecutorRPCServer) PrepareDirs(args *PrepareDirsArgs, reply *struct{}) error { | ||||
| 	err := s.Impl.PrepareDirs( | ||||
| 		context.Background(), | ||||
| 		args.Input, | ||||
| 		args.BasePkg, | ||||
| 	) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| // ============================= | ||||
| // | ||||
| // ExecuteSecondPass | ||||
| // | ||||
|  | ||||
| type ExecuteSecondPassArgs struct { | ||||
| 	Input          *BuildInput | ||||
| 	Sf             *alrsh.ScriptFile | ||||
| 	VarsOfPackages []*alrsh.Package | ||||
| 	RepoDeps       []string | ||||
| 	BuiltDeps      []*BuiltDep | ||||
| 	BasePkg        string | ||||
| } | ||||
|  | ||||
| func (s *ScriptExecutorRPC) ExecuteSecondPass( | ||||
| 	ctx context.Context, | ||||
| 	input *BuildInput, | ||||
| 	sf *alrsh.ScriptFile, | ||||
| 	varsOfPackages []*alrsh.Package, | ||||
| 	repoDeps []string, | ||||
| 	builtDeps []*BuiltDep, | ||||
| 	basePkg string, | ||||
| ) ([]*BuiltDep, error) { | ||||
| 	var resp []*BuiltDep | ||||
| 	err := s.client.Call("Plugin.ExecuteSecondPass", &ExecuteSecondPassArgs{ | ||||
| 		Input:          input, | ||||
| 		Sf:             sf, | ||||
| 		VarsOfPackages: varsOfPackages, | ||||
| 		RepoDeps:       repoDeps, | ||||
| 		BuiltDeps:      builtDeps, | ||||
| 		BasePkg:        basePkg, | ||||
| 	}, &resp) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return resp, nil | ||||
| } | ||||
|  | ||||
| func (s *ScriptExecutorRPCServer) ExecuteSecondPass(args *ExecuteSecondPassArgs, resp *[]*BuiltDep) error { | ||||
| 	res, err := s.Impl.ExecuteSecondPass( | ||||
| 		context.Background(), | ||||
| 		args.Input, | ||||
| 		args.Sf, | ||||
| 		args.VarsOfPackages, | ||||
| 		args.RepoDeps, | ||||
| 		args.BuiltDeps, | ||||
| 		args.BasePkg, | ||||
| 	) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	*resp = res | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| // | ||||
| // ============================ | ||||
| // | ||||
|  | ||||
| func (p *ScriptExecutorPlugin) Server(*plugin.MuxBroker) (interface{}, error) { | ||||
| 	return &ScriptExecutorRPCServer{Impl: p.Impl}, nil | ||||
| } | ||||
|  | ||||
| func (p *ScriptExecutorPlugin) Client(b *plugin.MuxBroker, c *rpc.Client) (interface{}, error) { | ||||
| 	return &ScriptExecutorRPC{client: c}, nil | ||||
| } | ||||
|  | ||||
| type ScriptExecutorRPC struct { | ||||
| 	client *rpc.Client | ||||
| } | ||||
|  | ||||
| var pluginMap = map[string]plugin.Plugin{ | ||||
| 	"script-executor": &ScriptExecutorPlugin{}, | ||||
| 	"installer":       &InstallerPlugin{}, | ||||
| } | ||||
|  | ||||
| func GetSafeScriptExecutor() (ScriptExecutor, func(), error) { | ||||
| 	var err error | ||||
|  | ||||
| 	executable, err := os.Executable() | ||||
| 	if err != nil { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
|  | ||||
| 	cmd := exec.Command(executable, "_internal-safe-script-executor") | ||||
| 	setCommonCmdEnv(cmd) | ||||
|  | ||||
| 	client := plugin.NewClient(&plugin.ClientConfig{ | ||||
| 		HandshakeConfig: HandshakeConfig, | ||||
| 		Plugins:         pluginMap, | ||||
| 		Cmd:             cmd, | ||||
| 		Logger:          logger.GetHCLoggerAdapter(), | ||||
| 		SkipHostEnv:     true, | ||||
| 		UnixSocketConfig: &plugin.UnixSocketConfig{ | ||||
| 			Group: "alr", | ||||
| 		}, | ||||
| 		SyncStderr: os.Stderr, | ||||
| 	}) | ||||
| 	rpcClient, err := client.Client() | ||||
| 	if err != nil { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
|  | ||||
| 	var cleanupOnce sync.Once | ||||
| 	cleanup := func() { | ||||
| 		cleanupOnce.Do(func() { | ||||
| 			client.Kill() | ||||
| 		}) | ||||
| 	} | ||||
|  | ||||
| 	defer func() { | ||||
| 		if err != nil { | ||||
| 			slog.Debug("close script-executor") | ||||
| 			cleanup() | ||||
| 		} | ||||
| 	}() | ||||
|  | ||||
| 	raw, err := rpcClient.Dispense("script-executor") | ||||
| 	if err != nil { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
|  | ||||
| 	executor, ok := raw.(ScriptExecutor) | ||||
| 	if !ok { | ||||
| 		err = fmt.Errorf("dispensed object is not a ScriptExecutor (got %T)", raw) | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
|  | ||||
| 	return executor, cleanup, nil | ||||
| } | ||||
		Reference in New Issue
	
	Block a user