mirror of
https://github.com/oven-sh/bun
synced 2026-02-06 17:08:51 +00:00
Compare commits
11 Commits
dylan/pyth
...
claude/ref
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ba8eccd72e | ||
|
|
648340d359 | ||
|
|
d5ddad66a5 | ||
|
|
b43d6a6cf2 | ||
|
|
bb07da19a7 | ||
|
|
bcebf4e663 | ||
|
|
61fb05a7c8 | ||
|
|
d8fe6471ff | ||
|
|
5ba8c4feda | ||
|
|
a3f269b13a | ||
|
|
04d498cfc4 |
109
bun.lock
109
bun.lock
@@ -3,6 +3,9 @@
|
||||
"workspaces": {
|
||||
"": {
|
||||
"name": "bun",
|
||||
"dependencies": {
|
||||
"2": "^3.0.0",
|
||||
},
|
||||
"devDependencies": {
|
||||
"@lezer/common": "^1.2.3",
|
||||
"@lezer/cpp": "^1.1.3",
|
||||
@@ -43,6 +46,8 @@
|
||||
"bun-types": "workspace:packages/bun-types",
|
||||
},
|
||||
"packages": {
|
||||
"2": ["2@3.0.0", "", { "dependencies": { "@lamansky/every": "^1.0.0", "add-counter": "^1.0.0", "empty-iterator": "^1.0.0", "is-array-of-length": "^1.0.0", "is-instance-of": "^1.0.2", "is-iterable": "^1.1.1", "is-nil": "^1.0.1", "is-object": "^1.0.1", "map-iter": "^1.0.0", "new-object": "^4.0.0", "otherwise": "^2.0.0", "parser-factory": "^1.1.0", "round-to": "^4.0.0", "sbo": "^1.1.0" } }, "sha512-Cq+wWyyKElk0zOk/ev7r4+pNJTa7V0fUKP/5ii4I47dn0E0QoY4VzqbIpfnkPQQPWuZzKj3oNzNT0MA657zkpw=="],
|
||||
|
||||
"@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.21.5", "", { "os": "aix", "cpu": "ppc64" }, "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ=="],
|
||||
|
||||
"@esbuild/android-arm": ["@esbuild/android-arm@0.21.5", "", { "os": "android", "cpu": "arm" }, "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg=="],
|
||||
@@ -89,6 +94,10 @@
|
||||
|
||||
"@esbuild/win32-x64": ["@esbuild/win32-x64@0.21.5", "", { "os": "win32", "cpu": "x64" }, "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw=="],
|
||||
|
||||
"@lamansky/every": ["@lamansky/every@1.0.0", "", { "dependencies": { "ffn": "^2.1.0", "plainify": "^1.0.0", "sbo": "^1.1.0" } }, "sha512-mbu6EV7RApOvzjE5RJqCneWFNVkrq1lYpIfOKwc39ngmfqNdGhCO8QYOFmESChIcCjn28zrNMPm1/pDrTAToMg=="],
|
||||
|
||||
"@lamansky/flatten": ["@lamansky/flatten@1.0.0", "", { "dependencies": { "sbo": "^1.0.0" } }, "sha512-4u7TNkdIjYD0JKwNCJFSBIwj92DN4y/+nGNHB104CmQUrNYyxwmm/fto8k7S+4H9rSeDityPyGhiPqMy4ukxYg=="],
|
||||
|
||||
"@lezer/common": ["@lezer/common@1.2.3", "", {}, "sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA=="],
|
||||
|
||||
"@lezer/cpp": ["@lezer/cpp@1.1.3", "", { "dependencies": { "@lezer/common": "^1.2.0", "@lezer/highlight": "^1.0.0", "@lezer/lr": "^1.0.0" } }, "sha512-ykYvuFQKGsRi6IcE+/hCSGUhb/I4WPjd3ELhEblm2wS2cOznDFzO+ubK2c+ioysOnlZ3EduV+MVQFCPzAIoY3w=="],
|
||||
@@ -163,8 +172,14 @@
|
||||
|
||||
"@types/react": ["@types/react@19.1.8", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-AwAfQ2Wa5bCx9WP8nZL2uMZWod7J7/JSplxbTmBQ5ms6QpqNYm672H0Vu9ZVKVngQ+ii4R/byguVEUZQyeg44g=="],
|
||||
|
||||
"add-counter": ["add-counter@1.0.0", "", {}, "sha512-0CTbBx0nmG090qY9kmAcN/Z87W5dQUT5lfwqzYz881+3vciNGAK0d6vGt/lUye6NZGhmQBfJTo/lvfZHb+0l1Q=="],
|
||||
|
||||
"aggregate-error": ["aggregate-error@3.1.0", "", { "dependencies": { "clean-stack": "^2.0.0", "indent-string": "^4.0.0" } }, "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA=="],
|
||||
|
||||
"array-pad": ["array-pad@0.0.1", "", {}, "sha512-uVzGjO5dqUHanQoCWJFEsf4boWOagEGQAx4HY67s0mYYmzo1eXnV12SOpH9v1lNfop6bUyBUI+IJlOofMUgZAg=="],
|
||||
|
||||
"arrify": ["arrify@1.0.1", "", {}, "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA=="],
|
||||
|
||||
"before-after-hook": ["before-after-hook@2.2.3", "", {}, "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ=="],
|
||||
|
||||
"bottleneck": ["bottleneck@2.19.5", "", {}, "sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw=="],
|
||||
@@ -181,8 +196,12 @@
|
||||
|
||||
"capital-case": ["capital-case@1.0.4", "", { "dependencies": { "no-case": "^3.0.4", "tslib": "^2.0.3", "upper-case-first": "^2.0.2" } }, "sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A=="],
|
||||
|
||||
"case-insensitive": ["case-insensitive@1.0.0", "", {}, "sha512-dnPuuPchX250ivRdSGfiqlgJ3eJYmxGx9WiCNIxVjjIYd7dXSLx2c4kFJOiVvdvrxxZagqPSgnLGR58EMKhznA=="],
|
||||
|
||||
"change-case": ["change-case@4.1.2", "", { "dependencies": { "camel-case": "^4.1.2", "capital-case": "^1.0.4", "constant-case": "^3.0.4", "dot-case": "^3.0.4", "header-case": "^2.0.4", "no-case": "^3.0.4", "param-case": "^3.0.4", "pascal-case": "^3.1.2", "path-case": "^3.0.4", "sentence-case": "^3.0.4", "snake-case": "^3.0.4", "tslib": "^2.0.3" } }, "sha512-bSxY2ws9OtviILG1EiY5K7NNxkqg/JnRnFxLtKQ96JaviiIxi7djMrSd0ECT9AC+lttClmYwKw53BWpOMblo7A=="],
|
||||
|
||||
"class-chain": ["class-chain@1.0.0", "", { "dependencies": { "is-object": "^1.0.1" } }, "sha512-Mjg98B+B9UDbQhqfqlfU7mppgXpWcsMIK/1Y4hwjQjGKnrcnruTBy8aU/plC32ss8qn3cEShYDxptHSk4LIgVQ=="],
|
||||
|
||||
"clean-css": ["clean-css@4.2.4", "", { "dependencies": { "source-map": "~0.6.0" } }, "sha512-EJUDT7nDVFDvaQgAo2G/PJvxmp1o/c6iXLbswsBbUFXi1Nr+AjA2cKmfbKDMjMvzEe75g3P6JkaDDAKk96A85A=="],
|
||||
|
||||
"clean-stack": ["clean-stack@2.2.0", "", {}, "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A=="],
|
||||
@@ -191,8 +210,12 @@
|
||||
|
||||
"constant-case": ["constant-case@3.0.4", "", { "dependencies": { "no-case": "^3.0.4", "tslib": "^2.0.3", "upper-case": "^2.0.2" } }, "sha512-I2hSBi7Vvs7BEuJDr5dDHfzb/Ruj3FyvFyh7KLilAjNQw3Be+xgqUBA2W6scVEcL0hL1dwPRtIqEPVUCKkSsyQ=="],
|
||||
|
||||
"copy-own": ["copy-own@1.2.0", "", {}, "sha512-YBWaRsqGUKW65je5Wr1gjaSmbIzioa/T8itzCBIqp8UXjNjvJKMTJv9jRx15xdGisl2ZJEGZDudkgnGDgpWSEA=="],
|
||||
|
||||
"csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="],
|
||||
|
||||
"def-props": ["def-props@1.0.0", "", { "dependencies": { "errate": "^1.3.0", "is-iterable": "^1.1.1", "is-obj": "^2.0.0", "type-error": "^1.0.3" } }, "sha512-LjCGIswKu5qqoa1azkhNzPasYJlN2h7fphiwcJ4Z5F6AoH4I3kvi5nE7Zu1SQ53s5tHKju+OOt3ZeZAdG/Tebw=="],
|
||||
|
||||
"deprecation": ["deprecation@2.3.1", "", {}, "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ=="],
|
||||
|
||||
"detect-libc": ["detect-libc@2.0.4", "", {}, "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA=="],
|
||||
@@ -201,16 +224,52 @@
|
||||
|
||||
"ecdsa-sig-formatter": ["ecdsa-sig-formatter@1.0.11", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ=="],
|
||||
|
||||
"empty-iterator": ["empty-iterator@1.0.0", "", {}, "sha512-QaxCCCfa58lYi7eo0eAcEhuzOZma3tZw20uj/uVYoGrd2lWtL5TKAy8Xs6ZnTmGhyFshfWovFVXiPIlqmikL0Q=="],
|
||||
|
||||
"enforce-range": ["enforce-range@1.0.0", "", { "dependencies": { "2": "^1.0.2" } }, "sha512-iOYthPljA5P/S823In8avtTbeUl8/uTP1+pqy08ryb8jeMO2enuIO/f72QFFqT4GTNiOe0yWPIzXB9nR3u6O5A=="],
|
||||
|
||||
"english-list": ["english-list@1.0.0", "", {}, "sha512-bymeFA1uVYM4Bt4aLvV36X9iYk7GrG2IN1HmL1CTueRSYJLYQTXJjbqOyUGmYgfrrS3fxqs1iEU/bIiHLuneRA=="],
|
||||
|
||||
"errate": ["errate@1.3.0", "", { "dependencies": { "copy-own": "^1.2.0", "is-class-of": "^1.0.1", "is-instance-of": "^1.0.2", "trim-call": "^1.1.0" } }, "sha512-RPWotQnbJyIck/w7b3yieWN7EnNqA21UdVuEy2vo5VIaRx5svLwwbeUVxB3Q5StVNdJkGHGhOX6embHG7bs5JQ=="],
|
||||
|
||||
"esbuild": ["esbuild@0.21.5", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.21.5", "@esbuild/android-arm": "0.21.5", "@esbuild/android-arm64": "0.21.5", "@esbuild/android-x64": "0.21.5", "@esbuild/darwin-arm64": "0.21.5", "@esbuild/darwin-x64": "0.21.5", "@esbuild/freebsd-arm64": "0.21.5", "@esbuild/freebsd-x64": "0.21.5", "@esbuild/linux-arm": "0.21.5", "@esbuild/linux-arm64": "0.21.5", "@esbuild/linux-ia32": "0.21.5", "@esbuild/linux-loong64": "0.21.5", "@esbuild/linux-mips64el": "0.21.5", "@esbuild/linux-ppc64": "0.21.5", "@esbuild/linux-riscv64": "0.21.5", "@esbuild/linux-s390x": "0.21.5", "@esbuild/linux-x64": "0.21.5", "@esbuild/netbsd-x64": "0.21.5", "@esbuild/openbsd-x64": "0.21.5", "@esbuild/sunos-x64": "0.21.5", "@esbuild/win32-arm64": "0.21.5", "@esbuild/win32-ia32": "0.21.5", "@esbuild/win32-x64": "0.21.5" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw=="],
|
||||
|
||||
"ffn": ["ffn@2.1.0", "", {}, "sha512-4RAYssW5tXRqsXfRRMLYZN5ze+JBBCaLhgv5sBQYyMturfeU+CAYnYIz7TS7Qzv9wgBAkvQF8w6XtIWTfHM26w=="],
|
||||
|
||||
"get-own-property": ["get-own-property@1.0.0", "", {}, "sha512-/OsW7bqVUPVxBuHfugVduRZ7uctFhGxilojaHlf4PMhgwadQDat91hx+9hngRV0LA5OAR3YaTH9wN8sYpGfuzA=="],
|
||||
|
||||
"has-duplicates": ["has-duplicates@1.0.0", "", {}, "sha512-hZQnmfSBopwmRuMMvX64DBUDc/yp67J8CVhazVXV+ARa0L3r8suf1g4iS2oDsWHld0JE5G6yeNQsqCJ7CQ4JqA=="],
|
||||
|
||||
"he": ["he@1.2.0", "", { "bin": { "he": "bin/he" } }, "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="],
|
||||
|
||||
"header-case": ["header-case@2.0.4", "", { "dependencies": { "capital-case": "^1.0.4", "tslib": "^2.0.3" } }, "sha512-H/vuk5TEEVZwrR0lp2zed9OCo1uAILMlx0JEMgC26rzyJJ3N1v6XkwHHXJQdR2doSjcGPM6OKPYoJgf0plJ11Q=="],
|
||||
|
||||
"html-minifier": ["html-minifier@4.0.0", "", { "dependencies": { "camel-case": "^3.0.0", "clean-css": "^4.2.1", "commander": "^2.19.0", "he": "^1.2.0", "param-case": "^2.1.1", "relateurl": "^0.2.7", "uglify-js": "^3.5.1" }, "bin": { "html-minifier": "./cli.js" } }, "sha512-aoGxanpFPLg7MkIl/DDFYtb0iWz7jMFGqFhvEDZga6/4QTjneiD8I/NXL1x5aaoCp7FSIT6h/OhykDdPsbtMig=="],
|
||||
|
||||
"if-else-throw": ["if-else-throw@1.0.0", "", { "dependencies": { "possible-function": "^1.0.1" } }, "sha512-LzTMNkDgHdayblt+7hXKcY0TSk6G5+8kQjOHZyvH/d0zzUuPptgaPAQbucd1ZQqUfOLv9VdlfLrnjJcTsklIlA=="],
|
||||
|
||||
"indent-string": ["indent-string@4.0.0", "", {}, "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg=="],
|
||||
|
||||
"is-array-of-length": ["is-array-of-length@1.1.0", "", { "dependencies": { "arrify": "^1.0.1", "is-instance-of": "^1.0.2", "sbo": "^1.1.0" } }, "sha512-s4srcJzEuKAJqWZUZL0bLRfFSZy6pQMkky/7HCtADhVuAT5im1RApMRHgiRmNApR3CdrpR061odhPh9a4uxQGw=="],
|
||||
|
||||
"is-class-of": ["is-class-of@1.0.1", "", { "dependencies": { "class-chain": "^1.0.0", "sbo": "^1.0.0" } }, "sha512-5Fi5UUAWcsq1T2n5yJxOm8udIfOn4X/cpCGaUA5wdQxRQ+YF29RuBuTp0DlMjooK5CQrJbxIE01bjYoAoobu3g=="],
|
||||
|
||||
"is-global-object": ["is-global-object@1.0.0", "", {}, "sha512-THgJ/n1Ndja7FZ6YksPlhcLsl1Z34LfYT1maxuKYtt4CT/apnFwhlb2U+HVm8u9tySJL12NPV+u4USUJ4p0GRQ=="],
|
||||
|
||||
"is-instance-of": ["is-instance-of@1.0.2", "", { "dependencies": { "@lamansky/flatten": "^1.0.0", "arrify": "^1.0.1", "case-insensitive": "^1.0.0", "class-chain": "^1.0.0", "is-obj": "^1.0.1", "qfn": "^1.0.1", "sbo": "^1.1.0" } }, "sha512-n4ZY/J5l9IAhuEfYPpcEHKfQ+jGOHS5iqWuoTsGenv08/wGC5z3T+jN9qGQrWspFGLOhAfxRlxF8hB1iQ/aY5w=="],
|
||||
|
||||
"is-iterable": ["is-iterable@1.1.1", "", {}, "sha512-EdOZCr0NsGE00Pot+x1ZFx9MJK3C6wy91geZpXwvwexDLJvA4nzYyZf7r+EIwSeVsOLDdBz7ATg9NqKTzuNYuQ=="],
|
||||
|
||||
"is-nil": ["is-nil@1.0.1", "", {}, "sha512-m2Rm8PhUFDNNhgvwZJjJG74a9h5CHU0fkA8WT+WGlCjyEbZ2jPwgb+ZxHu4np284EqNVyOsgppReK4qy/TwEwg=="],
|
||||
|
||||
"is-obj": ["is-obj@1.0.1", "", {}, "sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg=="],
|
||||
|
||||
"is-object": ["is-object@1.0.2", "", {}, "sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA=="],
|
||||
|
||||
"is-plain-object": ["is-plain-object@2.0.4", "", { "dependencies": { "isobject": "^3.0.1" } }, "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og=="],
|
||||
|
||||
"isobject": ["isobject@3.0.1", "", {}, "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg=="],
|
||||
|
||||
"js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="],
|
||||
|
||||
"jsonwebtoken": ["jsonwebtoken@9.0.2", "", { "dependencies": { "jws": "^3.2.2", "lodash.includes": "^4.3.0", "lodash.isboolean": "^3.0.3", "lodash.isinteger": "^4.0.4", "lodash.isnumber": "^3.0.3", "lodash.isplainobject": "^4.0.6", "lodash.isstring": "^4.0.1", "lodash.once": "^4.0.0", "ms": "^2.1.1", "semver": "^7.5.4" } }, "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ=="],
|
||||
@@ -255,44 +314,76 @@
|
||||
|
||||
"lodash.once": ["lodash.once@4.1.1", "", {}, "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg=="],
|
||||
|
||||
"lodash.set": ["lodash.set@4.3.2", "", {}, "sha512-4hNPN5jlm/N/HLMCO43v8BXKq9Z7QdAGc/VGrRD61w8gN9g/6jF9A4L1pbUgBLCffi0w9VsXfTOij5x8iTyFvg=="],
|
||||
|
||||
"longest-first": ["longest-first@1.0.0", "", { "dependencies": { "sbo": "^1.0.0" } }, "sha512-t0F2muH7jEiupZQQ9m8FeSD68intEx5WQG2GEnLOx21d7uZKk6pCmUMo2OoQODzxu2MlpGzlhX5lTDmMycQGyA=="],
|
||||
|
||||
"loose-envify": ["loose-envify@1.4.0", "", { "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, "bin": { "loose-envify": "cli.js" } }, "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q=="],
|
||||
|
||||
"lower-case": ["lower-case@2.0.2", "", { "dependencies": { "tslib": "^2.0.3" } }, "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg=="],
|
||||
|
||||
"lru-cache": ["@wolfy1339/lru-cache@11.0.2-patch.1", "", {}, "sha512-BgYZfL2ADCXKOw2wJtkM3slhHotawWkgIRRxq4wEybnZQPjvAp71SPX35xepMykTw8gXlzWcWPTY31hlbnRsDA=="],
|
||||
|
||||
"m-o": ["m-o@2.2.0", "", { "dependencies": { "get-own-property": "^1.0.0", "if-else-throw": "^1.0.0", "is-object": "^1.0.1", "new-object": "^3.0.0" } }, "sha512-G3DuyCvqBRr8riKPlWXTWuZbOGL6QrGZlyY7Pc3R503Mdf3dC6qPKAHk3IGlQW/dU/7pyBwjh/ik6s+7y+QOaw=="],
|
||||
|
||||
"map-iter": ["map-iter@1.0.0", "", { "dependencies": { "sbo": "^1.1.0" } }, "sha512-beFeBgHAX6kFPgLl0bck+hEcnu1M0W2b7bqHryE3OI3wdZhgvKQppeDmq/Ys/NVYYJ4/Nz+B45gWaH56PURexQ=="],
|
||||
|
||||
"marked": ["marked@12.0.2", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-qXUm7e/YKFoqFPYPa3Ukg9xlI5cyAtGmyEIzMfW//m6kXwCy2Ps9DYf5ioijFKQ8qyuscrHoY04iJGctu2Kg0Q=="],
|
||||
|
||||
"mitata": ["mitata@0.1.14", "", {}, "sha512-8kRs0l636eT4jj68PFXOR2D5xl4m56T478g16SzUPOYgkzQU+xaw62guAQxzBPm+SXb15GQi1cCpDxJfkr4CSA=="],
|
||||
|
||||
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
||||
|
||||
"new-object": ["new-object@4.0.0", "", { "dependencies": { "def-props": "^1.0.0" } }, "sha512-MqlQGddh5nIYwNl0II1/l434+yAdEQlnu3wxu/wbcBYeHXWxm0HDRhm1pS2PGRXhzjkxATGg4nceI5fmIo7XJA=="],
|
||||
|
||||
"no-case": ["no-case@3.0.4", "", { "dependencies": { "lower-case": "^2.0.2", "tslib": "^2.0.3" } }, "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg=="],
|
||||
|
||||
"octokit": ["octokit@3.2.2", "", { "dependencies": { "@octokit/app": "^14.0.2", "@octokit/core": "^5.0.0", "@octokit/oauth-app": "^6.0.0", "@octokit/plugin-paginate-graphql": "^4.0.0", "@octokit/plugin-paginate-rest": "11.4.4-cjs.2", "@octokit/plugin-rest-endpoint-methods": "13.3.2-cjs.1", "@octokit/plugin-retry": "^6.0.0", "@octokit/plugin-throttling": "^8.0.0", "@octokit/request-error": "^5.0.0", "@octokit/types": "^13.0.0", "@octokit/webhooks": "^12.3.1" } }, "sha512-7Abo3nADdja8l/aglU6Y3lpnHSfv0tw7gFPiqzry/yCU+2gTAX7R1roJ8hJrxIK+S1j+7iqRJXtmuHJ/UDsBhQ=="],
|
||||
|
||||
"ofn": ["ofn@1.0.0", "", { "dependencies": { "has-duplicates": "^1.0.0", "wfn": "^1.0.0" } }, "sha512-jcPbdrxmZ9BHCI6wuSR33picFQKORWuSQICXpU0XoeSMJ32sRMUdBNUHYgMl35pJoMB/UoW0q5TA7uWLp0nn8Q=="],
|
||||
|
||||
"once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="],
|
||||
|
||||
"otherwise": ["otherwise@2.0.1", "", { "dependencies": { "arrify": "^1.0.1", "errate": "^1.1.0", "roadblock": "^1.1.0" } }, "sha512-yh+oocdOedzHS/Z1yG2j8HHLRxajDmmdDYKLESEOikZ0E0gziTklcn9jODSlIiFkYewatVQ4N2bx3MPfIrObZg=="],
|
||||
|
||||
"param-case": ["param-case@2.1.1", "", { "dependencies": { "no-case": "^2.2.0" } }, "sha512-eQE845L6ot89sk2N8liD8HAuH4ca6Vvr7VWAWwt7+kvvG5aBcPmmphQ68JsEG2qa9n1TykS2DLeMt363AAH8/w=="],
|
||||
|
||||
"parser-factory": ["parser-factory@1.1.1", "", { "dependencies": { "arrify": "^2.0.1", "case-insensitive": "^1.0.0", "enforce-range": "^1.0.0", "is-instance-of": "^1.0.2", "longest-first": "^1.0.0", "m-o": "^2.2.0", "vfn": "^1.1.0" } }, "sha512-0F1U1NedNcB31BPOMzgqN5PN2XvK/xOD6uQ3D4FMkI1WoAHLAMkQN5Zw4aX1BUoZgwRrU8YQOp/So4j4+Wk8/g=="],
|
||||
|
||||
"pascal-case": ["pascal-case@3.1.2", "", { "dependencies": { "no-case": "^3.0.4", "tslib": "^2.0.3" } }, "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g=="],
|
||||
|
||||
"path-case": ["path-case@3.0.4", "", { "dependencies": { "dot-case": "^3.0.4", "tslib": "^2.0.3" } }, "sha512-qO4qCFjXqVTrcbPt/hQfhTQ+VhFsqNKOPtytgNKkKxSoEp3XPUQ8ObFuePylOIok5gjn69ry8XiULxCwot3Wfg=="],
|
||||
|
||||
"peechy": ["peechy@0.4.34", "", { "dependencies": { "change-case": "^4.1.2" }, "bin": { "peechy": "cli.js" } }, "sha512-Cpke/cCqqZHhkyxz7mdqS8ZAGJFUi5icu3ZGqxm9GC7g2VrhH0tmjPhZoWHAN5ghw1m1wq5+2YvfbDSqgC4+Zg=="],
|
||||
|
||||
"pfn": ["pfn@1.1.0", "", { "dependencies": { "is-nil": "^1.0.1" } }, "sha512-jT+RH1+ZbL2G5dTGzpr02jd99DTYyC9cRghyrQZRAn4CypWH3K6WQpEeNbC4uHZu0P6sXR2eROnhK+RCxoOUJw=="],
|
||||
|
||||
"plainify": ["plainify@1.0.0", "", { "dependencies": { "is-plain-object": "^2.0.4" } }, "sha512-z/JXOByYzJ7xs6MA3FLPhM7oS53SMrZWJCUdUlOBcq7e/X3kkxHmNNO1QEEtDnSZ8ZN4xIY0drALlCjLEVtIWA=="],
|
||||
|
||||
"possible-function": ["possible-function@1.0.1", "", {}, "sha512-/ThEWv9rxTeiXKA2p7zdxTgxl7ZiKFignkR2HBlL4VbAaYgf30KT2CpWT8qkswFgTAwxAfh+t/0l8UPSEbJzmg=="],
|
||||
|
||||
"prettier": ["prettier@3.6.2", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ=="],
|
||||
|
||||
"prettier-plugin-organize-imports": ["prettier-plugin-organize-imports@4.2.0", "", { "peerDependencies": { "prettier": ">=2.0", "typescript": ">=2.9", "vue-tsc": "^2.1.0 || 3" }, "optionalPeers": ["vue-tsc"] }, "sha512-Zdy27UhlmyvATZi67BTnLcKTo8fm6Oik59Sz6H64PgZJVs6NJpPD1mT240mmJn62c98/QaL+r3kx9Q3gRpDajg=="],
|
||||
|
||||
"qfn": ["qfn@1.0.1", "", { "dependencies": { "pfn": "^1.0.0", "wfn": "^1.0.0" } }, "sha512-Ci2jl+ICwQGoNusUgJCToecm0IFryiT9vhTIW3Tew4t5I4ySTt8Be84bpAz9FqF+4uGKLvilHzmApszjCvExlw=="],
|
||||
|
||||
"react": ["react@18.3.1", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ=="],
|
||||
|
||||
"react-dom": ["react-dom@18.3.1", "", { "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" }, "peerDependencies": { "react": "^18.3.1" } }, "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw=="],
|
||||
|
||||
"relateurl": ["relateurl@0.2.7", "", {}, "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog=="],
|
||||
|
||||
"roadblock": ["roadblock@1.1.0", "", {}, "sha512-qrKRAV1gz9XoV0GOeAeePSw6/lFs0u6/+EzIC55fISoprnpxrnI0zcCw6pTYpmagfIk1rRRurnHlK47opn4eRA=="],
|
||||
|
||||
"round-to": ["round-to@4.1.0", "", {}, "sha512-H/4z+4QdWS82iMZ23+5St302Mv2jJws0hUvEogrD6gC8NN6Z5TalDtbg51owCrVy4V/4c8ePvwVLNtlhEfPo5g=="],
|
||||
|
||||
"rtrim-array": ["rtrim-array@1.1.0", "", { "dependencies": { "pfn": "^1.0.0", "sbo": "^1.0.0" } }, "sha512-Kg2TlpJ1jRpYEs73H4vH9SUzICRVc02t5e89U5bonldCDIM3RqzG9pmnuh8BqQu44O+605EiTnPeF0GOgxVlDg=="],
|
||||
|
||||
"safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="],
|
||||
|
||||
"sbo": ["sbo@1.1.3", "", { "dependencies": { "array-pad": "0.0.1", "ffn": "^2.1.0", "is-global-object": "^1.0.0", "is-nil": "^1.0.1", "is-object": "^1.0.2", "lodash.set": "^4.3.2", "ofn": "^1.0.0", "plainify": "^1.0.0", "wfn": "^1.0.0" } }, "sha512-yEoPppneJ3AlDrs3SpJIZBX+JioAoWMEye4zB+tuF4yQhLKcY7WAdXmVzvUpWQestZFNFIJyiK0f30lkZucemg=="],
|
||||
|
||||
"scheduler": ["scheduler@0.23.2", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ=="],
|
||||
|
||||
"semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="],
|
||||
@@ -301,12 +392,18 @@
|
||||
|
||||
"snake-case": ["snake-case@3.0.4", "", { "dependencies": { "dot-case": "^3.0.4", "tslib": "^2.0.3" } }, "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg=="],
|
||||
|
||||
"sorp": ["sorp@1.0.0", "", {}, "sha512-iTeBVYTnKO4bsj4so0MnmCcIlIclZ2yWD37iudIFy0m9aRXvZVOf0r1JRvyUmj59UUtr+AUwC0TamseLmSDZgw=="],
|
||||
|
||||
"source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="],
|
||||
|
||||
"source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
|
||||
|
||||
"trim-call": ["trim-call@1.1.0", "", { "dependencies": { "rtrim-array": "^1.0.0" } }, "sha512-2I1sdAj5JY/zoiv9VZdmqh/rmmwL62Ak9S6I7Pwl9P4gLX4TO1ci+930HJ/rX9NPQLhEkPmHCb+tAZa1WBk8mA=="],
|
||||
|
||||
"tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
||||
|
||||
"type-error": ["type-error@1.0.3", "", {}, "sha512-hlNA4NwwjtL9clb8nv+x/5C45uzxND+N+h+/y3z2dYdubGSmdtNtJjHVH4E68ZHR98Bkav4ACf1lmTZepc/4sg=="],
|
||||
|
||||
"typescript": ["typescript@5.9.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A=="],
|
||||
|
||||
"uglify-js": ["uglify-js@3.19.3", "", { "bin": { "uglifyjs": "bin/uglifyjs" } }, "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ=="],
|
||||
@@ -321,6 +418,10 @@
|
||||
|
||||
"upper-case-first": ["upper-case-first@2.0.2", "", { "dependencies": { "tslib": "^2.0.3" } }, "sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg=="],
|
||||
|
||||
"vfn": ["vfn@1.1.0", "", { "dependencies": { "array-pad": "0.0.1", "is-plain-object": "^2.0.4", "plainify": "^1.0.0", "wfn": "^1.0.0" } }, "sha512-ZLp05QABhxCUsh/iCr+m94HH670VKTQXiYRQMMgXzvKwp98GzHnnnIJ6fbcyrU1n6j1MVhYgbYen0Fc4FNIGbA=="],
|
||||
|
||||
"wfn": ["wfn@1.0.0", "", { "dependencies": { "copy-own": "^1.0.0", "english-list": "^1.0.0", "sorp": "^1.0.0" } }, "sha512-oqi69SrZYlW66I/Bz4iJQ7V4E/uB0o776fW7KWbGaweTHvrtDUuemPkyEt7MgQeSnUs30NTSyqcbO4TT7/8SOw=="],
|
||||
|
||||
"wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="],
|
||||
|
||||
"@octokit/app/@octokit/plugin-paginate-rest": ["@octokit/plugin-paginate-rest@9.2.2", "", { "dependencies": { "@octokit/types": "^12.6.0" }, "peerDependencies": { "@octokit/core": "5" } }, "sha512-u3KYkGF7GcZnSD/3UP0S7K5XUFT2FkOQdcfXZGZQPGv3lm4F2Xbf71lvjldr8c1H3nNbF+33cLEkWYbokGWqiQ=="],
|
||||
@@ -343,8 +444,16 @@
|
||||
|
||||
"constant-case/upper-case": ["upper-case@2.0.2", "", { "dependencies": { "tslib": "^2.0.3" } }, "sha512-KgdgDGJt2TpuwBUIjgG6lzw2GWFRCW9Qkfkiv0DxqHHLYJHmtmdUIKcZd8rHgFSjopVTlw6ggzCm1b8MFQwikg=="],
|
||||
|
||||
"def-props/is-obj": ["is-obj@2.0.0", "", {}, "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w=="],
|
||||
|
||||
"enforce-range/2": ["2@1.0.2", "", {}, "sha512-G0Eca6Fz2qJKvjM9/niouz5kWTZy7pm+LRAMXir5v+DOt4bMszVlfIYKy2T+TPKnGxpp236pzK7/chNuToWlnQ=="],
|
||||
|
||||
"m-o/new-object": ["new-object@3.1.0", "", { "dependencies": { "errate": "^1.1.0" } }, "sha512-mAm06BBs3uEioVQ6eL5JTYQY+Dlo9xqJyCKwcvrXMbR0yOQPdSc3ZZrCtVXGjcDW20t2btlbWJVD1TjWd7rA3A=="],
|
||||
|
||||
"param-case/no-case": ["no-case@2.3.2", "", { "dependencies": { "lower-case": "^1.1.1" } }, "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ=="],
|
||||
|
||||
"parser-factory/arrify": ["arrify@2.0.1", "", {}, "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug=="],
|
||||
|
||||
"@octokit/app/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@20.0.0", "", {}, "sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA=="],
|
||||
|
||||
"@octokit/auth-unauthenticated/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@20.0.0", "", {}, "sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA=="],
|
||||
|
||||
@@ -603,6 +603,7 @@ src/install/bin.zig
|
||||
src/install/dependency.zig
|
||||
src/install/ExternalSlice.zig
|
||||
src/install/extract_tarball.zig
|
||||
src/install/git_command_runner.zig
|
||||
src/install/hoisted_install.zig
|
||||
src/install/install_binding.zig
|
||||
src/install/install.zig
|
||||
|
||||
@@ -81,5 +81,8 @@
|
||||
"node:test:cp": "bun ./scripts/fetch-node-test.ts ",
|
||||
"clean:zig": "rm -rf build/debug/cache/zig build/debug/CMakeCache.txt 'build/debug/*.o' .zig-cache zig-out || true",
|
||||
"sync-webkit-source": "bun ./scripts/sync-webkit-source.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"2": "^3.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,6 +82,7 @@ pub const ProcessExitHandler = struct {
|
||||
.{
|
||||
Subprocess,
|
||||
LifecycleScriptSubprocess,
|
||||
GitCommandRunner,
|
||||
ShellSubprocess,
|
||||
ProcessHandle,
|
||||
|
||||
@@ -115,6 +116,10 @@ pub const ProcessExitHandler = struct {
|
||||
const subprocess = this.ptr.as(ShellSubprocess);
|
||||
subprocess.onProcessExit(process, status, rusage);
|
||||
},
|
||||
@field(TaggedPointer.Tag, @typeName(GitCommandRunner)) => {
|
||||
const runner = this.ptr.as(GitCommandRunner);
|
||||
runner.onProcessExit(process, status, rusage);
|
||||
},
|
||||
@field(TaggedPointer.Tag, @typeName(SyncProcess)) => {
|
||||
const subprocess = this.ptr.as(SyncProcess);
|
||||
if (comptime Environment.isPosix) {
|
||||
@@ -2246,10 +2251,12 @@ const bun = @import("bun");
|
||||
const Environment = bun.Environment;
|
||||
const Output = bun.Output;
|
||||
const PosixSpawn = bun.spawn;
|
||||
const LifecycleScriptSubprocess = bun.install.LifecycleScriptSubprocess;
|
||||
const Maybe = bun.sys.Maybe;
|
||||
const ShellSubprocess = bun.shell.ShellSubprocess;
|
||||
const uv = bun.windows.libuv;
|
||||
|
||||
const GitCommandRunner = bun.install.GitCommandRunner;
|
||||
const LifecycleScriptSubprocess = bun.install.LifecycleScriptSubprocess;
|
||||
|
||||
const jsc = bun.jsc;
|
||||
const Subprocess = jsc.Subprocess;
|
||||
|
||||
@@ -135,6 +135,7 @@ updating_packages: bun.StringArrayHashMapUnmanaged(PackageUpdateInfo) = .{},
|
||||
patched_dependencies_to_remove: std.ArrayHashMapUnmanaged(PackageNameAndVersionHash, void, ArrayIdentityContext.U64, false) = .{},
|
||||
|
||||
active_lifecycle_scripts: LifecycleScriptSubprocess.List,
|
||||
active_git_commands: GitCommandRunner.List,
|
||||
last_reported_slow_lifecycle_script_at: u64 = 0,
|
||||
cached_tick_for_slow_lifecycle_script_logging: u64 = 0,
|
||||
|
||||
@@ -850,6 +851,9 @@ pub fn init(
|
||||
.active_lifecycle_scripts = .{
|
||||
.context = manager,
|
||||
},
|
||||
.active_git_commands = .{
|
||||
.context = manager,
|
||||
},
|
||||
.network_task_fifo = NetworkQueue.init(),
|
||||
.patch_task_fifo = PatchTaskFifo.init(),
|
||||
.allocator = ctx.allocator,
|
||||
@@ -1022,6 +1026,9 @@ pub fn initWithRuntimeOnce(
|
||||
.active_lifecycle_scripts = .{
|
||||
.context = manager,
|
||||
},
|
||||
.active_git_commands = .{
|
||||
.context = manager,
|
||||
},
|
||||
.network_task_fifo = NetworkQueue.init(),
|
||||
.allocator = allocator,
|
||||
.log = log,
|
||||
@@ -1291,6 +1298,7 @@ const Dependency = bun.install.Dependency;
|
||||
const DependencyID = bun.install.DependencyID;
|
||||
const Features = bun.install.Features;
|
||||
const FolderResolution = bun.install.FolderResolution;
|
||||
const GitCommandRunner = bun.install.GitCommandRunner;
|
||||
const IdentityContext = bun.install.IdentityContext;
|
||||
const LifecycleScriptSubprocess = bun.install.LifecycleScriptSubprocess;
|
||||
const NetworkTask = bun.install.NetworkTask;
|
||||
|
||||
@@ -180,7 +180,7 @@ pub fn enqueueGitForCheckout(
|
||||
if (checkout_queue.found_existing) return;
|
||||
|
||||
if (this.git_repositories.get(clone_id)) |repo_fd| {
|
||||
this.task_batch.push(ThreadPool.Batch.from(this.enqueueGitCheckout(checkout_id, repo_fd, dependency_id, alias, resolution.*, resolved, patch_name_and_version_hash)));
|
||||
this.enqueueGitCheckout(checkout_id, repo_fd, dependency_id, alias, resolution.*, resolved, patch_name_and_version_hash);
|
||||
} else {
|
||||
var clone_queue = this.task_queue.getOrPut(this.allocator, clone_id) catch unreachable;
|
||||
if (!clone_queue.found_existing) {
|
||||
@@ -194,7 +194,7 @@ pub fn enqueueGitForCheckout(
|
||||
|
||||
if (clone_queue.found_existing) return;
|
||||
|
||||
this.task_batch.push(ThreadPool.Batch.from(enqueueGitClone(
|
||||
enqueueGitClone(
|
||||
this,
|
||||
clone_id,
|
||||
alias,
|
||||
@@ -203,7 +203,7 @@ pub fn enqueueGitForCheckout(
|
||||
&this.lockfile.buffers.dependencies.items[dependency_id],
|
||||
resolution,
|
||||
null,
|
||||
)));
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -812,7 +812,7 @@ pub fn enqueueDependencyWithMainAndSuccessFn(
|
||||
|
||||
if (this.hasCreatedNetworkTask(checkout_id, dependency.behavior.isRequired())) return;
|
||||
|
||||
this.task_batch.push(ThreadPool.Batch.from(this.enqueueGitCheckout(
|
||||
this.enqueueGitCheckout(
|
||||
checkout_id,
|
||||
repo_fd,
|
||||
id,
|
||||
@@ -820,7 +820,7 @@ pub fn enqueueDependencyWithMainAndSuccessFn(
|
||||
res,
|
||||
resolved,
|
||||
null,
|
||||
)));
|
||||
);
|
||||
} else {
|
||||
var entry = this.task_queue.getOrPutContext(this.allocator, clone_id, .{}) catch unreachable;
|
||||
if (!entry.found_existing) entry.value_ptr.* = .{};
|
||||
@@ -835,7 +835,7 @@ pub fn enqueueDependencyWithMainAndSuccessFn(
|
||||
|
||||
if (this.hasCreatedNetworkTask(clone_id, dependency.behavior.isRequired())) return;
|
||||
|
||||
this.task_batch.push(ThreadPool.Batch.from(enqueueGitClone(this, clone_id, alias, dep, id, dependency, &res, null)));
|
||||
enqueueGitClone(this, clone_id, alias, dep, id, dependency, &res, null);
|
||||
}
|
||||
},
|
||||
.github => {
|
||||
@@ -1140,46 +1140,115 @@ fn enqueueGitClone(
|
||||
res: *const Resolution,
|
||||
/// if patched then we need to do apply step after network task is done
|
||||
patch_name_and_version_hash: ?u64,
|
||||
) *ThreadPool.Task {
|
||||
var task = this.preallocated_resolve_tasks.get();
|
||||
task.* = Task{
|
||||
.package_manager = this,
|
||||
.log = logger.Log.init(this.allocator),
|
||||
.tag = Task.Tag.git_clone,
|
||||
.request = .{
|
||||
.git_clone = .{
|
||||
) void {
|
||||
_ = patch_name_and_version_hash; // TODO: handle patches
|
||||
_ = dependency; // Currently unused
|
||||
|
||||
const url = this.lockfile.str(&repository.repo);
|
||||
// Enqueue git clone for url
|
||||
const folder_name = std.fmt.bufPrintZ(&git_folder_name_buf, "{any}.git", .{
|
||||
bun.fmt.hexIntLower(task_id.get()),
|
||||
}) catch unreachable;
|
||||
|
||||
// Build full path for git clone target
|
||||
const target = Path.joinAbsStringZ(this.cache_directory_path, &.{folder_name}, .auto);
|
||||
|
||||
// Build git command arguments
|
||||
var argc: usize = 0;
|
||||
|
||||
// Try HTTPS first
|
||||
const argv = if (Repository.tryHTTPS(url)) |https| blk: {
|
||||
const args: [10]?[*:0]const u8 = .{
|
||||
"git",
|
||||
"clone",
|
||||
"-c",
|
||||
"core.longpaths=true",
|
||||
"--quiet",
|
||||
"--bare",
|
||||
bun.default_allocator.dupeZ(u8, https) catch unreachable,
|
||||
target,
|
||||
null,
|
||||
null,
|
||||
};
|
||||
argc = 8;
|
||||
break :blk args;
|
||||
} else if (Repository.trySSH(url)) |ssh| blk: {
|
||||
const args: [10]?[*:0]const u8 = .{
|
||||
"git",
|
||||
"clone",
|
||||
"-c",
|
||||
"core.longpaths=true",
|
||||
"--quiet",
|
||||
"--bare",
|
||||
bun.default_allocator.dupeZ(u8, ssh) catch unreachable,
|
||||
target,
|
||||
null,
|
||||
null,
|
||||
};
|
||||
argc = 8;
|
||||
break :blk args;
|
||||
} else {
|
||||
// Can't parse URL - create a failed task
|
||||
const task = this.preallocated_resolve_tasks.get();
|
||||
task.* = Task{
|
||||
.package_manager = this,
|
||||
.log = logger.Log.init(this.allocator),
|
||||
.tag = Task.Tag.git_clone,
|
||||
.request = .{
|
||||
.git_clone = .{
|
||||
.name = strings.StringOrTinyString.init(name),
|
||||
.url = strings.StringOrTinyString.init(url),
|
||||
.env = DotEnv.Map{ .map = DotEnv.Map.HashTable.init(this.allocator) },
|
||||
.dep_id = dep_id,
|
||||
.res = res.*,
|
||||
},
|
||||
},
|
||||
.id = task_id,
|
||||
.threadpool_task = ThreadPool.Task{ .callback = &dummyCallback },
|
||||
.data = .{ .git_clone = bun.invalid_fd },
|
||||
.status = .fail,
|
||||
.err = error.InvalidGitURL,
|
||||
};
|
||||
// Increment pending tasks for this immediate failure task
|
||||
this.incrementPendingTasks(1);
|
||||
this.resolve_tasks.push(task);
|
||||
this.wake();
|
||||
return;
|
||||
};
|
||||
|
||||
// Spawn GitCommandRunner
|
||||
// Increment pending tasks so the event loop knows to wait for this
|
||||
this.incrementPendingTasks(1);
|
||||
GitCommandRunner.spawn(
|
||||
this,
|
||||
task_id,
|
||||
argv[0..argc],
|
||||
.{
|
||||
.clone = .{
|
||||
.name = strings.StringOrTinyString.initAppendIfNeeded(
|
||||
name,
|
||||
*FileSystem.FilenameStore,
|
||||
FileSystem.FilenameStore.instance,
|
||||
) catch unreachable,
|
||||
.url = strings.StringOrTinyString.initAppendIfNeeded(
|
||||
this.lockfile.str(&repository.repo),
|
||||
url,
|
||||
*FileSystem.FilenameStore,
|
||||
FileSystem.FilenameStore.instance,
|
||||
) catch unreachable,
|
||||
.env = Repository.shared_env.get(this.allocator, this.env),
|
||||
.dep_id = dep_id,
|
||||
.res = res.*,
|
||||
.attempt = 1,
|
||||
},
|
||||
},
|
||||
.id = task_id,
|
||||
.apply_patch_task = if (patch_name_and_version_hash) |h| brk: {
|
||||
const dep = dependency;
|
||||
const pkg_id = switch (this.lockfile.package_index.get(dep.name_hash) orelse @panic("Package not found")) {
|
||||
.id => |p| p,
|
||||
.ids => |ps| ps.items[0], // TODO is this correct
|
||||
};
|
||||
const patch_hash = this.lockfile.patched_dependencies.get(h).?.patchfileHash().?;
|
||||
const pt = PatchTask.newApplyPatchHash(this, pkg_id, patch_hash, h);
|
||||
pt.callback.apply.task_id = task_id;
|
||||
break :brk pt;
|
||||
} else null,
|
||||
.data = undefined,
|
||||
};
|
||||
return &task.threadpool_task;
|
||||
);
|
||||
}
|
||||
|
||||
fn dummyCallback(_: *ThreadPool.Task) void {
|
||||
unreachable;
|
||||
}
|
||||
|
||||
var git_folder_name_buf: [1024]u8 = undefined;
|
||||
|
||||
pub fn enqueueGitCheckout(
|
||||
this: *PackageManager,
|
||||
task_id: Task.Id,
|
||||
@@ -1190,16 +1259,65 @@ pub fn enqueueGitCheckout(
|
||||
resolved: string,
|
||||
/// if patched then we need to do apply step after network task is done
|
||||
patch_name_and_version_hash: ?u64,
|
||||
) *ThreadPool.Task {
|
||||
var task = this.preallocated_resolve_tasks.get();
|
||||
task.* = Task{
|
||||
.package_manager = this,
|
||||
.log = logger.Log.init(this.allocator),
|
||||
.tag = Task.Tag.git_checkout,
|
||||
.request = .{
|
||||
.git_checkout = .{
|
||||
) void {
|
||||
const folder_name = PackageManager.cachedGitFolderNamePrint(&git_folder_name_buf, resolved, null);
|
||||
const target = Path.joinAbsString(this.cache_directory_path, &.{folder_name}, .auto);
|
||||
const repo_path = bun.getFdPath(dir, &git_path_buf) catch |err| {
|
||||
// If we can't get the path, create a failed task
|
||||
const task = this.preallocated_resolve_tasks.get();
|
||||
task.* = Task{
|
||||
.package_manager = this,
|
||||
.log = logger.Log.init(this.allocator),
|
||||
.tag = Task.Tag.git_checkout,
|
||||
.request = .{
|
||||
.git_checkout = .{
|
||||
.repo_dir = dir,
|
||||
.resolution = resolution,
|
||||
.dependency_id = dependency_id,
|
||||
.name = strings.StringOrTinyString.init(name),
|
||||
.url = strings.StringOrTinyString.init(this.lockfile.str(&resolution.value.git.repo)),
|
||||
.resolved = strings.StringOrTinyString.init(resolved),
|
||||
.env = DotEnv.Map{ .map = DotEnv.Map.HashTable.init(this.allocator) },
|
||||
},
|
||||
},
|
||||
.id = task_id,
|
||||
.threadpool_task = ThreadPool.Task{ .callback = &dummyCallback },
|
||||
.data = .{ .git_checkout = .{} },
|
||||
.status = .fail,
|
||||
.err = err,
|
||||
};
|
||||
// Increment pending tasks for this immediate failure task
|
||||
this.incrementPendingTasks(1);
|
||||
this.resolve_tasks.push(task);
|
||||
this.wake();
|
||||
return;
|
||||
};
|
||||
|
||||
// Build git command arguments for clone --no-checkout
|
||||
const argv: [10]?[*:0]const u8 = .{
|
||||
"git",
|
||||
"clone",
|
||||
"-c",
|
||||
"core.longpaths=true",
|
||||
"--quiet",
|
||||
"--no-checkout",
|
||||
bun.default_allocator.dupeZ(u8, repo_path) catch unreachable,
|
||||
bun.default_allocator.dupeZ(u8, target) catch unreachable,
|
||||
null,
|
||||
null,
|
||||
};
|
||||
const argc: usize = 8;
|
||||
|
||||
// Spawn GitCommandRunner
|
||||
// Increment pending tasks so the event loop knows to wait for this
|
||||
this.incrementPendingTasks(1);
|
||||
GitCommandRunner.spawn(
|
||||
this,
|
||||
task_id,
|
||||
argv[0..argc],
|
||||
.{
|
||||
.checkout = .{
|
||||
.repo_dir = dir,
|
||||
.resolution = resolution,
|
||||
.dependency_id = dependency_id,
|
||||
.name = strings.StringOrTinyString.initAppendIfNeeded(
|
||||
name,
|
||||
@@ -1216,26 +1334,16 @@ pub fn enqueueGitCheckout(
|
||||
*FileSystem.FilenameStore,
|
||||
FileSystem.FilenameStore.instance,
|
||||
) catch unreachable,
|
||||
.env = Repository.shared_env.get(this.allocator, this.env),
|
||||
.resolution = resolution,
|
||||
.target_dir = bun.default_allocator.dupe(u8, target) catch unreachable,
|
||||
.patch_name_and_version_hash = patch_name_and_version_hash,
|
||||
},
|
||||
},
|
||||
.apply_patch_task = if (patch_name_and_version_hash) |h| brk: {
|
||||
const dep = this.lockfile.buffers.dependencies.items[dependency_id];
|
||||
const pkg_id = switch (this.lockfile.package_index.get(dep.name_hash) orelse @panic("Package not found")) {
|
||||
.id => |p| p,
|
||||
.ids => |ps| ps.items[0], // TODO is this correct
|
||||
};
|
||||
const patch_hash = this.lockfile.patched_dependencies.get(h).?.patchfileHash().?;
|
||||
const pt = PatchTask.newApplyPatchHash(this, pkg_id, patch_hash, h);
|
||||
pt.callback.apply.task_id = task_id;
|
||||
break :brk pt;
|
||||
} else null,
|
||||
.id = task_id,
|
||||
.data = undefined,
|
||||
};
|
||||
return &task.threadpool_task;
|
||||
);
|
||||
}
|
||||
|
||||
var git_path_buf: bun.PathBuffer = undefined;
|
||||
|
||||
fn enqueueLocalTarball(
|
||||
this: *PackageManager,
|
||||
task_id: Task.Id,
|
||||
@@ -1768,6 +1876,7 @@ const string = []const u8;
|
||||
const std = @import("std");
|
||||
|
||||
const bun = @import("bun");
|
||||
const DotEnv = bun.DotEnv;
|
||||
const Environment = bun.Environment;
|
||||
const Output = bun.Output;
|
||||
const Path = bun.path;
|
||||
@@ -1787,6 +1896,7 @@ const DependencyID = bun.install.DependencyID;
|
||||
const ExtractTarball = bun.install.ExtractTarball;
|
||||
const Features = bun.install.Features;
|
||||
const FolderResolution = bun.install.FolderResolution;
|
||||
const GitCommandRunner = bun.install.GitCommandRunner;
|
||||
const Npm = bun.install.Npm;
|
||||
const PackageID = bun.install.PackageID;
|
||||
const PackageNameHash = bun.install.PackageNameHash;
|
||||
|
||||
@@ -197,8 +197,7 @@ pub fn processExtractedTarballPackage(
|
||||
|
||||
return package;
|
||||
},
|
||||
else => if (data.json.?.buf.len > 0) {
|
||||
const json = data.json.?;
|
||||
else => if (data.json) |json| if (json.buf.len > 0) {
|
||||
const package_json_source = &logger.Source.initPathString(
|
||||
json.path,
|
||||
json.buf,
|
||||
|
||||
@@ -758,7 +758,7 @@ pub fn runTasks(
|
||||
|
||||
if (manager.hasCreatedNetworkTask(checkout_id, dep.behavior.isRequired())) continue;
|
||||
|
||||
manager.task_batch.push(ThreadPool.Batch.from(manager.enqueueGitCheckout(
|
||||
manager.enqueueGitCheckout(
|
||||
checkout_id,
|
||||
repo_fd,
|
||||
dep_id,
|
||||
@@ -766,7 +766,7 @@ pub fn runTasks(
|
||||
clone.res,
|
||||
resolved,
|
||||
null,
|
||||
)));
|
||||
);
|
||||
} else {
|
||||
// Resolving!
|
||||
const dependency_list_entry = manager.task_queue.getEntry(task.id).?;
|
||||
|
||||
@@ -157,82 +157,16 @@ pub fn callback(task: *ThreadPool.Task) void {
|
||||
this.status = Status.success;
|
||||
},
|
||||
.git_clone => {
|
||||
const name = this.request.git_clone.name.slice();
|
||||
const url = this.request.git_clone.url.slice();
|
||||
var attempt: u8 = 1;
|
||||
const dir = brk: {
|
||||
if (Repository.tryHTTPS(url)) |https| break :brk Repository.download(
|
||||
manager.allocator,
|
||||
this.request.git_clone.env,
|
||||
&this.log,
|
||||
manager.getCacheDirectory(),
|
||||
this.id,
|
||||
name,
|
||||
https,
|
||||
attempt,
|
||||
) catch |err| {
|
||||
// Exit early if git checked and could
|
||||
// not find the repository, skip ssh
|
||||
if (err == error.RepositoryNotFound) {
|
||||
this.err = err;
|
||||
this.status = Status.fail;
|
||||
this.data = .{ .git_clone = bun.invalid_fd };
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.err = err;
|
||||
this.status = Status.fail;
|
||||
this.data = .{ .git_clone = bun.invalid_fd };
|
||||
attempt += 1;
|
||||
break :brk null;
|
||||
};
|
||||
break :brk null;
|
||||
} orelse if (Repository.trySSH(url)) |ssh| Repository.download(
|
||||
manager.allocator,
|
||||
this.request.git_clone.env,
|
||||
&this.log,
|
||||
manager.getCacheDirectory(),
|
||||
this.id,
|
||||
name,
|
||||
ssh,
|
||||
attempt,
|
||||
) catch |err| {
|
||||
this.err = err;
|
||||
this.status = Status.fail;
|
||||
this.data = .{ .git_clone = bun.invalid_fd };
|
||||
return;
|
||||
} else {
|
||||
return;
|
||||
};
|
||||
|
||||
this.err = null;
|
||||
this.data = .{ .git_clone = .fromStdDir(dir) };
|
||||
this.status = Status.success;
|
||||
// Git operations are now handled by GitCommandRunner
|
||||
// This task should already have its data populated by GitCommandRunner
|
||||
// If we get here, it means something went wrong
|
||||
unreachable;
|
||||
},
|
||||
.git_checkout => {
|
||||
const git_checkout = &this.request.git_checkout;
|
||||
const data = Repository.checkout(
|
||||
manager.allocator,
|
||||
this.request.git_checkout.env,
|
||||
&this.log,
|
||||
manager.getCacheDirectory(),
|
||||
git_checkout.repo_dir.stdDir(),
|
||||
git_checkout.name.slice(),
|
||||
git_checkout.url.slice(),
|
||||
git_checkout.resolved.slice(),
|
||||
) catch |err| {
|
||||
this.err = err;
|
||||
this.status = Status.fail;
|
||||
this.data = .{ .git_checkout = .{} };
|
||||
|
||||
return;
|
||||
};
|
||||
|
||||
this.data = .{
|
||||
.git_checkout = data,
|
||||
};
|
||||
this.status = Status.success;
|
||||
// Git operations are now handled by GitCommandRunner
|
||||
// This task should already have its data populated by GitCommandRunner
|
||||
// If we get here, it means something went wrong
|
||||
unreachable;
|
||||
},
|
||||
.local_tarball => {
|
||||
const workspace_pkg_id = manager.lockfile.getWorkspacePkgIfWorkspaceDep(this.request.local_tarball.tarball.dependency_id);
|
||||
@@ -364,7 +298,6 @@ const Npm = install.Npm;
|
||||
const PackageID = install.PackageID;
|
||||
const PackageManager = install.PackageManager;
|
||||
const PatchTask = install.PatchTask;
|
||||
const Repository = install.Repository;
|
||||
const Resolution = install.Resolution;
|
||||
const Task = install.Task;
|
||||
const invalid_package_id = install.invalid_package_id;
|
||||
|
||||
@@ -630,6 +630,10 @@ pub const Version = struct {
|
||||
if (isGitHubRepoPath(url["hub:".len..])) return .github;
|
||||
}
|
||||
},
|
||||
'l' => {
|
||||
// gitlab:user/repo - when url = "lab:user/repo" after "git" prefix
|
||||
if (strings.hasPrefixComptime(url, "lab:")) return .git;
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
@@ -745,6 +749,10 @@ pub const Version = struct {
|
||||
// return `Tag.git` or `Tag.npm`.
|
||||
if (strings.hasPrefixComptime(dependency, "patch:")) return .npm;
|
||||
},
|
||||
'b' => {
|
||||
// bitbucket:user/repo
|
||||
if (strings.hasPrefixComptime(dependency, "bitbucket:")) return .git;
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
|
||||
@@ -1012,6 +1020,7 @@ pub fn parseWithTag(
|
||||
if (strings.hasPrefixComptime(input, "git+")) {
|
||||
input = input["git+".len..];
|
||||
}
|
||||
// Processing git URL
|
||||
const hash_index = strings.lastIndexOfChar(input, '#');
|
||||
|
||||
return .{
|
||||
|
||||
885
src/install/git_command_runner.zig
Normal file
885
src/install/git_command_runner.zig
Normal file
@@ -0,0 +1,885 @@
|
||||
const log = Output.scoped(.Git, false);
|
||||
|
||||
pub const GitCommandRunner = struct {
|
||||
manager: *PackageManager,
|
||||
process: ?*Process = null,
|
||||
stdout: OutputReader = OutputReader.init(@This()),
|
||||
stderr: OutputReader = OutputReader.init(@This()),
|
||||
has_called_process_exit: bool = false,
|
||||
remaining_fds: i8 = 0,
|
||||
|
||||
task_id: Task.Id,
|
||||
operation: Operation,
|
||||
// For checkout, we need to run two commands
|
||||
checkout_phase: enum { clone, checkout } = .clone,
|
||||
|
||||
heap: bun.io.heap.IntrusiveField(GitCommandRunner) = .{},
|
||||
|
||||
pub const Operation = union(enum) {
|
||||
clone: struct {
|
||||
name: strings.StringOrTinyString,
|
||||
url: strings.StringOrTinyString,
|
||||
dep_id: DependencyID,
|
||||
res: Resolution,
|
||||
attempt: u8,
|
||||
},
|
||||
checkout: struct {
|
||||
repo_dir: bun.FileDescriptor,
|
||||
dependency_id: DependencyID,
|
||||
name: strings.StringOrTinyString,
|
||||
url: strings.StringOrTinyString,
|
||||
resolved: strings.StringOrTinyString,
|
||||
resolution: Resolution,
|
||||
target_dir: []const u8,
|
||||
patch_name_and_version_hash: ?u64,
|
||||
},
|
||||
};
|
||||
|
||||
pub const List = bun.io.heap.Intrusive(GitCommandRunner, *PackageManager, sortByTaskId);
|
||||
|
||||
fn sortByTaskId(_: *PackageManager, a: *GitCommandRunner, b: *GitCommandRunner) bool {
|
||||
return a.task_id.get() < b.task_id.get();
|
||||
}
|
||||
|
||||
pub const new = bun.TrivialNew(@This());
|
||||
|
||||
pub const OutputReader = bun.io.BufferedReader;
|
||||
const uv = bun.windows.libuv;
|
||||
|
||||
fn resetOutputFlags(output: *OutputReader, fd: bun.FileDescriptor) void {
|
||||
output.flags.nonblocking = true;
|
||||
output.flags.socket = true;
|
||||
output.flags.memfd = false;
|
||||
output.flags.received_eof = false;
|
||||
output.flags.closed_without_reporting = false;
|
||||
|
||||
if (comptime Environment.allow_assert) {
|
||||
const flags = bun.sys.getFcntlFlags(fd).unwrap() catch @panic("Failed to get fcntl flags");
|
||||
bun.assertWithLocation(flags & bun.O.NONBLOCK != 0, @src());
|
||||
|
||||
const stat = bun.sys.fstat(fd).unwrap() catch @panic("Failed to fstat");
|
||||
bun.assertWithLocation(std.posix.S.ISSOCK(stat.mode), @src());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn loop(this: *const GitCommandRunner) *bun.uws.Loop {
|
||||
return this.manager.event_loop.loop();
|
||||
}
|
||||
|
||||
pub fn eventLoop(this: *const GitCommandRunner) *jsc.AnyEventLoop {
|
||||
return &this.manager.event_loop;
|
||||
}
|
||||
|
||||
pub fn onReaderDone(this: *GitCommandRunner) void {
|
||||
bun.assert(this.remaining_fds > 0);
|
||||
this.remaining_fds -= 1;
|
||||
this.maybeFinished();
|
||||
}
|
||||
|
||||
pub fn onReaderError(this: *GitCommandRunner, err: bun.sys.Error) void {
|
||||
bun.assert(this.remaining_fds > 0);
|
||||
this.remaining_fds -= 1;
|
||||
|
||||
Output.prettyErrorln("<r><red>error<r>: Failed to read git output due to error <b>{d} {s}<r>", .{
|
||||
err.errno,
|
||||
@tagName(err.getErrno()),
|
||||
});
|
||||
Output.flush();
|
||||
this.maybeFinished();
|
||||
}
|
||||
|
||||
fn maybeFinished(this: *GitCommandRunner) void {
|
||||
if (!this.has_called_process_exit or this.remaining_fds != 0)
|
||||
return;
|
||||
|
||||
const process = this.process orelse return;
|
||||
this.handleExit(process.status);
|
||||
}
|
||||
|
||||
fn ensureNotInHeap(this: *GitCommandRunner) void {
|
||||
if (this.heap.child != null or this.heap.next != null or this.heap.prev != null or this.manager.active_git_commands.root == this) {
|
||||
this.manager.active_git_commands.remove(this);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn spawn(
|
||||
manager: *PackageManager,
|
||||
task_id: Task.Id,
|
||||
argv_input: []const ?[*:0]const u8,
|
||||
operation: Operation,
|
||||
) void {
|
||||
// GitCommandRunner.spawn called
|
||||
|
||||
const runner = bun.new(GitCommandRunner, .{
|
||||
.manager = manager,
|
||||
.task_id = task_id,
|
||||
.operation = operation,
|
||||
});
|
||||
|
||||
runner.manager.active_git_commands.insert(runner);
|
||||
|
||||
// Find the git executable
|
||||
var path_buf: bun.PathBuffer = undefined;
|
||||
const git_path = bun.which(&path_buf, bun.getenvZ("PATH") orelse "", manager.cache_directory_path, "git") orelse {
|
||||
log("Failed to find git executable in PATH", .{});
|
||||
// Create a failed task
|
||||
const task = manager.preallocated_resolve_tasks.get();
|
||||
task.* = Task{
|
||||
.package_manager = manager,
|
||||
.log = logger.Log.init(manager.allocator),
|
||||
.tag = .git_clone,
|
||||
.request = .{
|
||||
.git_clone = .{
|
||||
.name = operation.clone.name,
|
||||
.url = operation.clone.url,
|
||||
.env = DotEnv.Map{ .map = DotEnv.Map.HashTable.init(manager.allocator) },
|
||||
.dep_id = operation.clone.dep_id,
|
||||
.res = operation.clone.res,
|
||||
},
|
||||
},
|
||||
.id = task_id,
|
||||
.threadpool_task = ThreadPool.Task{ .callback = &dummyCallback },
|
||||
.data = .{ .git_clone = bun.invalid_fd },
|
||||
.status = .fail,
|
||||
.err = error.GitCommandFailed,
|
||||
};
|
||||
manager.resolve_tasks.push(task);
|
||||
manager.wake();
|
||||
runner.deinit();
|
||||
return;
|
||||
};
|
||||
|
||||
// Copy argv to a local array to avoid const issues, using the full git path
|
||||
var argv: [16]?[*:0]const u8 = undefined;
|
||||
argv[0] = git_path.ptr; // Use the full path to git
|
||||
var argc: usize = 1;
|
||||
for (argv_input[1..]) |arg| {
|
||||
if (arg == null) break;
|
||||
argv[argc] = arg;
|
||||
argc += 1;
|
||||
}
|
||||
argv[argc] = null; // Ensure null termination
|
||||
|
||||
// Cache directory is manager.cache_directory_path
|
||||
|
||||
runner.remaining_fds = 0;
|
||||
var env_map = Repository.shared_env.get(manager.allocator, manager.env);
|
||||
const envp = env_map.createNullDelimitedEnvMap(manager.allocator) catch |err| {
|
||||
log("Failed to create env map: {}", .{err});
|
||||
// Create a failed task
|
||||
const task = manager.preallocated_resolve_tasks.get();
|
||||
task.* = Task{
|
||||
.package_manager = manager,
|
||||
.log = logger.Log.init(manager.allocator),
|
||||
.tag = .git_clone,
|
||||
.request = .{
|
||||
.git_clone = .{
|
||||
.name = operation.clone.name,
|
||||
.url = operation.clone.url,
|
||||
.env = DotEnv.Map{ .map = DotEnv.Map.HashTable.init(manager.allocator) },
|
||||
.dep_id = operation.clone.dep_id,
|
||||
.res = operation.clone.res,
|
||||
},
|
||||
},
|
||||
.id = task_id,
|
||||
.threadpool_task = ThreadPool.Task{ .callback = &dummyCallback },
|
||||
.data = .{ .git_clone = bun.invalid_fd },
|
||||
.status = .fail,
|
||||
.err = error.GitCommandFailed,
|
||||
};
|
||||
manager.resolve_tasks.push(task);
|
||||
manager.wake();
|
||||
runner.deinit();
|
||||
return;
|
||||
};
|
||||
|
||||
if (Environment.isWindows) {
|
||||
runner.stdout.source = .{ .pipe = bun.default_allocator.create(uv.Pipe) catch bun.outOfMemory() };
|
||||
runner.stderr.source = .{ .pipe = bun.default_allocator.create(uv.Pipe) catch bun.outOfMemory() };
|
||||
}
|
||||
|
||||
const spawn_options = bun.spawn.SpawnOptions{
|
||||
.stdin = .ignore,
|
||||
.stdout = if (Environment.isPosix) .buffer else .{ .buffer = runner.stdout.source.?.pipe },
|
||||
.stderr = if (Environment.isPosix) .buffer else .{ .buffer = runner.stderr.source.?.pipe },
|
||||
.argv0 = git_path.ptr,
|
||||
.windows = if (Environment.isWindows) .{
|
||||
.loop = jsc.EventLoopHandle.init(&manager.event_loop),
|
||||
},
|
||||
.stream = false,
|
||||
};
|
||||
|
||||
// About to spawn git process with argv[0]="{s}"
|
||||
if (comptime Environment.allow_assert) {
|
||||
log("Spawning git with argv[0]={s}, cwd={s}", .{ argv[0].?, manager.cache_directory_path });
|
||||
}
|
||||
var spawn_result = bun.spawn.spawnProcess(&spawn_options, @ptrCast(&argv), envp) catch |err| {
|
||||
log("Failed to spawn git process: {} (argv[0]={s})", .{ err, argv[0].? });
|
||||
// Create a failed task with proper error message
|
||||
const task = manager.preallocated_resolve_tasks.get();
|
||||
task.* = Task{
|
||||
.package_manager = manager,
|
||||
.log = logger.Log.init(manager.allocator),
|
||||
.tag = .git_clone,
|
||||
.request = .{
|
||||
.git_clone = .{
|
||||
.name = operation.clone.name,
|
||||
.url = operation.clone.url,
|
||||
.env = DotEnv.Map{ .map = DotEnv.Map.HashTable.init(manager.allocator) },
|
||||
.dep_id = operation.clone.dep_id,
|
||||
.res = operation.clone.res,
|
||||
},
|
||||
},
|
||||
.id = task_id,
|
||||
.threadpool_task = ThreadPool.Task{ .callback = &dummyCallback },
|
||||
.data = .{ .git_clone = bun.invalid_fd },
|
||||
.status = .fail,
|
||||
.err = error.GitCommandFailed,
|
||||
};
|
||||
manager.resolve_tasks.push(task);
|
||||
manager.wake();
|
||||
runner.deinit();
|
||||
return;
|
||||
};
|
||||
var spawned = spawn_result.unwrap() catch |err| {
|
||||
log("Failed to unwrap spawn result: {}", .{err});
|
||||
// Create a failed task with proper error message
|
||||
const task = manager.preallocated_resolve_tasks.get();
|
||||
task.* = Task{
|
||||
.package_manager = manager,
|
||||
.log = logger.Log.init(manager.allocator),
|
||||
.tag = .git_clone,
|
||||
.request = .{
|
||||
.git_clone = .{
|
||||
.name = operation.clone.name,
|
||||
.url = operation.clone.url,
|
||||
.env = DotEnv.Map{ .map = DotEnv.Map.HashTable.init(manager.allocator) },
|
||||
.dep_id = operation.clone.dep_id,
|
||||
.res = operation.clone.res,
|
||||
},
|
||||
},
|
||||
.id = task_id,
|
||||
.threadpool_task = ThreadPool.Task{ .callback = &dummyCallback },
|
||||
.data = .{ .git_clone = bun.invalid_fd },
|
||||
.status = .fail,
|
||||
.err = error.GitCommandFailed,
|
||||
};
|
||||
manager.resolve_tasks.push(task);
|
||||
manager.wake();
|
||||
runner.deinit();
|
||||
return;
|
||||
};
|
||||
|
||||
// Git process spawned
|
||||
|
||||
if (comptime Environment.isPosix) {
|
||||
if (spawned.stdout) |stdout| {
|
||||
if (!spawned.memfds[1]) {
|
||||
runner.stdout.setParent(runner);
|
||||
_ = bun.sys.setNonblocking(stdout);
|
||||
runner.remaining_fds += 1;
|
||||
|
||||
resetOutputFlags(&runner.stdout, stdout);
|
||||
runner.stdout.start(stdout, true).unwrap() catch |err| {
|
||||
log("Failed to start stdout reader: {}", .{err});
|
||||
// Create a failed task
|
||||
const task = manager.preallocated_resolve_tasks.get();
|
||||
task.* = Task{
|
||||
.package_manager = manager,
|
||||
.log = logger.Log.init(manager.allocator),
|
||||
.tag = .git_clone,
|
||||
.request = .{
|
||||
.git_clone = .{
|
||||
.name = operation.clone.name,
|
||||
.url = operation.clone.url,
|
||||
.env = DotEnv.Map{ .map = DotEnv.Map.HashTable.init(manager.allocator) },
|
||||
.dep_id = operation.clone.dep_id,
|
||||
.res = operation.clone.res,
|
||||
},
|
||||
},
|
||||
.id = task_id,
|
||||
.threadpool_task = ThreadPool.Task{ .callback = &dummyCallback },
|
||||
.data = .{ .git_clone = bun.invalid_fd },
|
||||
.status = .fail,
|
||||
.err = error.GitCommandFailed,
|
||||
};
|
||||
manager.resolve_tasks.push(task);
|
||||
manager.wake();
|
||||
runner.deinit();
|
||||
return;
|
||||
};
|
||||
if (runner.stdout.handle.getPoll()) |poll| {
|
||||
poll.flags.insert(.socket);
|
||||
}
|
||||
} else {
|
||||
runner.stdout.setParent(runner);
|
||||
runner.stdout.startMemfd(stdout);
|
||||
}
|
||||
}
|
||||
if (spawned.stderr) |stderr| {
|
||||
if (!spawned.memfds[2]) {
|
||||
runner.stderr.setParent(runner);
|
||||
_ = bun.sys.setNonblocking(stderr);
|
||||
runner.remaining_fds += 1;
|
||||
|
||||
resetOutputFlags(&runner.stderr, stderr);
|
||||
runner.stderr.start(stderr, true).unwrap() catch |err| {
|
||||
log("Failed to start stderr reader: {}", .{err});
|
||||
// Create a failed task
|
||||
const task = manager.preallocated_resolve_tasks.get();
|
||||
task.* = Task{
|
||||
.package_manager = manager,
|
||||
.log = logger.Log.init(manager.allocator),
|
||||
.tag = .git_clone,
|
||||
.request = .{
|
||||
.git_clone = .{
|
||||
.name = operation.clone.name,
|
||||
.url = operation.clone.url,
|
||||
.env = DotEnv.Map{ .map = DotEnv.Map.HashTable.init(manager.allocator) },
|
||||
.dep_id = operation.clone.dep_id,
|
||||
.res = operation.clone.res,
|
||||
},
|
||||
},
|
||||
.id = task_id,
|
||||
.threadpool_task = ThreadPool.Task{ .callback = &dummyCallback },
|
||||
.data = .{ .git_clone = bun.invalid_fd },
|
||||
.status = .fail,
|
||||
.err = error.GitCommandFailed,
|
||||
};
|
||||
manager.resolve_tasks.push(task);
|
||||
manager.wake();
|
||||
runner.deinit();
|
||||
return;
|
||||
};
|
||||
if (runner.stderr.handle.getPoll()) |poll| {
|
||||
poll.flags.insert(.socket);
|
||||
}
|
||||
} else {
|
||||
runner.stderr.setParent(runner);
|
||||
runner.stderr.startMemfd(stderr);
|
||||
}
|
||||
}
|
||||
} else if (comptime Environment.isWindows) {
|
||||
if (spawned.stdout == .buffer) {
|
||||
runner.stdout.parent = runner;
|
||||
runner.remaining_fds += 1;
|
||||
runner.stdout.startWithCurrentPipe().unwrap() catch |err| {
|
||||
log("Failed to start stdout reader on Windows: {}", .{err});
|
||||
// Create a failed task
|
||||
const task = manager.preallocated_resolve_tasks.get();
|
||||
task.* = Task{
|
||||
.package_manager = manager,
|
||||
.log = logger.Log.init(manager.allocator),
|
||||
.tag = .git_clone,
|
||||
.request = .{
|
||||
.git_clone = .{
|
||||
.name = operation.clone.name,
|
||||
.url = operation.clone.url,
|
||||
.env = DotEnv.Map{ .map = DotEnv.Map.HashTable.init(manager.allocator) },
|
||||
.dep_id = operation.clone.dep_id,
|
||||
.res = operation.clone.res,
|
||||
},
|
||||
},
|
||||
.id = task_id,
|
||||
.threadpool_task = ThreadPool.Task{ .callback = &dummyCallback },
|
||||
.data = .{ .git_clone = bun.invalid_fd },
|
||||
.status = .fail,
|
||||
.err = error.GitCommandFailed,
|
||||
};
|
||||
manager.resolve_tasks.push(task);
|
||||
manager.wake();
|
||||
runner.deinit();
|
||||
return;
|
||||
};
|
||||
}
|
||||
if (spawned.stderr == .buffer) {
|
||||
runner.stderr.parent = runner;
|
||||
runner.remaining_fds += 1;
|
||||
runner.stderr.startWithCurrentPipe().unwrap() catch |err| {
|
||||
log("Failed to start stderr reader on Windows: {}", .{err});
|
||||
// Create a failed task
|
||||
const task = manager.preallocated_resolve_tasks.get();
|
||||
task.* = Task{
|
||||
.package_manager = manager,
|
||||
.log = logger.Log.init(manager.allocator),
|
||||
.tag = .git_clone,
|
||||
.request = .{
|
||||
.git_clone = .{
|
||||
.name = operation.clone.name,
|
||||
.url = operation.clone.url,
|
||||
.env = DotEnv.Map{ .map = DotEnv.Map.HashTable.init(manager.allocator) },
|
||||
.dep_id = operation.clone.dep_id,
|
||||
.res = operation.clone.res,
|
||||
},
|
||||
},
|
||||
.id = task_id,
|
||||
.threadpool_task = ThreadPool.Task{ .callback = &dummyCallback },
|
||||
.data = .{ .git_clone = bun.invalid_fd },
|
||||
.status = .fail,
|
||||
.err = error.GitCommandFailed,
|
||||
};
|
||||
manager.resolve_tasks.push(task);
|
||||
manager.wake();
|
||||
runner.deinit();
|
||||
return;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const event_loop = &manager.event_loop;
|
||||
var process = spawned.toProcess(event_loop, false);
|
||||
|
||||
bun.assertf(runner.process == null, "forgot to call `resetPolls`", .{});
|
||||
runner.process = process;
|
||||
process.setExitHandler(runner);
|
||||
|
||||
switch (process.watchOrReap()) {
|
||||
.err => |err| {
|
||||
if (!process.hasExited())
|
||||
process.onExit(.{ .err = err }, &std.mem.zeroes(bun.spawn.Rusage));
|
||||
},
|
||||
.result => {},
|
||||
}
|
||||
}
|
||||
|
||||
fn handleExit(this: *GitCommandRunner, status: bun.spawn.Status) void {
|
||||
log("Git command finished: task_id={d}, status={}", .{ this.task_id.get(), status });
|
||||
|
||||
const stderr_text = this.stderr.finalBuffer().items;
|
||||
|
||||
this.ensureNotInHeap();
|
||||
|
||||
// Create a task with the result
|
||||
const task = this.manager.preallocated_resolve_tasks.get();
|
||||
|
||||
switch (this.operation) {
|
||||
.clone => |clone| {
|
||||
task.* = Task{
|
||||
.package_manager = this.manager,
|
||||
.log = logger.Log.init(this.manager.allocator),
|
||||
.tag = .git_clone,
|
||||
.request = .{
|
||||
.git_clone = .{
|
||||
.name = clone.name,
|
||||
.url = clone.url,
|
||||
.env = DotEnv.Map{ .map = DotEnv.Map.HashTable.init(this.manager.allocator) },
|
||||
.dep_id = clone.dep_id,
|
||||
.res = clone.res,
|
||||
},
|
||||
},
|
||||
.id = this.task_id,
|
||||
.threadpool_task = ThreadPool.Task{ .callback = &dummyCallback },
|
||||
.data = undefined,
|
||||
.status = undefined,
|
||||
.err = null,
|
||||
};
|
||||
|
||||
switch (status) {
|
||||
.exited => |exit| {
|
||||
if (exit.code == 0) {
|
||||
// Success - get the git dir
|
||||
const folder_name = std.fmt.bufPrintZ(&folder_name_buf, "{any}.git", .{
|
||||
bun.fmt.hexIntLower(this.task_id.get()),
|
||||
}) catch unreachable;
|
||||
if (this.manager.getCacheDirectory().openDirZ(folder_name, .{})) |dir| {
|
||||
task.data = .{ .git_clone = bun.FileDescriptor.fromStdDir(dir) };
|
||||
task.status = .success;
|
||||
} else |err| {
|
||||
task.err = err;
|
||||
task.status = .fail;
|
||||
task.data = .{ .git_clone = bun.invalid_fd };
|
||||
}
|
||||
} else {
|
||||
task.err = error.GitCloneFailed;
|
||||
task.status = .fail;
|
||||
task.data = .{ .git_clone = bun.invalid_fd };
|
||||
|
||||
if (stderr_text.len > 0) {
|
||||
task.log.addErrorFmt(null, logger.Loc.Empty, this.manager.allocator, "git clone failed: {s}", .{stderr_text}) catch {};
|
||||
}
|
||||
}
|
||||
},
|
||||
.signaled => |signal| {
|
||||
task.err = error.GitCloneSignaled;
|
||||
task.status = .fail;
|
||||
task.data = .{ .git_clone = bun.invalid_fd };
|
||||
|
||||
const signal_code = bun.SignalCode.from(signal);
|
||||
task.log.addErrorFmt(null, logger.Loc.Empty, this.manager.allocator, "git clone terminated by {}", .{
|
||||
signal_code.fmt(Output.enable_ansi_colors_stderr),
|
||||
}) catch {};
|
||||
},
|
||||
.err => |_| {
|
||||
task.err = error.GitCloneFailed;
|
||||
task.status = .fail;
|
||||
task.data = .{ .git_clone = bun.invalid_fd };
|
||||
},
|
||||
else => {
|
||||
task.err = error.UnexpectedGitStatus;
|
||||
task.status = .fail;
|
||||
task.data = .{ .git_clone = bun.invalid_fd };
|
||||
},
|
||||
}
|
||||
},
|
||||
.checkout => |checkout| {
|
||||
// Handle two-phase checkout
|
||||
if (this.checkout_phase == .clone) {
|
||||
// First phase completed (clone --no-checkout)
|
||||
if (status == .exited and status.exited.code == 0) {
|
||||
// Now run the actual checkout command
|
||||
this.checkout_phase = .checkout;
|
||||
|
||||
// Find the git executable
|
||||
var path_buf2: bun.PathBuffer = undefined;
|
||||
const git_path = bun.which(&path_buf2, bun.getenvZ("PATH") orelse "", this.manager.cache_directory_path, "git") orelse {
|
||||
log("Failed to find git executable in PATH for checkout", .{});
|
||||
this.handleCheckoutError(error.GitCommandFailed);
|
||||
return;
|
||||
};
|
||||
|
||||
// Build checkout command: git -C <folder> checkout --quiet <resolved>
|
||||
const argv: [7]?[*:0]const u8 = .{
|
||||
git_path.ptr,
|
||||
"-C",
|
||||
bun.default_allocator.dupeZ(u8, checkout.target_dir) catch unreachable,
|
||||
"checkout",
|
||||
"--quiet",
|
||||
bun.default_allocator.dupeZ(u8, checkout.resolved.slice()) catch unreachable,
|
||||
null,
|
||||
};
|
||||
|
||||
// Spawn the checkout command
|
||||
this.has_called_process_exit = false;
|
||||
this.remaining_fds = 0;
|
||||
this.resetPolls();
|
||||
|
||||
var env_map = Repository.shared_env.get(this.manager.allocator, this.manager.env);
|
||||
const envp = env_map.createNullDelimitedEnvMap(this.manager.allocator) catch |err| {
|
||||
log("Failed to create env map for checkout: {}", .{err});
|
||||
this.handleCheckoutError(error.EnvMapFailed);
|
||||
return;
|
||||
};
|
||||
|
||||
if (Environment.isWindows) {
|
||||
this.stdout.source = .{ .pipe = bun.default_allocator.create(uv.Pipe) catch bun.outOfMemory() };
|
||||
this.stderr.source = .{ .pipe = bun.default_allocator.create(uv.Pipe) catch bun.outOfMemory() };
|
||||
}
|
||||
|
||||
const spawn_options = bun.spawn.SpawnOptions{
|
||||
.stdin = .ignore,
|
||||
.stdout = if (Environment.isPosix) .buffer else .{ .buffer = this.stdout.source.?.pipe },
|
||||
.stderr = if (Environment.isPosix) .buffer else .{ .buffer = this.stderr.source.?.pipe },
|
||||
.argv0 = git_path.ptr,
|
||||
.windows = if (Environment.isWindows) .{
|
||||
.loop = jsc.EventLoopHandle.init(&this.manager.event_loop),
|
||||
},
|
||||
.stream = false,
|
||||
};
|
||||
|
||||
var spawn_result = bun.spawn.spawnProcess(&spawn_options, @constCast(@ptrCast(&argv)), envp) catch |err| {
|
||||
log("Failed to spawn git checkout: {}", .{err});
|
||||
this.handleCheckoutError(err);
|
||||
return;
|
||||
};
|
||||
|
||||
var spawned = spawn_result.unwrap() catch |err| {
|
||||
log("Failed to unwrap git checkout spawn: {}", .{err});
|
||||
this.handleCheckoutError(err);
|
||||
return;
|
||||
};
|
||||
|
||||
// Set up process monitoring
|
||||
if (comptime Environment.isPosix) {
|
||||
if (spawned.stdout) |stdout| {
|
||||
if (!spawned.memfds[1]) {
|
||||
this.stdout.setParent(this);
|
||||
_ = bun.sys.setNonblocking(stdout);
|
||||
this.remaining_fds += 1;
|
||||
|
||||
resetOutputFlags(&this.stdout, stdout);
|
||||
this.stdout.start(stdout, true).unwrap() catch |err| {
|
||||
log("Failed to start stdout reader: {}", .{err});
|
||||
this.handleCheckoutError(err);
|
||||
return;
|
||||
};
|
||||
if (this.stdout.handle.getPoll()) |poll| {
|
||||
poll.flags.insert(.socket);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (spawned.stderr) |stderr| {
|
||||
if (!spawned.memfds[2]) {
|
||||
this.stderr.setParent(this);
|
||||
_ = bun.sys.setNonblocking(stderr);
|
||||
this.remaining_fds += 1;
|
||||
|
||||
resetOutputFlags(&this.stderr, stderr);
|
||||
this.stderr.start(stderr, true).unwrap() catch |err| {
|
||||
log("Failed to start stderr reader: {}", .{err});
|
||||
this.handleCheckoutError(err);
|
||||
return;
|
||||
};
|
||||
if (this.stderr.handle.getPoll()) |poll| {
|
||||
poll.flags.insert(.socket);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const event_loop = &this.manager.event_loop;
|
||||
var process = spawned.toProcess(event_loop, false);
|
||||
|
||||
this.process = process;
|
||||
process.setExitHandler(this);
|
||||
|
||||
switch (process.watchOrReap()) {
|
||||
.err => |err| {
|
||||
if (!process.hasExited())
|
||||
process.onExit(.{ .err = err }, &std.mem.zeroes(bun.spawn.Rusage));
|
||||
},
|
||||
.result => {},
|
||||
}
|
||||
|
||||
// Don't continue to the task creation yet
|
||||
return;
|
||||
} else {
|
||||
// Clone failed
|
||||
this.handleCheckoutError(error.GitCloneFailed);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Second phase (actual checkout) completed
|
||||
task.* = Task{
|
||||
.package_manager = this.manager,
|
||||
.log = logger.Log.init(this.manager.allocator),
|
||||
.tag = .git_checkout,
|
||||
.request = .{
|
||||
.git_checkout = .{
|
||||
.repo_dir = checkout.repo_dir,
|
||||
.dependency_id = checkout.dependency_id,
|
||||
.name = checkout.name,
|
||||
.url = checkout.url,
|
||||
.resolved = checkout.resolved,
|
||||
.env = DotEnv.Map{ .map = DotEnv.Map.HashTable.init(this.manager.allocator) },
|
||||
.resolution = checkout.resolution,
|
||||
},
|
||||
},
|
||||
.id = this.task_id,
|
||||
.threadpool_task = ThreadPool.Task{ .callback = &dummyCallback },
|
||||
.data = undefined,
|
||||
.status = undefined,
|
||||
.err = null,
|
||||
.apply_patch_task = if (checkout.patch_name_and_version_hash) |h| brk: {
|
||||
const patch_hash = this.manager.lockfile.patched_dependencies.get(h).?.patchfileHash().?;
|
||||
const ptask = PatchTask.newApplyPatchHash(this.manager, checkout.dependency_id, patch_hash, h);
|
||||
ptask.callback.apply.task_id = this.task_id;
|
||||
break :brk ptask;
|
||||
} else null,
|
||||
};
|
||||
|
||||
switch (status) {
|
||||
.exited => |exit| {
|
||||
if (exit.code == 0) {
|
||||
// Success - create ExtractData
|
||||
const folder_name = PackageManager.cachedGitFolderNamePrint(&folder_name_buf, checkout.resolved.slice(), null);
|
||||
if (this.manager.getCacheDirectory().openDir(folder_name, .{})) |package_dir_const| {
|
||||
var package_dir = package_dir_const;
|
||||
defer package_dir.close();
|
||||
|
||||
// Delete .git directory
|
||||
package_dir.deleteTree(".git") catch {};
|
||||
|
||||
// Create .bun-tag file with resolved commit
|
||||
if (checkout.resolved.slice().len > 0) insert_tag: {
|
||||
const git_tag = package_dir.createFileZ(".bun-tag", .{ .truncate = true }) catch break :insert_tag;
|
||||
defer git_tag.close();
|
||||
git_tag.writeAll(checkout.resolved.slice()) catch {
|
||||
package_dir.deleteFileZ(".bun-tag") catch {};
|
||||
};
|
||||
}
|
||||
|
||||
// Read package.json if it exists
|
||||
if (bun.sys.File.readFileFrom(package_dir, "package.json", this.manager.allocator).unwrap()) |result| {
|
||||
const json_file, const json_buf = result;
|
||||
defer json_file.close();
|
||||
|
||||
var json_path_buf: bun.PathBuffer = undefined;
|
||||
if (json_file.getPath(&json_path_buf).unwrap()) |json_path| {
|
||||
const FileSystem = @import("../fs.zig").FileSystem;
|
||||
if (FileSystem.instance.dirname_store.append(@TypeOf(json_path), json_path)) |ret_json_path| {
|
||||
task.data = .{ .git_checkout = .{
|
||||
.url = checkout.url.slice(),
|
||||
.resolved = checkout.resolved.slice(),
|
||||
.json = .{
|
||||
.path = ret_json_path,
|
||||
.buf = json_buf,
|
||||
},
|
||||
} };
|
||||
task.status = .success;
|
||||
} else |err| {
|
||||
task.err = err;
|
||||
task.status = .fail;
|
||||
task.data = .{ .git_checkout = .{} };
|
||||
}
|
||||
} else |err| {
|
||||
task.err = err;
|
||||
task.status = .fail;
|
||||
task.data = .{ .git_checkout = .{} };
|
||||
}
|
||||
} else |err| {
|
||||
if (err == error.ENOENT) {
|
||||
// Allow git dependencies without package.json
|
||||
task.data = .{ .git_checkout = .{
|
||||
.url = checkout.url.slice(),
|
||||
.resolved = checkout.resolved.slice(),
|
||||
} };
|
||||
task.status = .success;
|
||||
} else {
|
||||
task.err = err;
|
||||
task.status = .fail;
|
||||
task.data = .{ .git_checkout = .{} };
|
||||
}
|
||||
}
|
||||
} else |err| {
|
||||
task.err = err;
|
||||
task.status = .fail;
|
||||
task.data = .{ .git_checkout = .{} };
|
||||
}
|
||||
} else {
|
||||
task.err = error.GitCheckoutFailed;
|
||||
task.status = .fail;
|
||||
task.data = .{ .git_checkout = .{} };
|
||||
|
||||
if (stderr_text.len > 0) {
|
||||
task.log.addErrorFmt(null, logger.Loc.Empty, this.manager.allocator, "git checkout failed: {s}", .{stderr_text}) catch {};
|
||||
}
|
||||
}
|
||||
},
|
||||
.signaled => |signal| {
|
||||
task.err = error.GitCheckoutSignaled;
|
||||
task.status = .fail;
|
||||
task.data = .{ .git_checkout = .{} };
|
||||
|
||||
const signal_code = bun.SignalCode.from(signal);
|
||||
task.log.addErrorFmt(null, logger.Loc.Empty, this.manager.allocator, "git checkout terminated by {}", .{
|
||||
signal_code.fmt(Output.enable_ansi_colors_stderr),
|
||||
}) catch {};
|
||||
},
|
||||
.err => |_| {
|
||||
task.err = error.GitCheckoutFailed;
|
||||
task.status = .fail;
|
||||
task.data = .{ .git_checkout = .{} };
|
||||
},
|
||||
else => {
|
||||
task.err = error.UnexpectedGitStatus;
|
||||
task.status = .fail;
|
||||
task.data = .{ .git_checkout = .{} };
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
// Push the task to the resolve queue
|
||||
this.manager.resolve_tasks.push(task);
|
||||
// Don't decrement pending tasks here - runTasks will do it when processing the task
|
||||
this.manager.wake();
|
||||
|
||||
this.deinit();
|
||||
}
|
||||
|
||||
pub fn onProcessExit(this: *GitCommandRunner, proc: *Process, _: bun.spawn.Status, _: *const bun.spawn.Rusage) void {
|
||||
// onProcessExit called
|
||||
if (this.process != proc) {
|
||||
Output.debugWarn("<d>[GitCommandRunner]<r> onProcessExit called with wrong process", .{});
|
||||
return;
|
||||
}
|
||||
this.has_called_process_exit = true;
|
||||
this.maybeFinished();
|
||||
}
|
||||
|
||||
pub fn resetPolls(this: *GitCommandRunner) void {
|
||||
if (comptime Environment.allow_assert) {
|
||||
bun.assert(this.remaining_fds == 0);
|
||||
}
|
||||
|
||||
if (this.process) |process| {
|
||||
this.process = null;
|
||||
process.close();
|
||||
process.deref();
|
||||
}
|
||||
|
||||
this.stdout.deinit();
|
||||
this.stderr.deinit();
|
||||
this.stdout = OutputReader.init(@This());
|
||||
this.stderr = OutputReader.init(@This());
|
||||
}
|
||||
|
||||
pub fn deinit(this: *GitCommandRunner) void {
|
||||
this.resetPolls();
|
||||
this.ensureNotInHeap();
|
||||
|
||||
this.stdout.deinit();
|
||||
this.stderr.deinit();
|
||||
|
||||
this.* = undefined;
|
||||
bun.destroy(this);
|
||||
}
|
||||
|
||||
// Dummy callback for the task - we never actually call this
|
||||
fn dummyCallback(_: *ThreadPool.Task) void {
|
||||
unreachable;
|
||||
}
|
||||
|
||||
fn handleCheckoutError(this: *GitCommandRunner, err: anyerror) void {
|
||||
const task = this.manager.preallocated_resolve_tasks.get();
|
||||
task.* = Task{
|
||||
.package_manager = this.manager,
|
||||
.log = logger.Log.init(this.manager.allocator),
|
||||
.tag = .git_checkout,
|
||||
.request = .{
|
||||
.git_checkout = .{
|
||||
.repo_dir = this.operation.checkout.repo_dir,
|
||||
.dependency_id = this.operation.checkout.dependency_id,
|
||||
.name = this.operation.checkout.name,
|
||||
.url = this.operation.checkout.url,
|
||||
.resolved = this.operation.checkout.resolved,
|
||||
.env = DotEnv.Map{ .map = DotEnv.Map.HashTable.init(this.manager.allocator) },
|
||||
.resolution = this.operation.checkout.resolution,
|
||||
},
|
||||
},
|
||||
.id = this.task_id,
|
||||
.threadpool_task = ThreadPool.Task{ .callback = &dummyCallback },
|
||||
.data = .{ .git_checkout = .{} },
|
||||
.status = .fail,
|
||||
.err = err,
|
||||
.apply_patch_task = null, // Don't apply patches on error
|
||||
};
|
||||
|
||||
this.manager.resolve_tasks.push(task);
|
||||
this.manager.wake();
|
||||
this.deinit();
|
||||
}
|
||||
};
|
||||
|
||||
var folder_name_buf: [1024]u8 = undefined;
|
||||
|
||||
const std = @import("std");
|
||||
const Repository = @import("./repository.zig").Repository;
|
||||
|
||||
const DependencyID = @import("./install.zig").DependencyID;
|
||||
const ExtractData = @import("./install.zig").ExtractData;
|
||||
const PackageManager = @import("./install.zig").PackageManager;
|
||||
const PatchTask = @import("./install.zig").PatchTask;
|
||||
const Resolution = @import("./install.zig").Resolution;
|
||||
const Task = @import("./install.zig").Task;
|
||||
|
||||
const bun = @import("bun");
|
||||
const DotEnv = bun.DotEnv;
|
||||
const Environment = bun.Environment;
|
||||
const Output = bun.Output;
|
||||
const ThreadPool = bun.ThreadPool;
|
||||
const jsc = bun.jsc;
|
||||
const logger = bun.logger;
|
||||
const strings = bun.strings;
|
||||
const Process = bun.spawn.Process;
|
||||
@@ -247,6 +247,7 @@ pub const TextLockfile = @import("./lockfile/bun.lock.zig");
|
||||
pub const Bin = @import("./bin.zig").Bin;
|
||||
pub const FolderResolution = @import("./resolvers/folder_resolver.zig").FolderResolution;
|
||||
pub const LifecycleScriptSubprocess = @import("./lifecycle_script_runner.zig").LifecycleScriptSubprocess;
|
||||
pub const GitCommandRunner = @import("./git_command_runner.zig").GitCommandRunner;
|
||||
pub const PackageInstall = @import("./PackageInstall.zig").PackageInstall;
|
||||
pub const Repository = @import("./repository.zig").Repository;
|
||||
pub const Resolution = @import("./resolution.zig").Resolution;
|
||||
|
||||
@@ -406,6 +406,16 @@ pub const Repository = extern struct {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Handle shorthand formats like bitbucket:user/repo or gitlab:user/repo
|
||||
if (strings.indexOfChar(url, ':')) |colon_index| {
|
||||
const prefix = url[0..colon_index];
|
||||
if (Hosts.get(prefix)) |domain_suffix| {
|
||||
const path = url[colon_index + 1 ..];
|
||||
const result = std.fmt.bufPrint(&ssh_path_buf, "git@{s}{s}:{s}", .{ prefix, domain_suffix, path }) catch return null;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if (strings.hasPrefixComptime(url, "git@") or strings.hasPrefixComptime(url, "ssh://")) {
|
||||
return url;
|
||||
}
|
||||
@@ -442,6 +452,16 @@ pub const Repository = extern struct {
|
||||
return url;
|
||||
}
|
||||
|
||||
// Handle shorthand formats like bitbucket:user/repo or gitlab:user/repo
|
||||
if (strings.indexOfChar(url, ':')) |colon_index| {
|
||||
const prefix = url[0..colon_index];
|
||||
if (Hosts.get(prefix)) |domain_suffix| {
|
||||
const path = url[colon_index + 1 ..];
|
||||
const result = std.fmt.bufPrint(&final_path_buf, "https://{s}{s}/{s}", .{ prefix, domain_suffix, path }) catch return null;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if (strings.hasPrefixComptime(url, "ssh://")) {
|
||||
final_path_buf[0.."https".len].* = "https".*;
|
||||
bun.copy(u8, final_path_buf["https".len..], url["ssh".len..]);
|
||||
@@ -486,6 +506,7 @@ pub const Repository = extern struct {
|
||||
attempt: u8,
|
||||
) !std.fs.Dir {
|
||||
bun.analytics.Features.git_dependencies += 1;
|
||||
// Repository.download called
|
||||
const folder_name = try std.fmt.bufPrintZ(&folder_name_buf, "{any}.git", .{
|
||||
bun.fmt.hexIntLower(task_id.get()),
|
||||
});
|
||||
|
||||
90
test/cli/install/git-dependency.test.ts
Normal file
90
test/cli/install/git-dependency.test.ts
Normal file
@@ -0,0 +1,90 @@
|
||||
import { spawnSync } from "bun";
|
||||
import { expect, test } from "bun:test";
|
||||
import { existsSync } from "fs";
|
||||
import { bunEnv, bunExe, tempDirWithFiles } from "harness";
|
||||
import { join } from "path";
|
||||
|
||||
test("install github dependency", async () => {
|
||||
const dir = tempDirWithFiles("test-github-install", {
|
||||
"package.json": JSON.stringify({
|
||||
name: "test-github-install",
|
||||
dependencies: {
|
||||
// Using github: shorthand which downloads as tarball
|
||||
"awesome-bun": "github:oven-sh/awesome-bun",
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
const result = spawnSync({
|
||||
cmd: [bunExe(), "install"],
|
||||
env: bunEnv,
|
||||
cwd: dir,
|
||||
stdout: "pipe",
|
||||
stderr: "pipe",
|
||||
});
|
||||
|
||||
expect(result.exitCode).toBe(0);
|
||||
expect(result.stderr.toString()).not.toContain("error");
|
||||
|
||||
// Check that the package was installed
|
||||
const packagePath = join(dir, "node_modules", "awesome-bun");
|
||||
expect(existsSync(packagePath)).toBe(true);
|
||||
|
||||
// Should have README.md
|
||||
const readmePath = join(packagePath, "README.md");
|
||||
expect(existsSync(readmePath)).toBe(true);
|
||||
});
|
||||
|
||||
test("install git+https URL dependency", async () => {
|
||||
const dir = tempDirWithFiles("test-git-url", {
|
||||
"package.json": JSON.stringify({
|
||||
name: "test-git-url",
|
||||
dependencies: {
|
||||
// Using git+ prefix which triggers git clone - use a smaller repo
|
||||
"awesome-bun": "git+https://github.com/oven-sh/awesome-bun.git#main",
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
const result = spawnSync({
|
||||
cmd: [bunExe(), "install"],
|
||||
env: bunEnv,
|
||||
cwd: dir,
|
||||
stdout: "pipe",
|
||||
stderr: "pipe",
|
||||
});
|
||||
|
||||
expect(result.exitCode).toBe(0);
|
||||
expect(result.stderr.toString()).not.toContain("error");
|
||||
|
||||
// Check that the package was installed
|
||||
const packagePath = join(dir, "node_modules", "awesome-bun");
|
||||
expect(existsSync(packagePath)).toBe(true);
|
||||
});
|
||||
|
||||
test("install git URL without commit hash", async () => {
|
||||
const dir = tempDirWithFiles("test-git-no-hash", {
|
||||
"package.json": JSON.stringify({
|
||||
name: "test-git-no-hash",
|
||||
dependencies: {
|
||||
// Using HEAD of default branch
|
||||
"awesome-bun-2": "git+https://github.com/oven-sh/awesome-bun.git",
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
const result = spawnSync({
|
||||
cmd: [bunExe(), "install"],
|
||||
env: bunEnv,
|
||||
cwd: dir,
|
||||
stdout: "pipe",
|
||||
stderr: "pipe",
|
||||
});
|
||||
|
||||
expect(result.exitCode).toBe(0);
|
||||
expect(result.stderr.toString()).not.toContain("error");
|
||||
|
||||
// Check that the package was installed
|
||||
const packagePath = join(dir, "node_modules", "awesome-bun-2");
|
||||
expect(existsSync(packagePath)).toBe(true);
|
||||
});
|
||||
@@ -4,7 +4,7 @@
|
||||
"!= alloc.ptr": 0,
|
||||
"!= allocator.ptr": 0,
|
||||
".arguments_old(": 279,
|
||||
".stdDir()": 40,
|
||||
".stdDir()": 39,
|
||||
".stdFile()": 18,
|
||||
"// autofix": 168,
|
||||
": [a-zA-Z0-9_\\.\\*\\?\\[\\]\\(\\)]+ = undefined,": 228,
|
||||
|
||||
Reference in New Issue
Block a user