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

pkgxdev / pkgx / 10739945979

06 Sep 2024 02:14PM UTC coverage: 93.36% (-0.6%) from 93.977%
10739945979

push

github

web-flow
Use deno 1.45: binaries ~25% smaller, ~10% faster (#978)

* dep on deno 1.40

* Bump deno to 1.41

* Relax deno from 1.41.0 to 1.41

* Use pkgx's denort

* Restore deno.lock

* Pin deno to 1.41.2, regenerate the lockfile

* Deno 1.42

* Add benchmark

* Fix compile task when using official's deno

* Try to improve benchmark

* Improve bench again

* deno 1.42.1

* cliffy@1.0.0-rc.4, @deno/std@0.221.0

Regenerated the lock file as well.

* Revert compile task after pkgxdev/pantry#5750

* Delete benchmark script

* Remove other bench file

* deno 1.42.3

* deno 1.42.4

* deno@1.43.0

* Deno 1.44

* deno 1.44.4

* Fix some flaky execve tests

* Undo formatting changes

* Update Deno from 1.44.4 to 1.46.3

* Downgrade Deno from 1.46 to 1.45

---------

Co-authored-by: Max Howell <mxcl@me.com>

402 of 438 branches covered (91.78%)

18 of 19 new or added lines in 2 files covered. (94.74%)

1454 of 1550 relevant lines covered (93.81%)

157.74 hits per line

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

91.58
/src/utils/execve.ts
1
import { ProgrammerError } from "./error.ts"
6✔
2
import { utils, Path, PkgxError } from "pkgx"
6✔
3
const { host } = utils
6✔
4

5
export default function({cmd: args, env}: {cmd: string[], env: Record<string, string>}): never {
6✔
6
  /// we need to forward any other env, some vars like HOME are super important
24✔
7
  /// but otherwise the user has set stuff so we should use it
24✔
8
  for (const [key, value] of Object.entries(Deno.env.toObject())) {
24✔
9
    env[key] ??= value
2,157✔
10
  }
2,157✔
11

12
  find_in_PATH(args, env.PATH, Path.abs(env.HOME))
24✔
13

14
  const path = cstr(args[0])
24✔
15
  const argv = new CStringArray(args)
24✔
16
  const envp = new CStringArray(Object.entries(env).map(([key, value]) => `${key}=${value}`))
24✔
17

18
  const errno = (() => {
24✔
19
    let tries = 10;
42✔
20
    while (true) {
42✔
21
      const errno = _internals.execve(
52✔
22
        Deno.UnsafePointer.of(path),
52✔
23
        Deno.UnsafePointer.of(argv),
52✔
24
        Deno.UnsafePointer.of(envp)
52✔
25
      );
NEW
26
      if (!tries--) return errno;
×
27
      // 11 = EAGAIN = Try again
52✔
28
      if (errno == 11) continue;
31!
29
      return errno;
61✔
30
    }
61✔
31
  })();
24✔
32

33
  switch (errno) {
24✔
34
    case 2:   //ENOENT:
24✔
35
    case 316: //FIXME ALERT! ALERT! BUG! SOMETHING IS WRONG WITH OUR USE OR ERRNO AND THIS SOMETIMES RESULTS, USUALLY ON MACOS :/
24✔
36
      // yes: strange behavior from execve here indeed
33✔
37
      if (parse_Path(args[0])?.exists()) {
33✔
38
        throw new Deno.errors.PermissionDenied()
38✔
39
      } else {
35✔
40
        throw new Deno.errors.NotFound()
37✔
41
      }
37✔
42
    case 13:
12!
43
      throw new Deno.errors.PermissionDenied()
13✔
44
    case 63: //ENAMETOOLONG:
12!
45
    case 7:  //E2BIG:
12!
46
    case 14: //EFAULT:
12!
47
    case 5:  //EIO:
12!
48
    case 62: //ELOOP:
12!
49
    case 8:  //ENOEXEC:
12!
50
    case 12: //ENOMEM:
12!
51
    case 20: //ENOTDIR:
12!
52
    case 26: //ETXTBSY:
12!
53
      throw new PkgxError(`execve (${errno})`)
13✔
54
  }
24✔
55

56
  throw new ProgrammerError(`execve (${errno})`)
31✔
57
}
24✔
58

59
export function parse_Path(input: string) {
6✔
60
  const p = Path.abs(input)
15✔
61
  if (p) return p
15✔
62
  try {
19✔
63
    return _internals.getcwd().join(input)
19✔
64
  } catch {
15✔
65
    return
17✔
66
  }
17✔
67
}
15✔
68

69
function find_in_PATH(cmd: string[], PATH: string | undefined, HOME: Path | undefined) {
24✔
70
  if (cmd[0].startsWith("/")) {
24✔
71
    return
30✔
72
  }
30✔
73
  if (cmd[0].includes("/")) {
24✔
74
    cmd[0] = _internals.getcwd().join(cmd[0]).string
26✔
75
    return
26✔
76
  }
26✔
77

78
  PATH ??= "/usr/bin:/bin"  // see manpage for execvp(3)
34✔
79

80
  for (const part of PATH.split(':')) {
24✔
81
    const path = (() => {
192✔
82
      if (part == '.') return _internals.getcwd()
360✔
83
      if (part == '~') return HOME
360✔
84
      if (part.startsWith('~/')) return HOME?.join(part.slice(2))
360✔
85
      //FIXME: not handled: ~user/...
522✔
86
      return new Path(part)
522✔
87
    })()?.join(cmd[0])
192✔
88
    if (path?.isExecutableFile()) {
192✔
89
      cmd[0] = path.string
194✔
90
      return
194✔
91
    }
194✔
92
  }
192✔
93
}
24✔
94

95

96
////// COPY PASTA
2✔
97
// actually minor mods to add trailing null
2✔
98
// https://github.com/aapoalas/libclang_deno/blob/main/lib/utils.ts
2✔
99

100
const ENCODER = new TextEncoder();
6✔
101

102
export class CStringArray extends Uint8Array {
6✔
103
  constructor(strings: string[]) {
6✔
104
    let stringsLength = 0;
42✔
105
    for (const string of strings) {
42✔
106
      // maximum bytes for a utf8 string is 4×length
2,256✔
107
      stringsLength += string.length * 4 + 1;
2,256✔
108
    }
2,256✔
109
    super(8 * (strings.length + 1) + stringsLength);
42✔
110
    const pointerBuffer = new BigUint64Array(this.buffer, 0, strings.length + 1);
42✔
111
    const stringsBuffer = new Uint8Array(this.buffer).subarray(
42✔
112
      (strings.length + 1) * 8,
42✔
113
    );
114
    const basePointer = BigInt(
42✔
115
      Deno.UnsafePointer.value(Deno.UnsafePointer.of(stringsBuffer)),
42✔
116
    );
117
    let index = 0;
42✔
118
    let offset = 0;
42✔
119
    for (const string of strings) {
42✔
120
      const start = offset;
2,256✔
121
      const result = ENCODER.encodeInto(
2,256✔
122
        string,
2,256✔
123
        stringsBuffer.subarray(start),
2,256✔
124
      );
125
      offset = start + result.written + 1; // Leave null byte
2,256✔
126
      pointerBuffer[index++] = basePointer + BigInt(start);
2,256✔
127
    }
2,256✔
128
  }
42✔
129
}
6✔
130

131
export const cstr = (string: string): Uint8Array =>
6✔
132
  ENCODER.encode(`${string}\0`);
6✔
133

134
function execve(arg0: Deno.PointerValue, args: Deno.PointerValue, env: Deno.PointerValue) {
19✔
135
  const filename = host().platform == 'darwin' ? '/usr/lib/libSystem.dylib' : 'libc.so.6'
×
136

137
  const libc = Deno.dlopen(
19✔
138
    filename, {
19✔
139
      execve: {
19✔
140
        parameters: ["pointer", "pointer", "pointer"],
95✔
141
        result: "i32"
19✔
142
      },
19✔
143
      errno: {
19✔
144
        type: "i32"
19✔
145
      }
19✔
146
    }
19✔
147
  )
148

149
  try {
19✔
150
    libc.symbols.execve(arg0, args, env)
19✔
151
    return libc.symbols.errno
19✔
152
  } finally {
19✔
153
    libc.close()
19✔
154
  }
19✔
155
}
19✔
156

157
export const _internals = {
6✔
158
  execve,
6✔
159
  getcwd: Path.cwd
6✔
160
}
6✔
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