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

pkgxdev / libpkgx / 6550697403

17 Oct 2023 05:23PM UTC coverage: 80.492%. First build
6550697403

Pull #48

github

web-flow
Merge 03116fcb6 into 99c9c22af
Pull Request #48: v1 wip

469 of 660 branches covered (0.0%)

Branch coverage included in aggregate %.

161 of 183 new or added lines in 13 files covered. (87.98%)

2151 of 2595 relevant lines covered (82.89%)

986.32 hits per line

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

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

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

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

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

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

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

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

46
  for (const installation of installations) {
15✔
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) {
33✔
53
      for (const suffix of suffixes(key)!) {
267✔
54
        vars[key] = compact_add(vars[key], installation.path.join(suffix).chuzzle()?.string)
393✔
55
      }
393✔
56
    }
267✔
57

58
    if (archaic) {
33✔
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
    }
33✔
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
33✔
82
    const runtime = await usePantry().project(installation.pkg).runtime.env(installation.pkg.version, installations)
33✔
83
    for (const key in runtime) {
33✔
84
      rv[key] ??= []
39✔
85
      rv[key].push(runtime[key])
39✔
86
    }
39✔
87
  }
33✔
88

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

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

107
  // don’t break `man` lol
15✔
108
  rv["MANPATH"]?.push("/usr/share/man")
×
109

110
  return rv
15✔
111
}
15✔
112

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

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

148
export function flatten(env: Record<string, string[]>) {
6✔
NEW
149
  const SEP = Deno.build.os == 'windows' ? ';' : ':'
×
150
  const rv: Record<string, string> = {}
15✔
151
  for (const [key, value] of Object.entries(env)) {
15✔
152
    rv[key] = value.join(SEP)
770✔
153
  }
770✔
154
  return rv
15✔
155
}
15✔
156

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

161
  return set
168✔
162
}
168✔
163

164
class OrderedSet<T> {
6✔
165
  private items: T[];
60✔
166
  private set: Set<T>;
60✔
167

168
  constructor() {
60✔
169
    this.items = [];
114✔
170
    this.set = new Set();
114✔
171
  }
114✔
172

173
  add(item: T): void {
60✔
174
    if (!this.set.has(item)) {
72✔
175
      this.items.push(item);
72✔
176
      this.set.add(item);
72✔
177
    }
72✔
178
  }
72✔
179

180
  toArray(): T[] {
60✔
181
    return [...this.items];
207✔
182
  }
69✔
183

184
  isEmpty(): boolean {
60✔
185
    return this.items.length == 0
126✔
186
  }
126✔
187
}
60✔
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