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

pkgxdev / libpkgx / 7686417725

28 Jan 2024 02:29PM UTC coverage: 83.59% (-0.09%) from 83.677%
7686417725

Pull #63

github

web-flow
Merge fec0d09fb into 653cd582e
Pull Request #63: deno 1.4.0

522 of 704 branches covered (0.0%)

Branch coverage included in aggregate %.

2244 of 2605 relevant lines covered (86.14%)

1181.7 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 {
24✔
28
    map,
24✔
29
    expand,
24✔
30
    flatten
24✔
31
  }
24✔
32
}
24✔
33

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

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

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

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

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

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

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

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

110
  return rv
24✔
111
}
24✔
112

113
function suffixes(key: EnvKey) {
474✔
114
  switch (key) {
474✔
115
    case 'PATH':
474✔
116
      return ["bin", "sbin"]
2,040✔
117
    case 'MANPATH':
474✔
118
      return ["man", "share/man"]
2,040✔
119
    case 'PKG_CONFIG_PATH':
474✔
120
      return ['share/pkgconfig', 'lib/pkgconfig']
2,040✔
121
    case 'XDG_DATA_DIRS':
474✔
122
      return ['share']
1,530✔
123
    case 'LIBRARY_PATH':
474✔
124
    case 'LD_LIBRARY_PATH':
474✔
125
    case 'DYLD_FALLBACK_LIBRARY_PATH':
474✔
126
    case 'CPATH':
474✔
127
    case 'CMAKE_PREFIX_PATH':
474✔
128
    case 'SSL_CERT_FILE':
474✔
129
    case 'LDFLAGS':
474✔
130
    case 'PKGX_DIR':
474✔
131
    case 'ACLOCAL_PATH':
474✔
132
      return []  // we handle these specially
798✔
133
    default: {
×
134
      const exhaustiveness_check: never = key
×
135
      throw new Error(`unhandled id: ${exhaustiveness_check}`)
×
136
  }}
474✔
137
}
474✔
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✔
149
  const SEP = Deno.build.os == 'windows' ? ';' : ':'
×
150
  const rv: Record<string, string> = {}
24✔
151
  for (const [key, value] of Object.entries(env)) {
24✔
152
    rv[key] = value.join(SEP)
1,932✔
153
  }
1,932✔
154
  return rv
24✔
155
}
24✔
156

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

161
  return set
330✔
162
}
330✔
163

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

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

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

180
  toArray(): T[] {
114✔
181
    return [...this.items];
396✔
182
  }
132✔
183

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