fix: executable path in hooks (#459)

Ashish and Ayman Bagabas created

* fix: executable path in hooks

On platforms, where soft-serve executable gets installed in a path that
is not the same throughout installation, or upgrades, hooks break. Some
examples of such a situation is when moving soft-serve repositories from
one OS to another OS, or on NixOS/Guix

This commit passes the path to the current executable as an environment
variable $SOFT_SERVE_BIN_PATH to the hooks.

To fix/update existing repository hooks:

  [/path/to/soft-serve/repos] $ grep -ERl \
   '^[^[:space:]]+soft-serve[^[:space:]]+' . | xargs sed -r -e \
   's,^([^[:space:]]*soft-serve[^[:space:]]*),"${SOFT_SERVE_BIN_PATH}",g' -i

Signed-off-by: Ashish SHUKLA <ashish.is@lostca.se>
Co-authored-by: Ayman Bagabas <ayman.bagabas@gmail.com>

* fix: update pkg/config/config.go

* fix: update pkg/config/config.go

---------

Signed-off-by: Ashish SHUKLA <ashish.is@lostca.se>
Co-authored-by: Ayman Bagabas <ayman.bagabas@gmail.com>

Change summary

pkg/config/config.go | 12 +++++++++++-
pkg/hooks/gen.go     | 12 ++----------
2 files changed, 13 insertions(+), 11 deletions(-)

Detailed changes

pkg/config/config.go 🔗

@@ -14,6 +14,8 @@ import (
 	"gopkg.in/yaml.v3"
 )
 
+var binPath = "soft"
+
 // SSHConfig is the configuration for the SSH server.
 type SSHConfig struct {
 	// ListenAddr is the address on which the SSH server will listen.
@@ -151,7 +153,9 @@ type Config struct {
 
 // Environ returns the config as a list of environment variables.
 func (c *Config) Environ() []string {
-	envs := []string{}
+	envs := []string{
+		fmt.Sprintf("SOFT_SERVE_BIN_PATH=%s", binPath),
+	}
 	if c == nil {
 		return envs
 	}
@@ -419,3 +423,9 @@ func parseAuthKeys(aks []string) []ssh.PublicKey {
 func (c *Config) AdminKeys() []ssh.PublicKey {
 	return parseAuthKeys(c.InitialAdminKeys)
 }
+
+func init() {
+	if ex, err := os.Executable(); err == nil {
+		binPath = filepath.ToSlash(ex)
+	}
+}

pkg/hooks/gen.go 🔗

@@ -35,14 +35,6 @@ func GenerateHooks(_ context.Context, cfg *config.Config, repo string) error {
 		return err
 	}
 
-	ex, err := os.Executable()
-	if err != nil {
-		return err
-	}
-
-	// Convert to forward slashes for Windows.
-	ex = filepath.ToSlash(ex)
-
 	for _, hook := range []string{
 		PreReceiveHook,
 		UpdateHook,
@@ -78,7 +70,7 @@ func GenerateHooks(_ context.Context, cfg *config.Config, repo string) error {
 			Hook       string
 			Args       string
 		}{
-			Executable: ex,
+			Executable: "\"${SOFT_SERVE_BIN_PATH}\"",
 			Hook:       hook,
 			Args:       args,
 		}); err != nil {
@@ -88,7 +80,7 @@ func GenerateHooks(_ context.Context, cfg *config.Config, repo string) error {
 
 		// Write the soft-serve hook inside ${hook}.d directory.
 		hp = filepath.Join(hp, "soft-serve")
-		err = os.WriteFile(hp, data.Bytes(), os.ModePerm) //nolint:gosec
+		err := os.WriteFile(hp, data.Bytes(), os.ModePerm) //nolint:gosec
 		if err != nil {
 			log.WithPrefix("hooks").Error("failed to write hook", "err", err)
 			continue