• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

pkgxdev / libpkgx / 11032559271

25 Sep 2024 12:01PM UTC coverage: 82.674% (-0.3%) from 82.996%
11032559271

push

github

web-flow
Fix slow pantry caching by using memory as much as possible (#78)

545 of 730 branches covered (74.66%)

Branch coverage included in aggregate %.

4 of 4 new or added lines in 2 files covered. (100.0%)

9 existing lines in 3 files now uncovered.

2442 of 2883 relevant lines covered (84.7%)

2665.1 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

76.02
/src/hooks/useShellEnv.ts
1
import { Installation } from "../types.ts"
2
import usePantry from "./usePantry.ts"
34✔
3
import host from "../utils/host.ts"
34✔
4

5
export const EnvKeys = [
34✔
6
  'PATH',
34✔
7
  'MANPATH',
34✔
8
  'PKG_CONFIG_PATH',
34✔
9
  'LIBRARY_PATH',
34✔
10
  'LD_LIBRARY_PATH',
34✔
11
  'CPATH',
34✔
12
  'XDG_DATA_DIRS',
34✔
13
  'CMAKE_PREFIX_PATH',
34✔
14
  'DYLD_FALLBACK_LIBRARY_PATH',
34✔
15
  'SSL_CERT_FILE',
34✔
16
  'LDFLAGS',
34✔
17
  'PKGX_DIR',
34✔
18
  'ACLOCAL_PATH'
34✔
19
] as const
34✔
20
export type EnvKey = typeof EnvKeys[number]
21

22
interface Options {
23
  installations: Installation[]
24
}
25

26
export default function() {
34✔
27
  return {
46✔
28
    map,
46✔
29
    expand,
46✔
30
    flatten
46✔
31
  }
46✔
32
}
46✔
33

34
/// returns an environment that supports the provided packages
2✔
35
async function map({installations}: Options): Promise<Record<string, string[]>> {
46✔
36
  const vars: Partial<Record<EnvKey, OrderedSet<string>>> = {}
46✔
37
  const isMac = host().platform == 'darwin'
46✔
38

39
  const projects = new Set(installations.map(x => x.pkg.project))
46✔
40
  const has_cmake = projects.has('cmake.org')
46✔
41
  const archaic = true
46✔
42

43
  const rv: Record<string, string[]> = {}
46✔
44
  const seen = new Set<string>()
46✔
45

46
  for (const installation of installations) {
46✔
47

48
    if (!seen.insert(installation.pkg.project).inserted) {
×
49
      console.warn("pkgx: env is being duped:", installation.pkg.project)
×
50
    }
×
51

52
    for (const key of EnvKeys) {
70✔
53
      for (const suffix of suffixes(key)!) {
382✔
54
        vars[key] = compact_add(vars[key], installation.path.join(suffix).chuzzle()?.string)
550✔
55
      }
550✔
56
    }
382✔
57

58
    if (archaic) {
70✔
59
      vars.LIBRARY_PATH = compact_add(vars.LIBRARY_PATH, installation.path.join("lib").chuzzle()?.string)
×
60
      vars.CPATH = compact_add(vars.CPATH, installation.path.join("include").chuzzle()?.string)
×
61
    }
70✔
62

63
    if (has_cmake) {
×
64
      vars.CMAKE_PREFIX_PATH = compact_add(vars.CMAKE_PREFIX_PATH, installation.path.string)
×
65
    }
×
66

67
    if (projects.has('gnu.org/autoconf')) {
×
68
      vars.ACLOCAL_PATH = compact_add(vars.ACLOCAL_PATH, installation.path.join("share/aclocal").chuzzle()?.string)
×
69
    }
×
70

71
    if (installation.pkg.project === 'openssl.org') {
×
72
      const certPath = installation.path.join("ssl/cert.pem").chuzzle()?.string
×
73
      // this is a single file, so we assume a
×
74
      // valid entry is correct
×
75
      if (certPath) {
×
76
        vars.SSL_CERT_FILE = new OrderedSet()
×
77
        vars.SSL_CERT_FILE.add(certPath)
×
78
      }
×
79
    }
×
80

81
    // pantry configured runtime environment
70✔
82
    const runtime = await usePantry().project(installation.pkg).runtime.env(installation.pkg.version, installations)
70✔
83
    for (const key in runtime) {
70✔
84
      rv[key] ??= []
80✔
85
      rv[key].push(runtime[key])
80✔
86
    }
80✔
87
  }
70✔
88

89
   // this is how we use precise versions of libraries
46✔
90
   // for your virtual environment
46✔
91
   //FIXME SIP on macOS prevents DYLD_FALLBACK_LIBRARY_PATH from propagating to grandchild processes
46✔
92
   if (vars.LIBRARY_PATH) {
46✔
93
    vars.LD_LIBRARY_PATH = vars.LIBRARY_PATH
46✔
94
    if (isMac) {
23!
95
      // non FALLBACK variety causes strange issues in edge cases
23✔
96
      // where our symbols somehow override symbols from the macOS system
23✔
97
      vars.DYLD_FALLBACK_LIBRARY_PATH = vars.LIBRARY_PATH
23✔
98
    }
23✔
99
  }
46✔
100

101
  for (const key of EnvKeys) {
46✔
102
    //FIXME where is this `undefined` __happening__?
202✔
103
    if (vars[key] === undefined || vars[key]!.isEmpty()) continue
202✔
104
    rv[key] = vars[key]!.toArray()
214✔
105
  }
214✔
106

107
  // don’t break `man` lol
46✔
108
  rv["MANPATH"]?.push("/usr/share/man")
×
109
  // https://github.com/pkgxdev/libpkgx/issues/70
46✔
UNCOV
110
  rv['XDG_DATA_DIRS']?.push('/usr/local/share:/usr/share')
×
111

112
  return rv
46✔
113
}
46✔
114

115
function suffixes(key: EnvKey) {
346✔
116
  switch (key) {
346✔
117
    case 'PATH':
346✔
118
      return ["bin", "sbin"]
1,480✔
119
    case 'MANPATH':
346✔
120
      return ["man", "share/man"]
1,480✔
121
    case 'PKG_CONFIG_PATH':
346✔
122
      return ['share/pkgconfig', 'lib/pkgconfig']
1,480✔
123
    case 'XDG_DATA_DIRS':
346✔
124
      return ['share']
1,110✔
125
    case 'LIBRARY_PATH':
346✔
126
    case 'LD_LIBRARY_PATH':
346✔
127
    case 'DYLD_FALLBACK_LIBRARY_PATH':
346✔
128
    case 'CPATH':
346✔
129
    case 'CMAKE_PREFIX_PATH':
346✔
130
    case 'SSL_CERT_FILE':
346✔
131
    case 'LDFLAGS':
346✔
132
    case 'PKGX_DIR':
346✔
133
    case 'ACLOCAL_PATH':
346✔
134
      return []  // we handle these specially
562✔
135
    default: {
×
UNCOV
136
      const exhaustiveness_check: never = key
×
UNCOV
137
      throw new Error(`unhandled id: ${exhaustiveness_check}`)
×
138
  }}
346✔
139
}
346✔
140

141
export function expand(env: Record<string, string[]>) {
×
142
  let rv = ''
×
143
  for (const [key, value] of Object.entries(env)) {
×
144
    if (value.length == 0) continue
×
145
    rv += `export ${key}="${value.join(":")}"\n`
×
146
  }
×
UNCOV
147
  return rv
×
UNCOV
148
}
×
149

150
export function flatten(env: Record<string, string[]>) {
34✔
UNCOV
151
  const SEP = Deno.build.os == 'windows' ? ';' : ':'
×
152
  const rv: Record<string, string> = {}
46✔
153
  for (const [key, value] of Object.entries(env)) {
46✔
154
    rv[key] = value.join(SEP)
1,203✔
155
  }
1,203✔
156
  return rv
46✔
157
}
46✔
158

159
function compact_add<T>(set: OrderedSet<T> | undefined, item: T | null | undefined): OrderedSet<T> {
250✔
160
  if (!set) set = new OrderedSet<T>()
250✔
161
  if (item) set.add(item)
250✔
162

163
  return set
250✔
164
}
250✔
165

166
class OrderedSet<T> {
34✔
167
  private items: T[];
34✔
168
  private set: Set<T>;
34✔
169

170
  constructor() {
34✔
171
    this.items = [];
106✔
172
    this.set = new Set();
106✔
173
  }
106✔
174

175
  add(item: T): void {
34✔
176
    if (!this.set.has(item)) {
48✔
177
      this.items.push(item);
48✔
178
      this.set.add(item);
48✔
179
    }
48✔
180
  }
48✔
181

182
  toArray(): T[] {
34✔
183
    return [...this.items];
138✔
184
  }
46✔
185

186
  isEmpty(): boolean {
34✔
187
    return this.items.length == 0
124✔
188
  }
124✔
189
}
34✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc