1package deps
2
3import (
4 "os"
5 "path/filepath"
6 "strings"
7)
8
9// ApplyPrefixEnv prepends environment variables derived from prefix.
10//
11// This is used to support manual runtime installs under /opt.
12func ApplyPrefixEnv(prefix string) {
13 if strings.TrimSpace(prefix) == "" {
14 return
15 }
16
17 for key, values := range prefixEnv(prefix) {
18 _ = os.Setenv(key, prependPathList(os.Getenv(key), values...))
19 }
20}
21
22// CommandEnvWithPrefix returns an environment suitable for exec.Cmd.Env.
23// It prepends prefix-derived paths to the current environment.
24func CommandEnvWithPrefix(prefix string) []string {
25 if strings.TrimSpace(prefix) == "" {
26 return os.Environ()
27 }
28
29 updates := prefixEnv(prefix)
30 base := os.Environ()
31
32 // Convert base env to map.
33 m := make(map[string]string, len(base))
34 for _, kv := range base {
35 k, v, ok := strings.Cut(kv, "=")
36 if ok {
37 m[k] = v
38 }
39 }
40
41 for k, values := range updates {
42 m[k] = prependPathList(m[k], values...)
43 }
44
45 out := make([]string, 0, len(m))
46 for k, v := range m {
47 out = append(out, k+"="+v)
48 }
49 return out
50}
51
52func prefixEnv(prefix string) map[string][]string {
53 prefix = filepath.Clean(prefix)
54
55 pkgConfig := []string{
56 filepath.Join(prefix, "lib", "pkgconfig"),
57 filepath.Join(prefix, "lib64", "pkgconfig"),
58 filepath.Join(prefix, "share", "pkgconfig"),
59 filepath.Join(prefix, "lib", "x86_64-linux-gnu", "pkgconfig"),
60 filepath.Join(prefix, "lib64", "x86_64-linux-gnu", "pkgconfig"),
61 }
62
63 ldLibrary := []string{
64 filepath.Join(prefix, "lib"),
65 filepath.Join(prefix, "lib64"),
66 filepath.Join(prefix, "lib", "x86_64-linux-gnu"),
67 filepath.Join(prefix, "lib64", "x86_64-linux-gnu"),
68 }
69
70 giTypelib := []string{
71 filepath.Join(prefix, "lib", "girepository-1.0"),
72 filepath.Join(prefix, "lib64", "girepository-1.0"),
73 filepath.Join(prefix, "lib", "x86_64-linux-gnu", "girepository-1.0"),
74 filepath.Join(prefix, "lib64", "x86_64-linux-gnu", "girepository-1.0"),
75 }
76
77 xdgData := []string{
78 filepath.Join(prefix, "share"),
79 }
80
81 return map[string][]string{
82 "PKG_CONFIG_PATH": pkgConfig,
83 "LD_LIBRARY_PATH": ldLibrary,
84 "GI_TYPELIB_PATH": giTypelib,
85 "XDG_DATA_DIRS": xdgData,
86 }
87}
88
89func prependPathList(existing string, values ...string) string {
90 seen := map[string]struct{}{}
91 out := make([]string, 0, len(values)+4)
92
93 add := func(p string) {
94 p = strings.TrimSpace(p)
95 if p == "" {
96 return
97 }
98 if _, ok := seen[p]; ok {
99 return
100 }
101 seen[p] = struct{}{}
102 out = append(out, p)
103 }
104
105 for _, v := range values {
106 add(v)
107 }
108
109 if existing != "" {
110 for _, v := range strings.Split(existing, ":") {
111 add(v)
112 }
113 }
114
115 return strings.Join(out, ":")
116}