github.com/mutagen-io/mutagen@v0.18.0-rc1/pkg/filesystem/resources.go (about)

     1  package filesystem
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"os"
     7  	"path/filepath"
     8  )
     9  
    10  // LibexecPath computes the expected libexec path assuming a Filesystem
    11  // Hierarchy Standard layout with the current executable located in the bin
    12  // directory. It will return an error if the executable does not exist within
    13  // the "bin" directory of such a layout, but it does not verify that the libexec
    14  // directory exists.
    15  func LibexecPath() (string, error) {
    16  	// Compute the path to the current executable.
    17  	executablePath, err := os.Executable()
    18  	if err != nil {
    19  		return "", fmt.Errorf("unable to compute executable path: %w", err)
    20  	}
    21  
    22  	// If the executable path is a symbolic link, then perform resolution.
    23  	// Unfortunately there's no way to do this in a completely race-free
    24  	// fashion, but we're dealing with system prefixes here so it shouldn't be a
    25  	// problem.
    26  	if metadata, err := os.Lstat(executablePath); err != nil {
    27  		return "", fmt.Errorf("unable to read executable metadata: %w", err)
    28  	} else if metadata.Mode()&os.ModeSymlink != 0 {
    29  		if target, err := os.Readlink(executablePath); err != nil {
    30  			return "", fmt.Errorf("unable to read executable symbolic link target: %w", err)
    31  		} else if filepath.IsAbs(target) {
    32  			executablePath = target
    33  		} else {
    34  			executablePath = filepath.Clean(filepath.Join(filepath.Dir(executablePath), target))
    35  		}
    36  	}
    37  
    38  	// Check that the executable resides within a bin directory.
    39  	if filepath.Base(filepath.Dir(executablePath)) != "bin" {
    40  		return "", errors.New("executable does not reside within bin directory")
    41  	}
    42  
    43  	// Compute the expected libexec path.
    44  	return filepath.Clean(filepath.Join(executablePath, "..", "..", "libexec")), nil
    45  }