Merge pull request #1620 from nagilson/nagilson-linux-single-prompt

Reduce Linux Prompt to Single Ask
This commit is contained in:
Noah Gilson 2024-02-05 12:34:25 -08:00 коммит произвёл GitHub
Родитель 2c4ca30313 6b66731a54
Коммит cd362f67ba
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
20 изменённых файлов: 1433 добавлений и 329 удалений

1
.vscode/settings.json поставляемый
Просмотреть файл

@ -9,6 +9,7 @@
"HKCU",
"HKEY",
"norestart",
"proccom",
"programfiles",
"REGHEXVALUE",
"REGTYPE"

Просмотреть файл

@ -1,3 +1,4 @@
# The library doesn't get webpacked, but it needs the copy of items that would normally be webpacked
# ... into the SDK or Runtime Extension for it to run in local dev scenarios.
Copy-Item ".\vscode-dotnet-runtime-library\distro-data\" -Destination ".\vscode-dotnet-runtime-library\dist\Acquisition\" -Recurse -Force
Copy-Item ".\vscode-dotnet-runtime-library\install scripts\" -Destination ".\vscode-dotnet-runtime-library\dist\utils\" -Recurse -Force

Просмотреть файл

@ -2,3 +2,4 @@ echo ""
echo "----------- Copying Library Webpacked Dependencies -----------"
echo "" # See the build.ps1 for more details on why we do this
cp -r ./vscode-dotnet-runtime-library/distro-data ./vscode-dotnet-runtime-library/dist/Acquisition
cp -r "./vscode-dotnet-runtime-library/install scripts" ./vscode-dotnet-runtime-library/dist/Utils

476
vscode-dotnet-runtime-extension/package-lock.json сгенерированный
Просмотреть файл

@ -9,6 +9,7 @@
"version": "2.0.1",
"license": "MIT",
"dependencies": {
"@types/chai-as-promised": "^7.1.8",
"axios": "^1.3.4",
"axios-cache-interceptor": "^1.0.1",
"axios-retry": "^3.4.0",
@ -24,6 +25,7 @@
"open": "^8.4.0",
"public-ip": "5.0.0",
"rimraf": "3.0.2",
"safe-array-concat": "^1.1.0",
"safe-regex-test": "^1.0.0",
"shelljs": "^0.8.5",
"ts-loader": "^9.2.6",
@ -31,6 +33,7 @@
"typescript": "4.4.4",
"vscode-dotnet-runtime-library": "file:../vscode-dotnet-runtime-library",
"vscode-test": "^1.6.1",
"webpack-permissions-plugin": "^1.0.9",
"yarn": "^1.22.19"
},
"devDependencies": {
@ -377,9 +380,17 @@
"version": "4.3.5",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@types/chai/-/chai-4.3.5.tgz",
"integrity": "sha1-rmm8uxvrtoxKwLEenY7QRSazVis=",
"dev": true,
"license": "MIT"
},
"node_modules/@types/chai-as-promised": {
"version": "7.1.8",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@types/chai-as-promised/-/chai-as-promised-7.1.8.tgz",
"integrity": "sha1-8rPYLVPFlia11rvAh2Z8y0tnf+k=",
"license": "MIT",
"dependencies": {
"@types/chai": "*"
}
},
"node_modules/@types/eslint": {
"version": "8.4.5",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@types/eslint/-/eslint-8.4.5.tgz",
@ -1000,13 +1011,14 @@
}
},
"node_modules/call-bind": {
"version": "1.0.2",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/call-bind/-/call-bind-1.0.2.tgz",
"integrity": "sha1-sdTonmiBGcPJqQOtMKuy9qkZvjw=",
"version": "1.0.5",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/call-bind/-/call-bind-1.0.5.tgz",
"integrity": "sha1-b6K3hFzg6km/TYue9kcnosLi5RM=",
"license": "MIT",
"dependencies": {
"function-bind": "^1.1.1",
"get-intrinsic": "^1.0.2"
"function-bind": "^1.1.2",
"get-intrinsic": "^1.2.1",
"set-function-length": "^1.1.1"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
@ -1380,6 +1392,20 @@
"node": ">=10"
}
},
"node_modules/define-data-property": {
"version": "1.1.1",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/define-data-property/-/define-data-property-1.1.1.tgz",
"integrity": "sha1-w1980KsJiDSA0SrFyyE3FVh4ALM=",
"license": "MIT",
"dependencies": {
"get-intrinsic": "^1.2.1",
"gopd": "^1.0.1",
"has-property-descriptors": "^1.0.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/define-lazy-prop": {
"version": "2.0.0",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz",
@ -1506,6 +1532,12 @@
"node": ">=4"
}
},
"node_modules/err-code": {
"version": "1.1.2",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/err-code/-/err-code-1.1.2.tgz",
"integrity": "sha1-BuARbTAo9q70gGhJ6w6mp0iuaWA=",
"license": "MIT"
},
"node_modules/es-module-lexer": {
"version": "1.3.0",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/es-module-lexer/-/es-module-lexer-1.3.0.tgz",
@ -1635,6 +1667,12 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/extend": {
"version": "3.0.2",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/extend/-/extend-3.0.2.tgz",
"integrity": "sha1-+LETa0Bx+9jrFAr/hYsQGewpFfo=",
"license": "MIT"
},
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@ -1700,6 +1738,58 @@
"reusify": "^1.0.4"
}
},
"node_modules/file-js": {
"version": "0.3.0",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/file-js/-/file-js-0.3.0.tgz",
"integrity": "sha1-+rRr94I0bJKUSZ8fDSrQfYOPJdE=",
"license": "MIT",
"dependencies": {
"bluebird": "^3.4.7",
"minimatch": "^3.0.3",
"proper-lockfile": "^1.2.0"
}
},
"node_modules/filehound": {
"version": "1.17.6",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/filehound/-/filehound-1.17.6.tgz",
"integrity": "sha1-1dh71pQxbqZzvQZCt3a1CNP5ih0=",
"license": "MIT",
"dependencies": {
"bluebird": "^3.7.2",
"file-js": "0.3.0",
"lodash": "^4.17.21",
"minimatch": "^5.0.0",
"moment": "^2.29.1",
"unit-compare": "^1.0.1"
}
},
"node_modules/filehound/node_modules/bluebird": {
"version": "3.7.2",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/bluebird/-/bluebird-3.7.2.tgz",
"integrity": "sha1-nyKcFb4nJFT/qXOs4NvueaGww28=",
"license": "MIT"
},
"node_modules/filehound/node_modules/brace-expansion": {
"version": "2.0.1",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/brace-expansion/-/brace-expansion-2.0.1.tgz",
"integrity": "sha1-HtxFng8MVISG7Pn8mfIiE2S5oK4=",
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0"
}
},
"node_modules/filehound/node_modules/minimatch": {
"version": "5.1.6",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/minimatch/-/minimatch-5.1.6.tgz",
"integrity": "sha1-HPy4z1Ui6mmVLNKvla4JR38SKpY=",
"license": "ISC",
"dependencies": {
"brace-expansion": "^2.0.1"
},
"engines": {
"node": ">=10"
}
},
"node_modules/fill-range": {
"version": "7.0.1",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/fill-range/-/fill-range-7.0.1.tgz",
@ -1827,10 +1917,13 @@
}
},
"node_modules/function-bind": {
"version": "1.1.1",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/function-bind/-/function-bind-1.1.1.tgz",
"integrity": "sha1-pWiZ0+o8m6uHS7l3O3xe3pL0iV0=",
"license": "MIT"
"version": "1.1.2",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/function-bind/-/function-bind-1.1.2.tgz",
"integrity": "sha1-LALYZNl/PqbIgwxGTL0Rq26rehw=",
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/get-caller-file": {
"version": "2.0.5",
@ -1851,14 +1944,15 @@
}
},
"node_modules/get-intrinsic": {
"version": "1.1.3",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/get-intrinsic/-/get-intrinsic-1.1.3.tgz",
"integrity": "sha1-BjyEMprZPoOJPH9PJD72P/o1E4U=",
"version": "1.2.2",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/get-intrinsic/-/get-intrinsic-1.2.2.tgz",
"integrity": "sha1-KBt2IpcRI+HvSzyQ/XU5MG2pPzs=",
"license": "MIT",
"dependencies": {
"function-bind": "^1.1.1",
"has": "^1.0.3",
"has-symbols": "^1.0.3"
"function-bind": "^1.1.2",
"has-proto": "^1.0.1",
"has-symbols": "^1.0.3",
"hasown": "^2.0.0"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
@ -1939,6 +2033,18 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/gopd": {
"version": "1.0.1",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/gopd/-/gopd-1.0.1.tgz",
"integrity": "sha1-Kf923mnax0ibfAkYpXiOVkd8Myw=",
"license": "MIT",
"dependencies": {
"get-intrinsic": "^1.1.3"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/got": {
"version": "11.8.5",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/got/-/got-11.8.5.tgz",
@ -2000,6 +2106,30 @@
"node": ">=8"
}
},
"node_modules/has-property-descriptors": {
"version": "1.0.1",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz",
"integrity": "sha1-UrowtsXsh/2J+ldLwcORJcb2U0A=",
"license": "MIT",
"dependencies": {
"get-intrinsic": "^1.2.2"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/has-proto": {
"version": "1.0.1",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/has-proto/-/has-proto-1.0.1.tgz",
"integrity": "sha1-GIXBMFU4lYr/Rp/vN5N8InlUCOA=",
"license": "MIT",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/has-symbols": {
"version": "1.0.3",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/has-symbols/-/has-symbols-1.0.3.tgz",
@ -2037,6 +2167,18 @@
"minimalistic-assert": "^1.0.1"
}
},
"node_modules/hasown": {
"version": "2.0.0",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/hasown/-/hasown-2.0.0.tgz",
"integrity": "sha1-9MUT1FSle3x+FlB3jeImsRcAVGw=",
"license": "MIT",
"dependencies": {
"function-bind": "^1.1.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/he": {
"version": "1.2.0",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/he/-/he-1.2.0.tgz",
@ -2705,6 +2847,12 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/lodash": {
"version": "4.17.21",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha1-Z5WRxWTDv/quhFTPCz3zcMPWkRw=",
"license": "MIT"
},
"node_modules/log-symbols": {
"version": "4.1.0",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/log-symbols/-/log-symbols-4.1.0.tgz",
@ -2949,6 +3097,15 @@
"node": ">=10"
}
},
"node_modules/moment": {
"version": "2.30.1",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/moment/-/moment-2.30.1.tgz",
"integrity": "sha1-+MkcB7enhuMMWZJt9TC06slpdK4=",
"license": "MIT",
"engines": {
"node": "*"
}
},
"node_modules/ms": {
"version": "2.1.3",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/ms/-/ms-2.1.3.tgz",
@ -3318,6 +3475,18 @@
"integrity": "sha1-eCDZsWEgzFXKmud5JoCufbptf+I=",
"license": "MIT"
},
"node_modules/proper-lockfile": {
"version": "1.2.0",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/proper-lockfile/-/proper-lockfile-1.2.0.tgz",
"integrity": "sha1-zv9d2J0+XxD7deHo52vHWAGlnDQ=",
"license": "MIT",
"dependencies": {
"err-code": "^1.0.0",
"extend": "^3.0.0",
"graceful-fs": "^4.1.2",
"retry": "^0.10.0"
}
},
"node_modules/proxy-from-env": {
"version": "1.1.0",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
@ -3677,6 +3846,15 @@
"lowercase-keys": "^2.0.0"
}
},
"node_modules/retry": {
"version": "0.10.1",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/retry/-/retry-0.10.1.tgz",
"integrity": "sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q=",
"license": "MIT",
"engines": {
"node": "*"
}
},
"node_modules/reusify": {
"version": "1.0.4",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/reusify/-/reusify-1.0.4.tgz",
@ -3727,6 +3905,30 @@
"queue-microtask": "^1.2.2"
}
},
"node_modules/safe-array-concat": {
"version": "1.1.0",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/safe-array-concat/-/safe-array-concat-1.1.0.tgz",
"integrity": "sha1-jQyunLgG1tHAbgirE9hHKT6+BpI=",
"license": "MIT",
"dependencies": {
"call-bind": "^1.0.5",
"get-intrinsic": "^1.2.2",
"has-symbols": "^1.0.3",
"isarray": "^2.0.5"
},
"engines": {
"node": ">=0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/safe-array-concat/node_modules/isarray": {
"version": "2.0.5",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/isarray/-/isarray-2.0.5.tgz",
"integrity": "sha1-ivHkwSISRMxiRZ+vOJQNTmRKVyM=",
"license": "MIT"
},
"node_modules/safe-buffer": {
"version": "5.2.1",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/safe-buffer/-/safe-buffer-5.2.1.tgz",
@ -3797,6 +3999,22 @@
"randombytes": "^2.1.0"
}
},
"node_modules/set-function-length": {
"version": "1.2.0",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/set-function-length/-/set-function-length-1.2.0.tgz",
"integrity": "sha1-L4HcbBbHBZvaWrfILBHwOlFe2OE=",
"license": "MIT",
"dependencies": {
"define-data-property": "^1.1.1",
"function-bind": "^1.1.2",
"get-intrinsic": "^1.2.2",
"gopd": "^1.0.1",
"has-property-descriptors": "^1.0.1"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/setimmediate": {
"version": "1.0.5",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/setimmediate/-/setimmediate-1.0.5.tgz",
@ -4291,6 +4509,15 @@
"node": ">=4.2.0"
}
},
"node_modules/unit-compare": {
"version": "1.0.1",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/unit-compare/-/unit-compare-1.0.1.tgz",
"integrity": "sha1-DHRZ8OW/U2N+qHPKPO4Y3i7so4Y=",
"license": "ISC",
"dependencies": {
"moment": "^2.14.1"
}
},
"node_modules/unzipper": {
"version": "0.10.11",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/unzipper/-/unzipper-0.10.11.tgz",
@ -4584,6 +4811,15 @@
"node": ">=10.0.0"
}
},
"node_modules/webpack-permissions-plugin": {
"version": "1.0.9",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/webpack-permissions-plugin/-/webpack-permissions-plugin-1.0.9.tgz",
"integrity": "sha1-gK5aCe0ZkdvbL5/kYYuNVxlhbh4=",
"license": "MIT",
"dependencies": {
"filehound": "^1.17.6"
}
},
"node_modules/webpack-sources": {
"version": "3.2.3",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/webpack-sources/-/webpack-sources-3.2.3.tgz",
@ -4923,8 +5159,15 @@
"@types/chai": {
"version": "4.3.5",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@types/chai/-/chai-4.3.5.tgz",
"integrity": "sha1-rmm8uxvrtoxKwLEenY7QRSazVis=",
"dev": true
"integrity": "sha1-rmm8uxvrtoxKwLEenY7QRSazVis="
},
"@types/chai-as-promised": {
"version": "7.1.8",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@types/chai-as-promised/-/chai-as-promised-7.1.8.tgz",
"integrity": "sha1-8rPYLVPFlia11rvAh2Z8y0tnf+k=",
"requires": {
"@types/chai": "*"
}
},
"@types/eslint": {
"version": "8.4.5",
@ -5393,12 +5636,13 @@
}
},
"call-bind": {
"version": "1.0.2",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/call-bind/-/call-bind-1.0.2.tgz",
"integrity": "sha1-sdTonmiBGcPJqQOtMKuy9qkZvjw=",
"version": "1.0.5",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/call-bind/-/call-bind-1.0.5.tgz",
"integrity": "sha1-b6K3hFzg6km/TYue9kcnosLi5RM=",
"requires": {
"function-bind": "^1.1.1",
"get-intrinsic": "^1.0.2"
"function-bind": "^1.1.2",
"get-intrinsic": "^1.2.1",
"set-function-length": "^1.1.1"
}
},
"camelcase": {
@ -5641,6 +5885,16 @@
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/defer-to-connect/-/defer-to-connect-2.0.1.tgz",
"integrity": "sha1-gBa9tBQ+RjK3ejRJxiNid95SBYc="
},
"define-data-property": {
"version": "1.1.1",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/define-data-property/-/define-data-property-1.1.1.tgz",
"integrity": "sha1-w1980KsJiDSA0SrFyyE3FVh4ALM=",
"requires": {
"get-intrinsic": "^1.2.1",
"gopd": "^1.0.1",
"has-property-descriptors": "^1.0.0"
}
},
"define-lazy-prop": {
"version": "2.0.0",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz",
@ -5727,6 +5981,11 @@
"integrity": "sha1-Bjd+Pl9NN5/qesWS1a2JJ+DE1HU=",
"dev": true
},
"err-code": {
"version": "1.1.2",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/err-code/-/err-code-1.1.2.tgz",
"integrity": "sha1-BuARbTAo9q70gGhJ6w6mp0iuaWA="
},
"es-module-lexer": {
"version": "1.3.0",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/es-module-lexer/-/es-module-lexer-1.3.0.tgz",
@ -5806,6 +6065,11 @@
}
}
},
"extend": {
"version": "3.0.2",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/extend/-/extend-3.0.2.tgz",
"integrity": "sha1-+LETa0Bx+9jrFAr/hYsQGewpFfo="
},
"fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@ -5860,6 +6124,52 @@
"reusify": "^1.0.4"
}
},
"file-js": {
"version": "0.3.0",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/file-js/-/file-js-0.3.0.tgz",
"integrity": "sha1-+rRr94I0bJKUSZ8fDSrQfYOPJdE=",
"requires": {
"bluebird": "^3.4.7",
"minimatch": "^3.0.3",
"proper-lockfile": "^1.2.0"
}
},
"filehound": {
"version": "1.17.6",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/filehound/-/filehound-1.17.6.tgz",
"integrity": "sha1-1dh71pQxbqZzvQZCt3a1CNP5ih0=",
"requires": {
"bluebird": "^3.7.2",
"file-js": "0.3.0",
"lodash": "^4.17.21",
"minimatch": "^5.0.0",
"moment": "^2.29.1",
"unit-compare": "^1.0.1"
},
"dependencies": {
"bluebird": {
"version": "3.7.2",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/bluebird/-/bluebird-3.7.2.tgz",
"integrity": "sha1-nyKcFb4nJFT/qXOs4NvueaGww28="
},
"brace-expansion": {
"version": "2.0.1",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/brace-expansion/-/brace-expansion-2.0.1.tgz",
"integrity": "sha1-HtxFng8MVISG7Pn8mfIiE2S5oK4=",
"requires": {
"balanced-match": "^1.0.0"
}
},
"minimatch": {
"version": "5.1.6",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/minimatch/-/minimatch-5.1.6.tgz",
"integrity": "sha1-HPy4z1Ui6mmVLNKvla4JR38SKpY=",
"requires": {
"brace-expansion": "^2.0.1"
}
}
}
},
"fill-range": {
"version": "7.0.1",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/fill-range/-/fill-range-7.0.1.tgz",
@ -5935,9 +6245,9 @@
}
},
"function-bind": {
"version": "1.1.1",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/function-bind/-/function-bind-1.1.1.tgz",
"integrity": "sha1-pWiZ0+o8m6uHS7l3O3xe3pL0iV0="
"version": "1.1.2",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/function-bind/-/function-bind-1.1.2.tgz",
"integrity": "sha1-LALYZNl/PqbIgwxGTL0Rq26rehw="
},
"get-caller-file": {
"version": "2.0.5",
@ -5950,13 +6260,14 @@
"integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE="
},
"get-intrinsic": {
"version": "1.1.3",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/get-intrinsic/-/get-intrinsic-1.1.3.tgz",
"integrity": "sha1-BjyEMprZPoOJPH9PJD72P/o1E4U=",
"version": "1.2.2",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/get-intrinsic/-/get-intrinsic-1.2.2.tgz",
"integrity": "sha1-KBt2IpcRI+HvSzyQ/XU5MG2pPzs=",
"requires": {
"function-bind": "^1.1.1",
"has": "^1.0.3",
"has-symbols": "^1.0.3"
"function-bind": "^1.1.2",
"has-proto": "^1.0.1",
"has-symbols": "^1.0.3",
"hasown": "^2.0.0"
}
},
"get-stream": {
@ -6008,6 +6319,14 @@
"slash": "^3.0.0"
}
},
"gopd": {
"version": "1.0.1",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/gopd/-/gopd-1.0.1.tgz",
"integrity": "sha1-Kf923mnax0ibfAkYpXiOVkd8Myw=",
"requires": {
"get-intrinsic": "^1.1.3"
}
},
"got": {
"version": "11.8.5",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/got/-/got-11.8.5.tgz",
@ -6049,6 +6368,19 @@
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha1-lEdx/ZyByBJlxNaUGGDaBrtZR5s="
},
"has-property-descriptors": {
"version": "1.0.1",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz",
"integrity": "sha1-UrowtsXsh/2J+ldLwcORJcb2U0A=",
"requires": {
"get-intrinsic": "^1.2.2"
}
},
"has-proto": {
"version": "1.0.1",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/has-proto/-/has-proto-1.0.1.tgz",
"integrity": "sha1-GIXBMFU4lYr/Rp/vN5N8InlUCOA="
},
"has-symbols": {
"version": "1.0.3",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/has-symbols/-/has-symbols-1.0.3.tgz",
@ -6071,6 +6403,14 @@
"minimalistic-assert": "^1.0.1"
}
},
"hasown": {
"version": "2.0.0",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/hasown/-/hasown-2.0.0.tgz",
"integrity": "sha1-9MUT1FSle3x+FlB3jeImsRcAVGw=",
"requires": {
"function-bind": "^1.1.2"
}
},
"he": {
"version": "1.2.0",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/he/-/he-1.2.0.tgz",
@ -6512,6 +6852,11 @@
"p-locate": "^5.0.0"
}
},
"lodash": {
"version": "4.17.21",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha1-Z5WRxWTDv/quhFTPCz3zcMPWkRw="
},
"log-symbols": {
"version": "4.1.0",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/log-symbols/-/log-symbols-4.1.0.tgz",
@ -6678,6 +7023,11 @@
}
}
},
"moment": {
"version": "2.30.1",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/moment/-/moment-2.30.1.tgz",
"integrity": "sha1-+MkcB7enhuMMWZJt9TC06slpdK4="
},
"ms": {
"version": "2.1.3",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/ms/-/ms-2.1.3.tgz",
@ -6907,6 +7257,17 @@
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
"integrity": "sha1-eCDZsWEgzFXKmud5JoCufbptf+I="
},
"proper-lockfile": {
"version": "1.2.0",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/proper-lockfile/-/proper-lockfile-1.2.0.tgz",
"integrity": "sha1-zv9d2J0+XxD7deHo52vHWAGlnDQ=",
"requires": {
"err-code": "^1.0.0",
"extend": "^3.0.0",
"graceful-fs": "^4.1.2",
"retry": "^0.10.0"
}
},
"proxy-from-env": {
"version": "1.1.0",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
@ -7134,6 +7495,11 @@
"lowercase-keys": "^2.0.0"
}
},
"retry": {
"version": "0.10.1",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/retry/-/retry-0.10.1.tgz",
"integrity": "sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q="
},
"reusify": {
"version": "1.0.4",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/reusify/-/reusify-1.0.4.tgz",
@ -7157,6 +7523,24 @@
"queue-microtask": "^1.2.2"
}
},
"safe-array-concat": {
"version": "1.1.0",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/safe-array-concat/-/safe-array-concat-1.1.0.tgz",
"integrity": "sha1-jQyunLgG1tHAbgirE9hHKT6+BpI=",
"requires": {
"call-bind": "^1.0.5",
"get-intrinsic": "^1.2.2",
"has-symbols": "^1.0.3",
"isarray": "^2.0.5"
},
"dependencies": {
"isarray": {
"version": "2.0.5",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/isarray/-/isarray-2.0.5.tgz",
"integrity": "sha1-ivHkwSISRMxiRZ+vOJQNTmRKVyM="
}
}
},
"safe-buffer": {
"version": "5.2.1",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/safe-buffer/-/safe-buffer-5.2.1.tgz",
@ -7195,6 +7579,18 @@
"randombytes": "^2.1.0"
}
},
"set-function-length": {
"version": "1.2.0",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/set-function-length/-/set-function-length-1.2.0.tgz",
"integrity": "sha1-L4HcbBbHBZvaWrfILBHwOlFe2OE=",
"requires": {
"define-data-property": "^1.1.1",
"function-bind": "^1.1.2",
"get-intrinsic": "^1.2.2",
"gopd": "^1.0.1",
"has-property-descriptors": "^1.0.1"
}
},
"setimmediate": {
"version": "1.0.5",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/setimmediate/-/setimmediate-1.0.5.tgz",
@ -7515,6 +7911,14 @@
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/typescript/-/typescript-4.4.4.tgz",
"integrity": "sha1-LNAaGh8WBwTTEB/VpY/w+fy4Aww="
},
"unit-compare": {
"version": "1.0.1",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/unit-compare/-/unit-compare-1.0.1.tgz",
"integrity": "sha1-DHRZ8OW/U2N+qHPKPO4Y3i7so4Y=",
"requires": {
"moment": "^2.14.1"
}
},
"unzipper": {
"version": "0.10.11",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/unzipper/-/unzipper-0.10.11.tgz",
@ -7743,6 +8147,14 @@
"wildcard": "^2.0.0"
}
},
"webpack-permissions-plugin": {
"version": "1.0.9",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/webpack-permissions-plugin/-/webpack-permissions-plugin-1.0.9.tgz",
"integrity": "sha1-gK5aCe0ZkdvbL5/kYYuNVxlhbh4=",
"requires": {
"filehound": "^1.17.6"
}
},
"webpack-sources": {
"version": "3.2.3",
"resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/webpack-sources/-/webpack-sources-3.2.3.tgz",

Просмотреть файл

@ -68,7 +68,11 @@
"dotnetAcquisitionExtension.existingDotnetPath": {
"type": "array",
"description": "File Path to an existing installation of .NET. Used for both the .NET SDK and .NET Runtime.",
"examples": ["C:\\Program Files\\dotnet\\dotnet.exe", "/usr/local/share/dotnet/dotnet", "/usr/lib/dotnet/dotnet"]
"examples": [
"C:\\Program Files\\dotnet\\dotnet.exe",
"/usr/local/share/dotnet/dotnet",
"/usr/lib/dotnet/dotnet"
]
},
"dotnetAcquisitionExtension.proxyUrl": {
"type": "string",
@ -88,6 +92,7 @@
"webpack": "webpack --mode development"
},
"dependencies": {
"@types/chai-as-promised": "^7.1.8",
"axios": "^1.3.4",
"axios-cache-interceptor": "^1.0.1",
"axios-retry": "^3.4.0",
@ -103,6 +108,7 @@
"open": "^8.4.0",
"public-ip": "5.0.0",
"rimraf": "3.0.2",
"safe-array-concat": "^1.1.0",
"safe-regex-test": "^1.0.0",
"shelljs": "^0.8.5",
"ts-loader": "^9.2.6",
@ -110,6 +116,7 @@
"typescript": "4.4.4",
"vscode-dotnet-runtime-library": "file:../vscode-dotnet-runtime-library",
"vscode-test": "^1.6.1",
"webpack-permissions-plugin": "^1.0.9",
"yarn": "^1.22.19"
},
"devDependencies": {

Просмотреть файл

@ -4,6 +4,8 @@
const path = require('path');
const CopyPlugin = require('copy-webpack-plugin');
const { exec } = require('node:child_process');
const PermissionsOutputPlugin = require('webpack-permissions-plugin');
/**@type {import('webpack').Configuration}*/
const config = {
@ -50,6 +52,20 @@ const config = {
{ from: path.resolve(__dirname, '../images'), to: path.resolve(__dirname, 'images') },
{ from: path.resolve(__dirname, '../LICENSE.txt'), to: path.resolve(__dirname, 'LICENSE.txt') }
]}),
new PermissionsOutputPlugin({
buildFolders: [
],
buildFiles: [
{
path: path.resolve(__dirname, 'dist', 'distro-data', 'distro-support.json'),
fileMode: '544'
},
{
path: path.resolve(__dirname, 'dist', 'install scripts', 'interprocess-communicator.sh'),
fileMode: '500'
}
]
})
]
};
module.exports = config;

Просмотреть файл

@ -152,7 +152,14 @@
"@types/node" "*"
"@types/responselike" "*"
"@types/chai@^4.3.5":
"@types/chai-as-promised@^7.1.8":
"integrity" "sha1-8rPYLVPFlia11rvAh2Z8y0tnf+k="
"resolved" "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@types/chai-as-promised/-/chai-as-promised-7.1.8.tgz"
"version" "7.1.8"
dependencies:
"@types/chai" "*"
"@types/chai@*", "@types/chai@^4.3.5":
"integrity" "sha1-rmm8uxvrtoxKwLEenY7QRSazVis="
"resolved" "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@types/chai/-/chai-4.3.5.tgz"
"version" "4.3.5"
@ -546,11 +553,16 @@
"buffers" "~0.1.1"
"chainsaw" "~0.1.0"
"bluebird@~3.4.1":
"bluebird@^3.4.7", "bluebird@~3.4.1":
"integrity" "sha1-9y12C+Cbf3bQjtj66Ysomo0F+rM="
"resolved" "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/bluebird/-/bluebird-3.4.7.tgz"
"version" "3.4.7"
"bluebird@^3.7.2":
"integrity" "sha1-nyKcFb4nJFT/qXOs4NvueaGww28="
"resolved" "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/bluebird/-/bluebird-3.7.2.tgz"
"version" "3.7.2"
"brace-expansion@^1.1.7":
"integrity" "sha1-PH/L9SnYcibz0vUrlm/1Jx60Qd0="
"resolved" "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/brace-expansion/-/brace-expansion-1.1.11.tgz"
@ -559,6 +571,13 @@
"balanced-match" "^1.0.0"
"concat-map" "0.0.1"
"brace-expansion@^2.0.1":
"integrity" "sha1-HtxFng8MVISG7Pn8mfIiE2S5oK4="
"resolved" "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/brace-expansion/-/brace-expansion-2.0.1.tgz"
"version" "2.0.1"
dependencies:
"balanced-match" "^1.0.0"
"braces@^3.0.2", "braces@~3.0.2":
"integrity" "sha1-NFThpGLujVmeI23zNs2epPiv4Qc="
"resolved" "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/braces/-/braces-3.0.2.tgz"
@ -655,13 +674,14 @@
"normalize-url" "^6.0.1"
"responselike" "^2.0.0"
"call-bind@^1.0.2":
"integrity" "sha1-sdTonmiBGcPJqQOtMKuy9qkZvjw="
"resolved" "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/call-bind/-/call-bind-1.0.2.tgz"
"version" "1.0.2"
"call-bind@^1.0.2", "call-bind@^1.0.5":
"integrity" "sha1-b6K3hFzg6km/TYue9kcnosLi5RM="
"resolved" "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/call-bind/-/call-bind-1.0.5.tgz"
"version" "1.0.5"
dependencies:
"function-bind" "^1.1.1"
"get-intrinsic" "^1.0.2"
"function-bind" "^1.1.2"
"get-intrinsic" "^1.2.1"
"set-function-length" "^1.1.1"
"camelcase@^6.0.0":
"integrity" "sha1-VoW5XrIJrJwMF3Rnd4ychN9Yupo="
@ -906,6 +926,15 @@
"resolved" "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/defer-to-connect/-/defer-to-connect-2.0.1.tgz"
"version" "2.0.1"
"define-data-property@^1.1.1":
"integrity" "sha1-w1980KsJiDSA0SrFyyE3FVh4ALM="
"resolved" "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/define-data-property/-/define-data-property-1.1.1.tgz"
"version" "1.1.1"
dependencies:
"get-intrinsic" "^1.2.1"
"gopd" "^1.0.1"
"has-property-descriptors" "^1.0.0"
"define-lazy-prop@^2.0.0":
"integrity" "sha1-P3rkIRKbyqrJvHSQXJigAJ7J7n8="
"resolved" "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz"
@ -994,6 +1023,11 @@
"resolved" "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/envinfo/-/envinfo-7.8.1.tgz"
"version" "7.8.1"
"err-code@^1.0.0":
"integrity" "sha1-BuARbTAo9q70gGhJ6w6mp0iuaWA="
"resolved" "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/err-code/-/err-code-1.1.2.tgz"
"version" "1.1.2"
"es-module-lexer@^1.2.1":
"integrity" "sha1-a+nJ4LRUOmDNFm/2+LTp2uCwwW8="
"resolved" "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/es-module-lexer/-/es-module-lexer-1.3.0.tgz"
@ -1064,6 +1098,11 @@
"signal-exit" "^3.0.3"
"strip-final-newline" "^2.0.0"
"extend@^3.0.0":
"integrity" "sha1-+LETa0Bx+9jrFAr/hYsQGewpFfo="
"resolved" "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/extend/-/extend-3.0.2.tgz"
"version" "3.0.2"
"fast-deep-equal@^3.1.1":
"integrity" "sha1-On1WtVnWy8PrUSMlJE5hmmXGxSU="
"resolved" "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz"
@ -1102,6 +1141,27 @@
dependencies:
"reusify" "^1.0.4"
"file-js@0.3.0":
"integrity" "sha1-+rRr94I0bJKUSZ8fDSrQfYOPJdE="
"resolved" "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/file-js/-/file-js-0.3.0.tgz"
"version" "0.3.0"
dependencies:
"bluebird" "^3.4.7"
"minimatch" "^3.0.3"
"proper-lockfile" "^1.2.0"
"filehound@^1.17.6":
"integrity" "sha1-1dh71pQxbqZzvQZCt3a1CNP5ih0="
"resolved" "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/filehound/-/filehound-1.17.6.tgz"
"version" "1.17.6"
dependencies:
"bluebird" "^3.7.2"
"file-js" "0.3.0"
"lodash" "^4.17.21"
"minimatch" "^5.0.0"
"moment" "^2.29.1"
"unit-compare" "^1.0.1"
"fill-range@^7.0.1":
"integrity" "sha1-GRmmp8df44ssfHflGYU12prN2kA="
"resolved" "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/fill-range/-/fill-range-7.0.1.tgz"
@ -1164,10 +1224,10 @@
"mkdirp" ">=0.5 0"
"rimraf" "2"
"function-bind@^1.1.1":
"integrity" "sha1-pWiZ0+o8m6uHS7l3O3xe3pL0iV0="
"resolved" "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/function-bind/-/function-bind-1.1.1.tgz"
"version" "1.1.1"
"function-bind@^1.1.1", "function-bind@^1.1.2":
"integrity" "sha1-LALYZNl/PqbIgwxGTL0Rq26rehw="
"resolved" "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/function-bind/-/function-bind-1.1.2.tgz"
"version" "1.1.2"
"get-caller-file@^2.0.5":
"integrity" "sha1-T5RBKoLbMvNuOwuXQfipf+sDH34="
@ -1179,14 +1239,15 @@
"resolved" "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/get-func-name/-/get-func-name-2.0.0.tgz"
"version" "2.0.0"
"get-intrinsic@^1.0.2", "get-intrinsic@^1.1.3":
"integrity" "sha1-BjyEMprZPoOJPH9PJD72P/o1E4U="
"resolved" "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/get-intrinsic/-/get-intrinsic-1.1.3.tgz"
"version" "1.1.3"
"get-intrinsic@^1.1.3", "get-intrinsic@^1.2.1", "get-intrinsic@^1.2.2":
"integrity" "sha1-KBt2IpcRI+HvSzyQ/XU5MG2pPzs="
"resolved" "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/get-intrinsic/-/get-intrinsic-1.2.2.tgz"
"version" "1.2.2"
dependencies:
"function-bind" "^1.1.1"
"has" "^1.0.3"
"function-bind" "^1.1.2"
"has-proto" "^1.0.1"
"has-symbols" "^1.0.3"
"hasown" "^2.0.0"
"get-stream@^4.1.0":
"integrity" "sha1-wbJVV189wh1Zv8ec09K0axw6VLU="
@ -1274,6 +1335,13 @@
"merge2" "^1.4.1"
"slash" "^3.0.0"
"gopd@^1.0.1":
"integrity" "sha1-Kf923mnax0ibfAkYpXiOVkd8Myw="
"resolved" "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/gopd/-/gopd-1.0.1.tgz"
"version" "1.0.1"
dependencies:
"get-intrinsic" "^1.1.3"
"got@^11.8.0", "got@11.8.5":
"integrity" "sha1-znfQRRNt5W6PAkvruC6jSbxzAEY="
"resolved" "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/got/-/got-11.8.5.tgz"
@ -1345,6 +1413,18 @@
"resolved" "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/has-flag/-/has-flag-4.0.0.tgz"
"version" "4.0.0"
"has-property-descriptors@^1.0.0", "has-property-descriptors@^1.0.1":
"integrity" "sha1-UrowtsXsh/2J+ldLwcORJcb2U0A="
"resolved" "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz"
"version" "1.0.1"
dependencies:
"get-intrinsic" "^1.2.2"
"has-proto@^1.0.1":
"integrity" "sha1-GIXBMFU4lYr/Rp/vN5N8InlUCOA="
"resolved" "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/has-proto/-/has-proto-1.0.1.tgz"
"version" "1.0.1"
"has-symbols@^1.0.2", "has-symbols@^1.0.3":
"integrity" "sha1-u3ssQ0klHc6HsSX3vfh0qnyLOfg="
"resolved" "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/has-symbols/-/has-symbols-1.0.3.tgz"
@ -1372,6 +1452,13 @@
"inherits" "^2.0.3"
"minimalistic-assert" "^1.0.1"
"hasown@^2.0.0":
"integrity" "sha1-9MUT1FSle3x+FlB3jeImsRcAVGw="
"resolved" "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/hasown/-/hasown-2.0.0.tgz"
"version" "2.0.0"
dependencies:
"function-bind" "^1.1.2"
"he@1.2.0":
"integrity" "sha1-hK5l+n6vsWX922FWauFLrwVmTw8="
"resolved" "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/he/-/he-1.2.0.tgz"
@ -1583,6 +1670,11 @@
dependencies:
"is-docker" "^2.0.0"
"isarray@^2.0.5":
"integrity" "sha1-ivHkwSISRMxiRZ+vOJQNTmRKVyM="
"resolved" "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/isarray/-/isarray-2.0.5.tgz"
"version" "2.0.5"
"isarray@~1.0.0":
"integrity" "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
"resolved" "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/isarray/-/isarray-1.0.0.tgz"
@ -1690,6 +1782,11 @@
dependencies:
"p-locate" "^5.0.0"
"lodash@^4.17.21":
"integrity" "sha1-Z5WRxWTDv/quhFTPCz3zcMPWkRw="
"resolved" "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/lodash/-/lodash-4.17.21.tgz"
"version" "4.17.21"
"log-symbols@4.1.0":
"integrity" "sha1-P727lbRoOsn8eFER55LlWNSr1QM="
"resolved" "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/log-symbols/-/log-symbols-4.1.0.tgz"
@ -1785,13 +1882,20 @@
"resolved" "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz"
"version" "1.0.1"
"minimatch@^3.0.4", "minimatch@^3.1.1":
"minimatch@^3.0.3", "minimatch@^3.0.4", "minimatch@^3.1.1":
"integrity" "sha1-Gc0ZS/0+Qo8EmnCBfAONiatL41s="
"resolved" "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/minimatch/-/minimatch-3.1.2.tgz"
"version" "3.1.2"
dependencies:
"brace-expansion" "^1.1.7"
"minimatch@^5.0.0":
"integrity" "sha1-HPy4z1Ui6mmVLNKvla4JR38SKpY="
"resolved" "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/minimatch/-/minimatch-5.1.6.tgz"
"version" "5.1.6"
dependencies:
"brace-expansion" "^2.0.1"
"minimatch@4.2.1":
"integrity" "sha1-QNnVEaRr3E5WPCLDCAzenA2CmbQ="
"resolved" "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/minimatch/-/minimatch-4.2.1.tgz"
@ -1841,6 +1945,11 @@
"yargs-parser" "20.2.4"
"yargs-unparser" "2.0.0"
"moment@^2.14.1", "moment@^2.29.1":
"integrity" "sha1-+MkcB7enhuMMWZJt9TC06slpdK4="
"resolved" "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/moment/-/moment-2.30.1.tgz"
"version" "2.30.1"
"ms@2.1.2":
"integrity" "sha1-0J0fNXtEP0kzgqjrPM0YOHKuYAk="
"resolved" "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/ms/-/ms-2.1.2.tgz"
@ -2054,6 +2163,16 @@
"resolved" "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/process-nextick-args/-/process-nextick-args-2.0.1.tgz"
"version" "2.0.1"
"proper-lockfile@^1.2.0":
"integrity" "sha1-zv9d2J0+XxD7deHo52vHWAGlnDQ="
"resolved" "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/proper-lockfile/-/proper-lockfile-1.2.0.tgz"
"version" "1.2.0"
dependencies:
"err-code" "^1.0.0"
"extend" "^3.0.0"
"graceful-fs" "^4.1.2"
"retry" "^0.10.0"
"proxy-from-env@^1.1.0":
"integrity" "sha1-4QLxbKNVQkhldV0sno6k8k1Yw+I="
"resolved" "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/proxy-from-env/-/proxy-from-env-1.1.0.tgz"
@ -2198,6 +2317,11 @@
dependencies:
"lowercase-keys" "^3.0.0"
"retry@^0.10.0":
"integrity" "sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q="
"resolved" "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/retry/-/retry-0.10.1.tgz"
"version" "0.10.1"
"reusify@^1.0.4":
"integrity" "sha1-kNo4Kx4SbvwCFG6QhFqI2xKSXXY="
"resolved" "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/reusify/-/reusify-1.0.4.tgz"
@ -2224,6 +2348,16 @@
dependencies:
"queue-microtask" "^1.2.2"
"safe-array-concat@^1.1.0":
"integrity" "sha1-jQyunLgG1tHAbgirE9hHKT6+BpI="
"resolved" "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/safe-array-concat/-/safe-array-concat-1.1.0.tgz"
"version" "1.1.0"
dependencies:
"call-bind" "^1.0.5"
"get-intrinsic" "^1.2.2"
"has-symbols" "^1.0.3"
"isarray" "^2.0.5"
"safe-buffer@^5.1.0":
"integrity" "sha1-Hq+fqb2x/dTsdfWPnNtOa3gn7sY="
"resolved" "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/safe-buffer/-/safe-buffer-5.2.1.tgz"
@ -2283,6 +2417,17 @@
dependencies:
"randombytes" "^2.1.0"
"set-function-length@^1.1.1":
"integrity" "sha1-L4HcbBbHBZvaWrfILBHwOlFe2OE="
"resolved" "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/set-function-length/-/set-function-length-1.2.0.tgz"
"version" "1.2.0"
dependencies:
"define-data-property" "^1.1.1"
"function-bind" "^1.1.2"
"get-intrinsic" "^1.2.2"
"gopd" "^1.0.1"
"has-property-descriptors" "^1.0.1"
"setimmediate@~1.0.4":
"integrity" "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU="
"resolved" "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/setimmediate/-/setimmediate-1.0.5.tgz"
@ -2497,6 +2642,13 @@
"resolved" "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/typescript/-/typescript-4.4.4.tgz"
"version" "4.4.4"
"unit-compare@^1.0.1":
"integrity" "sha1-DHRZ8OW/U2N+qHPKPO4Y3i7so4Y="
"resolved" "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/unit-compare/-/unit-compare-1.0.1.tgz"
"version" "1.0.1"
dependencies:
"moment" "^2.14.1"
"unzipper@^0.10.11":
"integrity" "sha1-C0mRRGRyy9uS7nQDkJ8mwkGceC4="
"resolved" "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/unzipper/-/unzipper-0.10.11.tgz"
@ -2625,6 +2777,13 @@
"clone-deep" "^4.0.1"
"wildcard" "^2.0.0"
"webpack-permissions-plugin@^1.0.9":
"integrity" "sha1-gK5aCe0ZkdvbL5/kYYuNVxlhbh4="
"resolved" "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/webpack-permissions-plugin/-/webpack-permissions-plugin-1.0.9.tgz"
"version" "1.0.9"
dependencies:
"filehound" "^1.17.6"
"webpack-sources@^3.2.3":
"integrity" "sha1-LU2quEUf1LJAzCcFX/agwszqDN4="
"resolved" "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/webpack-sources/-/webpack-sources-3.2.3.tgz"

Просмотреть файл

@ -40,7 +40,7 @@
{
"runUnderSudo": false,
"commandRoot": "apt-cache",
"commandParts": ["search", "{packageName}"]
"commandParts": ["search", "--names-only", "^{packageName}$"]
}
],
"isInstalledCommand":
@ -132,6 +132,30 @@
[
"aspnetcore-runtime-7.0"
]
},
{
"version": "8.0",
"sdk": [
"dotnet-sdk-8.0"
],
"runtime": [
"dotnet-runtime-8.0"
],
"aspnetcore": [
"aspnetcore-runtime-8.0"
]
},
{
"version": "9.0",
"sdk": [
"dotnet-sdk-9.0"
],
"runtime": [
"dotnet-runtime-9.0"
],
"aspnetcore": [
"aspnetcore-runtime-9.0"
]
}
],
"versions": [{
@ -333,6 +357,30 @@
"aspnetcore": [
"aspnetcore-runtime-7.0"
]
},
{
"version": "8.0",
"sdk": [
"dotnet-sdk-8.0"
],
"runtime": [
"dotnet-runtime-8.0"
],
"aspnetcore": [
"aspnetcore-runtime-8.0"
]
},
{
"version": "9.0",
"sdk": [
"dotnet-sdk-9.0"
],
"runtime": [
"dotnet-runtime-9.0"
],
"aspnetcore": [
"aspnetcore-runtime-9.0"
]
}
],
"versions": [

Просмотреть файл

@ -0,0 +1,45 @@
#!/usr/bin/env bash
EXECFOLDER=$1 # First argument is the working folder as this is launched with cwd of /root
OKSIGNALFILE="$EXECFOLDER/ok.txt"
COMMANDTORUNFILE="$EXECFOLDER/command.txt"
#OUTPUTFILE="/home/test_output_.txt"
end=$((SECONDS+3600))
function finish {
rm "$COMMANDTORUNFILE"
rm "$OKSIGNALFILE"
}
trap finish EXIT
while true
do
stop=false
while [ $SECONDS -lt $end ];
do
if test -f "$COMMANDTORUNFILE"; then
# echo "COMMAND FILE FOUND" >> "$OUTPUTFILE" # Leave this here as an example of debugging
COMMAND="$(cat "$COMMANDTORUNFILE" | awk '{$1=$1;print}')"
for validCmd in "${@:2}"
do
if [ "$COMMAND" == "$validCmd" ]; then
# Eventually we should split the cmd file to be line by line instead of space separated,
# but it works for now because the commands are running under sudo
IFS=' ' read -ra COMMANDARGS <<< "$COMMAND"
fi
done
if [ -z "$COMMANDARGS" ]; then
rm "$COMMANDTORUNFILE"
exit 111777 # Special exit code - arbitrarily picked for when the command is not expected
fi
sudo "${COMMANDARGS[@]}" 2> "$EXECFOLDER/stderr.txt" 1> "$EXECFOLDER/stdout.txt"
STATUSCODE=$?
echo $STATUSCODE > "$EXECFOLDER/status.txt"
rm "$COMMANDTORUNFILE"
touch "$EXECFOLDER/output.txt"
fi
if test -f "$OKSIGNALFILE"; then
rm "$OKSIGNALFILE"
fi
sleep 5
done
done

Просмотреть файл

@ -182,7 +182,7 @@ export class GenericDistroSDKProvider extends IDistroDotnetSDKProvider
}
else
{
const availableVersions = await this.myVersionPackages(installType);
const availableVersions = await this.myVersionPackages(installType, this.isMidFeedInjection);
const simplifiedVersion = this.JsonDotnetVersion(fullySpecifiedVersion);
for(const dotnetPackages of availableVersions)
@ -200,7 +200,7 @@ export class GenericDistroSDKProvider extends IDistroDotnetSDKProvider
public async getRecommendedDotnetVersion(installType : LinuxInstallType) : Promise<string>
{
let maxVersion = '0';
const json = await this.myVersionPackages(installType);
const json = await this.myVersionPackages(installType, this.isMidFeedInjection);
for(const dotnetPackages of json)
{
if(Number(dotnetPackages.version) > Number(maxVersion))
@ -218,7 +218,7 @@ export class GenericDistroSDKProvider extends IDistroDotnetSDKProvider
return this.versionResolver.getMajorMinor(fullySpecifiedDotnetVersion);
}
protected isPackageFoundInSearch(resultOfSearchCommand: any): boolean {
return resultOfSearchCommand !== '';
protected isPackageFoundInSearch(resultOfSearchCommand: any, searchCommandExitCode : string): boolean {
return resultOfSearchCommand.trim() !== '' && searchCommandExitCode === '0';
}
}

Просмотреть файл

@ -4,15 +4,13 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import * as fs from 'fs';
import * as os from 'os';
import path = require('path');
import { DistroVersionPair, DotnetDistroSupportStatus } from './LinuxVersionResolver';
import { DotnetAcquisitionDistroUnknownError, DotnetVersionResolutionError } from '../EventStream/EventStreamEvents';
import { DotnetAcquisitionDistroUnknownError, DotnetVersionResolutionError, SuppressedAcquisitionError } from '../EventStream/EventStreamEvents';
import { VersionResolver } from './VersionResolver';
import { CommandExecutorCommand } from '../Utils/CommandExecutorCommand';
import { DotnetCoreAcquisitionWorker } from './DotnetCoreAcquisitionWorker';
import { CommandExecutor } from '../Utils/CommandExecutor';
import { LinuxInstallType } from './LinuxInstallType';
import { LinuxPackageCollection } from './LinuxPackageCollection';
@ -62,14 +60,24 @@ export abstract class IDistroDotnetSDKProvider {
protected runtimeKey = 'runtime';
protected aspNetKey = 'aspnetcore';
protected isMidFeedInjection = false;
protected cachedMyVersionPacakges : any = null;
constructor(distroVersion : DistroVersionPair, context : IAcquisitionWorkerContext, utilContext : IUtilityContext, executor : ICommandExecutor | null = null)
{
this.commandRunner = executor ?? new CommandExecutor(context, utilContext);
this.context = context;
this.distroVersion = distroVersion;
this.versionResolver = new VersionResolver(context);
// Hard-code to the upper path (lib/dist/acquisition) from __dirname to the lib folder, as webpack-copy doesn't seem to copy the distro-support.json
const distroDataFile = path.join(__dirname, 'distro-data', `distro-support.json`);
try
{
fs.chmodSync(distroDataFile, 0o544);
}
catch(error : any)
{
this.context.eventStream.post(new SuppressedAcquisitionError(error, `Failed to chmod +x on .NET folder ${distroDataFile} when marked for deletion.`));
}
this.distroJson = JSON.parse(fs.readFileSync(distroDataFile, 'utf8'));
if(!distroVersion || !this.distroJson || !((this.distroJson as any)[this.distroVersion.distro]))
{
@ -77,6 +85,9 @@ export abstract class IDistroDotnetSDKProvider {
getInstallKeyFromContext(this.context.acquisitionContext));
throw error.error;
}
const validCommandSet = this.getAllValidCommands();
this.commandRunner = executor ?? new CommandExecutor(context, utilContext, validCommandSet);
}
/**
@ -176,6 +187,11 @@ export abstract class IDistroDotnetSDKProvider {
protected async myVersionPackages(installType : LinuxInstallType, haveTriedFeedInjectionAlready = false) : Promise<LinuxPackageCollection[]>
{
if(this.cachedMyVersionPacakges)
{
return this.cachedMyVersionPacakges;
}
const availableVersions : LinuxPackageCollection[] = [];
const potentialDotnetPackageNames = this.distroJson[this.distroVersion.distro][this.distroPackagesKey];
@ -191,8 +207,15 @@ export abstract class IDistroDotnetSDKProvider {
{
let command = this.myDistroCommands(this.searchCommandKey);
command = CommandExecutor.replaceSubstringsInCommands(command, this.missingPackageNameKey, packageName);
const packageIsAvailableResult = (await this.commandRunner.executeMultipleCommands(command))[0];
const packageExists = this.isPackageFoundInSearch(packageIsAvailableResult);
const packageIsAvailableResult = (await this.commandRunner.executeMultipleCommands(command))[0].trim();
const oldReturnStatusSetting = this.commandRunner.returnStatus;
this.commandRunner.returnStatus = true;
const packageAvailableExitCode = (await this.commandRunner.executeMultipleCommands(command))[0].trim();
this.commandRunner.returnStatus = oldReturnStatusSetting;
const packageExists = this.isPackageFoundInSearch(packageIsAvailableResult, packageAvailableExitCode);
if(packageExists)
{
thisVersionPackage.packages.push(packageName);
@ -212,13 +235,24 @@ export abstract class IDistroDotnetSDKProvider {
const fakeVersionToCheckMicrosoftSupportStatus = '6.0.1xx';
await this.injectPMCFeed(fakeVersionToCheckMicrosoftSupportStatus, installType);
return this.myVersionPackages(installType, true);
this.cachedMyVersionPacakges = this.myVersionPackages(installType, true);
}
return availableVersions;
else
{
this.cachedMyVersionPacakges = availableVersions;
}
return this.cachedMyVersionPacakges;
}
protected async injectPMCFeed(fullySpecifiedVersion : string, installType : LinuxInstallType)
{
if(this.isMidFeedInjection)
{
return;
}
this.isMidFeedInjection = true;
const supportStatus = await this.getDotnetVersionSupportStatus(fullySpecifiedVersion, installType);
if(supportStatus === DotnetDistroSupportStatus.Microsoft)
{
@ -226,6 +260,8 @@ export abstract class IDistroDotnetSDKProvider {
const preInstallCommands = myVersionDetails[this.preinstallCommandKey] as CommandExecutorCommand[];
await this.commandRunner.executeMultipleCommands(preInstallCommands);
}
this.isMidFeedInjection = false;
}
protected myVersionDetails() : any
@ -269,9 +305,53 @@ export abstract class IDistroDotnetSDKProvider {
return this.distroJson[this.distroVersion.distro][commandKey] as CommandExecutorCommand[];
}
protected getAllValidCommands() : string[]
{
const validCommands : string[] = [];
const baseCommands = (Object.values(this.distroJson[this.distroVersion.distro])
.filter((x : any) => x && Array.isArray(x) && ((x[0] as CommandExecutorCommand).commandParts))).flat();
let preInstallCommands = this.myVersionDetails()[this.preinstallCommandKey] as CommandExecutorCommand[];
if(!preInstallCommands)
{
preInstallCommands = [];
}
const sudoCommands = (baseCommands as CommandExecutorCommand[]).concat(preInstallCommands).filter(x => x.runUnderSudo);
for(const command of sudoCommands)
{
if(command.commandParts.slice(-1)[0] !== this.missingPackageNameKey)
{
validCommands.push(`"${CommandExecutor.prettifyCommandExecutorCommand(command, false)}"`);
}
else
{
for(const packageName of this.allPackages())
{
const newCommand = CommandExecutor.replaceSubstringsInCommands([command], this.missingPackageNameKey, packageName)[0];
validCommands.push(`"${CommandExecutor.prettifyCommandExecutorCommand(newCommand, false)}"`);
}
}
}
return [...new Set(validCommands)];
}
protected allPackages() : string[]
{
let allPackages : string[] = [];
const distroPackages = this.distroJson[this.distroVersion.distro][this.distroPackagesKey];
for(const packageSet of distroPackages)
{
allPackages = allPackages.concat(packageSet[this.sdkKey]);
allPackages = allPackages.concat(packageSet[this.runtimeKey])
allPackages = allPackages.concat(packageSet[this.aspNetKey])
}
return allPackages;
}
protected async myDotnetVersionPackageName(fullySpecifiedDotnetVersion : string, installType : LinuxInstallType) : Promise<string>
{
const myDotnetVersions = await this.myVersionPackages(installType);
const myDotnetVersions = await this.myVersionPackages(installType, this.isMidFeedInjection);
for(const dotnetPackage of myDotnetVersions)
{
if(dotnetPackage.version === this.JsonDotnetVersion(fullySpecifiedDotnetVersion))
@ -280,10 +360,10 @@ export abstract class IDistroDotnetSDKProvider {
return dotnetPackage.packages[0];
}
}
const err = new Error(`Could not find a .NET package for version ${fullySpecifiedDotnetVersion}. Found only: ${JSON.stringify(await this.myVersionPackages(installType))}`);
const err = new Error(`Could not find a .NET package for version ${fullySpecifiedDotnetVersion}. Found only: ${JSON.stringify(myDotnetVersions)}`);
this.context.eventStream.post(new DotnetVersionResolutionError(err, getInstallKeyFromContext(this.context.acquisitionContext)));
throw err;
}
protected abstract isPackageFoundInSearch(resultOfSearchCommand : any) : boolean;
protected abstract isPackageFoundInSearch(resultOfSearchCommand : any, searchCommandExitCode : string) : boolean;
}

Просмотреть файл

@ -43,7 +43,7 @@ export class InstallScriptAcquisitionWorker implements IInstallScriptAcquisition
throw new Error('Unable to get script path.');
}
await this.fileUtilities.writeFileOntoDisk(script, this.scriptFilePath, this.context.eventStream);
await this.fileUtilities.writeFileOntoDisk(script, this.scriptFilePath, false, this.context.eventStream);
this.context.eventStream.post(new DotnetInstallScriptAcquisitionCompleted());
return this.scriptFilePath;
}

Просмотреть файл

@ -187,6 +187,18 @@ export class DotnetPreinstallDetectionError extends DotnetAcquisitionError {
public readonly eventName = 'DotnetPreinstallDetectionError';
}
export class TimeoutSudoProcessSpawnerError extends DotnetAcquisitionError {
public readonly eventName = 'TimeoutSudoProcessSpawnerError';
}
export class TimeoutSudoCommandExecutionError extends DotnetAcquisitionError {
public readonly eventName = 'TimeoutSudoCommandExecutionError';
}
export class CommandExecutionNonZeroExitFailure extends DotnetAcquisitionError {
public readonly eventName = 'CommandExecutionNonZeroExitFailure';
}
export class DotnetNotInstallRelatedCommandFailed extends DotnetNonAcquisitionError {
public readonly eventName = 'DotnetNotInstallRelatedCommandFailed';
@ -488,6 +500,18 @@ export class DotnetGlobalVersionResolutionCompletionEvent extends DotnetCustomMe
public readonly eventName = 'DotnetGlobalVersionResolutionCompletionEvent';
}
export class CommandProcessesExecutionFailureNonTerminal extends DotnetCustomMessageEvent {
public readonly eventName = 'CommandProcessesExecutionFailureNonTerminal';
}
export class CommandProcessorExecutionBegin extends DotnetCustomMessageEvent {
public readonly eventName = 'CommandProcessorExecutionBegin';
}
export class CommandProcessorExecutionEnd extends DotnetCustomMessageEvent {
public readonly eventName = 'CommandProcessorExecutionEnd';
}
export class DotnetBeginGlobalInstallerExecution extends DotnetCustomMessageEvent {
public readonly eventName = 'DotnetBeginGlobalInstallerExecution';
}
@ -547,6 +571,26 @@ export class CommandExecutionEvent extends DotnetCustomMessageEvent {
public readonly eventName = 'CommandExecutionEvent';
}
export class SudoProcAliveCheckBegin extends DotnetCustomMessageEvent {
public readonly eventName = 'SudoProcAliveCheckBegin';
}
export class SudoProcAliveCheckEnd extends DotnetCustomMessageEvent {
public readonly eventName = 'SudoProcAliveCheckEnd';
}
export class SudoProcCommandExchangeBegin extends DotnetCustomMessageEvent {
public readonly eventName = 'SudoProcCommandExchangeBegin';
}
export class SudoProcCommandExchangePing extends DotnetCustomMessageEvent {
public readonly eventName = 'SudoProcCommandExchangePing';
}
export class SudoProcCommandExchangeEnd extends DotnetCustomMessageEvent {
public readonly eventName = 'SudoProcCommandExchangeEnd';
}
export class CommandExecutionUserAskDialogueEvent extends DotnetCustomMessageEvent {
public readonly eventName = 'CommandExecutionUserAskDialogueEvent';
}
@ -563,6 +607,10 @@ export class CommandExecutionUserRejectedPasswordRequest extends DotnetInstallEx
public readonly eventName = 'CommandExecutionUserRejectedPasswordRequest';
}
export class CommandExecutionUnknownCommandExecutionAttempt extends DotnetInstallExpectedAbort {
public readonly eventName = 'CommandExecutionUnknownCommandExecutionAttempt';
}
export class DotnetVersionParseEvent extends DotnetCustomMessageEvent {
public readonly eventName = 'DotnetVersionParseEvent';
}

Просмотреть файл

@ -12,20 +12,34 @@ import path = require('path');
import {
CommandExecutionEvent,
CommandExecutionNoStatusCodeWarning,
CommandExecutionNonZeroExitFailure,
CommandExecutionSignalSentEvent,
CommandExecutionStatusEvent,
CommandExecutionStdError,
CommandExecutionStdOut,
CommandExecutionUnderSudoEvent,
CommandExecutionUnknownCommandExecutionAttempt,
CommandExecutionUserAskDialogueEvent,
CommandExecutionUserCompletedDialogueEvent,
CommandExecutionUserRejectedPasswordRequest,
CommandProcessesExecutionFailureNonTerminal,
CommandProcessorExecutionBegin,
CommandProcessorExecutionEnd,
DotnetAlternativeCommandFoundEvent,
DotnetCommandNotFoundEvent,
DotnetWSLSecurityError
DotnetLockAcquiredEvent,
DotnetLockReleasedEvent,
DotnetWSLSecurityError,
SudoProcAliveCheckBegin,
SudoProcAliveCheckEnd,
SudoProcCommandExchangeBegin,
SudoProcCommandExchangeEnd,
SudoProcCommandExchangePing,
TimeoutSudoCommandExecutionError,
TimeoutSudoProcessSpawnerError
} from '../EventStream/EventStreamEvents';
import {exec} from '@vscode/sudo-prompt';
import * as lockfile from 'proper-lockfile';
import { CommandExecutorCommand } from './CommandExecutorCommand';
import { getInstallKeyFromContext } from '../Utils/InstallKeyGenerator';
@ -35,16 +49,25 @@ import { IUtilityContext } from './IUtilityContext';
import { IVSCodeExtensionContext } from '../IVSCodeExtensionContext';
import { IWindowDisplayWorker } from '../EventStream/IWindowDisplayWorker';
import { IAcquisitionWorkerContext } from '../Acquisition/IAcquisitionWorkerContext';
import { FileUtilities } from './FileUtilities';
import { IFileUtilities } from './IFileUtilities';
import { CommandProcessorOutput } from './CommandProcessorOutput';
import { setTimeout } from 'timers';
/* tslint:disable:no-any */
/* tslint:disable:no-string-literal */
export class CommandExecutor extends ICommandExecutor
{
private pathTroubleshootingOption = 'Troubleshoot';
private sudoProcessCommunicationDir = path.join(__dirname, 'install scripts');
private fileUtil : IFileUtilities;
private hasEverLaunchedSudoFork = false;
constructor(context : IAcquisitionWorkerContext | null, utilContext : IUtilityContext)
constructor(context : IAcquisitionWorkerContext | null, utilContext : IUtilityContext, protected readonly validSudoCommands? : string[])
{
super(context, utilContext);
this.fileUtil = new FileUtilities();
}
/**
@ -69,6 +92,7 @@ export class CommandExecutor extends ICommandExecutor
{
const fullCommandString = CommandExecutor.prettifyCommandExecutorCommand(command, false);
this.context?.eventStream.post(new CommandExecutionUnderSudoEvent(`The command ${fullCommandString} is being ran under sudo.`));
const shellScript = path.join(this.sudoProcessCommunicationDir, 'interprocess-communicator.sh');
if(this.isRunningUnderWSL())
{
@ -84,62 +108,285 @@ Please install the .NET SDK manually by following https://learn.microsoft.com/en
throw err.error;
}
// We wrap the exec in a promise because there is no synchronous version of the sudo exec command for vscode/sudo
return new Promise<string>((resolve, reject) =>
const oldReturnStatusSetting = this.returnStatus;
this.returnStatus = true;
const masterSudoProcessSpawnResult = this.startupSudoProc(fullCommandString, shellScript, terminalFailure);
this.returnStatus = oldReturnStatusSetting;
await this.sudoProcIsLive(terminalFailure);
return this.executeSudoViaProcessCommunication(fullCommandString, terminalFailure);
}
/**
*
* @param fullCommandString the command that will be run by the master process once it is spawned, not super relevant here, used for logging.
* @param shellScriptPath the path of the shell script file for the process to run that should loop and follow the protocol procedure
* @param terminalFailure whether if we cannot start the sudo process, should we fail the entire program.
* @returns The string result of either trying to spawn the sudo master process, or the status code of that attempt depending on the return mode.
*/
private async startupSudoProc(fullCommandString : string, shellScriptPath : string, terminalFailure : boolean) : Promise<string>
{
if(this.hasEverLaunchedSudoFork)
{
// The '.' character is not allowed for sudo-prompt so we use 'NET'
let sanitizedCallerName = this.context?.acquisitionContext?.requestingExtensionId?.replace(/[^0-9a-z]/gi, ''); // Remove non-alphanumerics per OS requirements
sanitizedCallerName = sanitizedCallerName?.substring(0, 69); // 70 Characters is the maximum limit we can use for the prompt.
const options = { name: `${sanitizedCallerName ?? '.NET Install Tool'}` };
this.context?.eventStream.post(new CommandExecutionUserAskDialogueEvent(`Prompting user for command ${fullCommandString} under sudo.`));
exec((fullCommandString), options, (error?: any, stdout?: any, stderr?: any) =>
if(await this.sudoProcIsLive(false))
{
let commandResultString = '';
return Promise.resolve('0');
}
}
this.hasEverLaunchedSudoFork = true;
if (stdout)
{
this.context?.eventStream.post(new CommandExecutionStdOut(`The command ${fullCommandString} encountered stdout, continuing
// Launch the process under sudo
this.context?.eventStream.post(new CommandExecutionUserAskDialogueEvent(`Prompting user for command ${fullCommandString} under sudo.`));
// The '.' character is not allowed for sudo-prompt so we use 'NET'
let sanitizedCallerName = this.context?.acquisitionContext?.requestingExtensionId?.replace(/[^0-9a-z]/gi, ''); // Remove non-alphanumerics per OS requirements
sanitizedCallerName = sanitizedCallerName?.substring(0, 69); // 70 Characters is the maximum limit we can use for the prompt.
const options = { name: `${sanitizedCallerName ?? 'NET Install Tool'}` };
fs.chmodSync(shellScriptPath, 0o500);
exec((`"${shellScriptPath}" "${this.sudoProcessCommunicationDir}" ${this.validSudoCommands?.join(' ')} &`), options, (error?: any, stdout?: any, stderr?: any) =>
{
let commandResultString = '';
if (stdout)
{
this.context?.eventStream.post(new CommandExecutionStdOut(`The process spawn: ${fullCommandString} encountered stdout, continuing
${stdout}`));
commandResultString += stdout;
}
if (stderr)
{
this.context?.eventStream.post(new CommandExecutionStdError(`The command ${fullCommandString} encountered stderr, continuing
commandResultString += stdout;
}
if (stderr)
{
this.context?.eventStream.post(new CommandExecutionStdError(`The process spawn: ${fullCommandString} encountered stderr, continuing
${stderr}`));
commandResultString += stderr;
}
commandResultString += stderr;
}
if (error)
if (error)
{
this.context?.eventStream.post(new CommandExecutionUserCompletedDialogueEvent(`The process spawn: ${fullCommandString} failed to run under sudo.`));
if(terminalFailure)
{
this.context?.eventStream.post(new CommandExecutionUserCompletedDialogueEvent(`The command ${fullCommandString} failed to run under sudo.`));
if(terminalFailure)
if(error.code === 126)
{
if(error.code === 126)
{
const err = new CommandExecutionUserRejectedPasswordRequest(new Error(`Cancelling .NET Install, as command ${fullCommandString} failed.
const cancelledErr = new CommandExecutionUserRejectedPasswordRequest(new Error(`Cancelling .NET Install, as command ${fullCommandString} failed.
The user refused the password prompt.`),
getInstallKeyFromContext(this.context?.acquisitionContext!));
this.context?.eventStream.post(err);
reject(err.error);
}
reject(error);
getInstallKeyFromContext(this.context?.acquisitionContext!));
this.context?.eventStream.post(cancelledErr);
return Promise.reject(cancelledErr.error);
}
else
else if(error.code === 111777)
{
resolve(this.returnStatus ? '1' : stderr);
const securityErr = new CommandExecutionUnknownCommandExecutionAttempt(new Error(`Cancelling .NET Install, as command ${fullCommandString} is UNKNOWN.
Please report this at https://github.com/dotnet/vscode-dotnet-runtime/issues.`),
getInstallKeyFromContext(this.context?.acquisitionContext!));
this.context?.eventStream.post(securityErr);
return Promise.reject(securityErr.error);
}
return Promise.reject(error);
}
else
{
this.context?.eventStream.post(new CommandExecutionUserCompletedDialogueEvent(`The command ${fullCommandString} successfully ran under sudo.`));
resolve(this.returnStatus ? '0' : commandResultString);
return Promise.resolve(this.returnStatus ? '1' : stderr);
}
}
else
{
this.context?.eventStream.post(new CommandExecutionUserCompletedDialogueEvent(`The process spawn: ${fullCommandString} successfully ran under sudo.`));
return Promise.resolve(this.returnStatus ? '0' : commandResultString);
}
});
return Promise.resolve('0');
}
/**
*
* @param errorIfDead set this to true if we should terminally fail if the master process is not yet alive
* @returns a boolean, true if the master process is live, false otherwise
*/
private async sudoProcIsLive(errorIfDead : boolean) : Promise<boolean>
{
let isLive = false;
const processAliveOkSentinelFile = path.join(this.sudoProcessCommunicationDir, 'ok.txt');
const fakeLockFile = path.join(this.sudoProcessCommunicationDir, 'fakeLockFile'); // We need a file to lock the directory in the API besides the dir lock file
await this.fileUtil.writeFileOntoDisk('', fakeLockFile, false, this.context?.eventStream!);
// Prepare to lock directory
const directoryLock = 'dir.lock';
const directoryLockPath = path.join(path.dirname(processAliveOkSentinelFile), directoryLock);
// Lock the directory -- this is not a system wide lock, only a library lock we must respect in the code.
// This will allow the process to still edit the directory, but not our extension API calls from overlapping with one another.
await lockfile.lock(fakeLockFile, { lockfilePath: directoryLockPath, retries: { retries: 10, maxTimeout: 1000 } } )
.then(async (release: () => void) =>
{
this.context?.eventStream.post(new DotnetLockAcquiredEvent(`Lock Acquired.`, new Date().toISOString(), directoryLockPath, fakeLockFile));
await this.fileUtil.wipeDirectory(this.sudoProcessCommunicationDir, this.context?.eventStream, ['.txt']);
await this.fileUtil.writeFileOntoDisk('', processAliveOkSentinelFile, true, this.context?.eventStream);
this.context?.eventStream.post(new SudoProcAliveCheckBegin(`Looking for Sudo Process Master, wrote OK file. ${new Date().toISOString()}`));
const waitTime = this.context?.timeoutSeconds ? ((this.context?.timeoutSeconds/3) * 1000) : 180000;
await this.loopWithTimeoutOnCond(100, waitTime,
function processRespondedByDeletingOkFile() : boolean { return !fs.existsSync(processAliveOkSentinelFile) },
function setProcessIsAlive() : void { isLive = true; }
)
.catch(error =>
{
// Let the rejected promise get handled below
});
this.context?.eventStream.post(new DotnetLockReleasedEvent(`Lock about to be released.`, new Date().toISOString(), directoryLockPath, fakeLockFile));
return release();
});
this.context?.eventStream.post(new SudoProcAliveCheckEnd(`Finished Sudo Process Master: Is Alive? ${isLive}. ${new Date().toISOString()}`));
if(!isLive && errorIfDead)
{
const err = new TimeoutSudoProcessSpawnerError(new Error(`We are unable to spawn the process to run commands under sudo for installing .NET.
Process Directory: ${this.sudoProcessCommunicationDir} failed with error mode: ${errorIfDead}.
It had previously spawned: ${this.hasEverLaunchedSudoFork}.`), getInstallKeyFromContext(this.context?.acquisitionContext));
this.context?.eventStream.post(err);
throw err.error;
}
return isLive;
}
private async loopWithTimeoutOnCond(sampleRatePerMs : number, durationToWaitBeforeTimeoutMs : number, conditionToStop : () => boolean, doAfterStop : () => void )
{
return new Promise(async (resolve, reject) =>
{
for (let i = 0; i < (durationToWaitBeforeTimeoutMs / sampleRatePerMs); i++)
{
if(conditionToStop())
{
doAfterStop();
return resolve('The promise succeeded.');
}
this.context?.eventStream.post(new SudoProcCommandExchangePing(`Ping : Waiting. ${new Date().toISOString()}`));
await new Promise(waitAndResolve => setTimeout(waitAndResolve, sampleRatePerMs));
}
return reject('The promise timed out.');
});
}
public async executeMultipleCommands(commands: CommandExecutorCommand[], options?: any, terminalFailure = true): Promise<string[]> {
/**
*
* @param commandToExecuteString The command to tell the sudo'd master process to execute. It must be live.
* @param terminalFailure Whether to fail if we never get a response from the sudo process.
* @param failOnNonZeroExit Whether to fail if we get an exit code from the command besides 0.
* @returns The output string of the command, or the string status code, depending on the mode of execution.
*/
private async executeSudoViaProcessCommunication(commandToExecuteString : string, terminalFailure : boolean, failOnNonZeroExit = true) : Promise<string>
{
let commandOutputJson : CommandProcessorOutput | null = null;
let statusCode = '1220'; // Special failure code for if code is never set error
let commandResultString = '';
const commandFile = path.join(this.sudoProcessCommunicationDir, 'command.txt');
const stderrFile = path.join(this.sudoProcessCommunicationDir, 'stderr.txt');
const stdoutFile = path.join(this.sudoProcessCommunicationDir, 'stdout.txt');
const statusFile = path.join(this.sudoProcessCommunicationDir, 'status.txt');
const outputFile = path.join(this.sudoProcessCommunicationDir, 'output.txt');
const fakeLockFile = path.join(this.sudoProcessCommunicationDir, 'fakeLockFile'); // We need a file to lock the directory in the API besides the dir lock file
await this.fileUtil.writeFileOntoDisk('', fakeLockFile, false, this.context?.eventStream!);
// Prepare to lock directory
const directoryLock = 'dir.lock';
const directoryLockPath = path.join(path.dirname(commandFile), directoryLock);
// Lock the directory -- this is not a system wide lock, only a library lock we must respect in the code.
// This will allow the process to still edit the directory, but not our extension API calls from overlapping with one another.
await lockfile.lock(fakeLockFile, { lockfilePath: directoryLockPath, retries: { retries: 10, maxTimeout: 1000 } } )
.then(async (release: () => any) =>
{
this.context?.eventStream.post(new DotnetLockAcquiredEvent(`Lock Acquired.`, new Date().toISOString(), directoryLockPath, fakeLockFile));
await this.fileUtil.wipeDirectory(this.sudoProcessCommunicationDir, this.context?.eventStream, ['.txt', '.json']);
await this.fileUtil.writeFileOntoDisk(`${commandToExecuteString}`, commandFile, true, this.context?.eventStream!);
this.context?.eventStream.post(new SudoProcCommandExchangeBegin(`Handing command off to master process. ${new Date().toISOString()}`));
this.context?.eventStream.post(new CommandProcessorExecutionBegin(`The command ${commandToExecuteString} was forwarded to the master process to run.`));
const waitTime = this.context?.timeoutSeconds ? (this.context?.timeoutSeconds * 1000) : 600000;
await this.loopWithTimeoutOnCond(100, waitTime,
function ProcessFinishedExecutingAndWroteOutput() : boolean { return fs.existsSync(outputFile) },
function doNothing() : void { ; }
)
.catch(error =>
{
// Let the rejected promise get handled below
});
commandOutputJson = {
stdout : (fs.readFileSync(stdoutFile, 'utf8')).trim(),
stderr : (fs.readFileSync(stderrFile, 'utf8')).trim(),
status : (fs.readFileSync(statusFile, 'utf8')).trim()
} as CommandProcessorOutput;
this.context?.eventStream.post(new DotnetLockReleasedEvent(`Lock about to be released.`, new Date().toISOString(), directoryLockPath, fakeLockFile));
await this.fileUtil.wipeDirectory(this.sudoProcessCommunicationDir, this.context?.eventStream, ['.txt']);
return release();
});
this.context?.eventStream.post(new SudoProcCommandExchangeEnd(`Finished or timed out with master process. ${new Date().toISOString()}`));
if(!commandOutputJson && terminalFailure)
{
const err = new TimeoutSudoCommandExecutionError(new Error(`Timeout: The master process with command ${commandToExecuteString} never finished executing.
Process Directory: ${this.sudoProcessCommunicationDir} failed with error mode: ${terminalFailure}.
It had previously spawned: ${this.hasEverLaunchedSudoFork}.`), getInstallKeyFromContext(this.context?.acquisitionContext));
this.context?.eventStream.post(err);
throw err.error;
}
else if(!commandOutputJson)
{
this.context?.eventStream.post(new CommandProcessesExecutionFailureNonTerminal(`The command ${commandToExecuteString} never finished under the process, but it was marked non terminal.`));
}
else
{
this.context?.eventStream.post(new CommandProcessorExecutionEnd(`The command ${commandToExecuteString} was finished by the master process, as ${outputFile} was found.`));
const stdout = commandOutputJson['stdout'];
const stderr = commandOutputJson['stderr'];
statusCode = commandOutputJson['status'];
if (stdout)
{
this.context?.eventStream.post(new CommandExecutionStdOut(`The command ${commandToExecuteString} encountered stdout, continuing
${stdout}`));
commandResultString += stdout;
}
if (stderr)
{
this.context?.eventStream.post(new CommandExecutionStdError(`The command ${commandToExecuteString} encountered stderr, continuing
${stderr}`));
commandResultString += stderr;
}
if(statusCode !== '0' && failOnNonZeroExit)
{
const err = new CommandExecutionNonZeroExitFailure(new Error(`Cancelling .NET Install, as command ${commandToExecuteString} returned with status ${statusCode}.`),
getInstallKeyFromContext(this.context?.acquisitionContext!));
this.context?.eventStream.post(err);
throw err.error;
}
}
return (this.returnStatus ? statusCode : commandResultString);
}
public async executeMultipleCommands(commands: CommandExecutorCommand[], options?: any, terminalFailure = true): Promise<string[]>
{
const results = [];
for(const command of commands)
{

Просмотреть файл

@ -0,0 +1,20 @@
/* --------------------------------------------------------------------------------------------
* Licensed to the .NET Foundation under one or more agreements.
* The .NET Foundation licenses this file to you under the MIT license.
* Licensed under the MIT License. See License.txt in the project root for license information.
* ------------------------------------------------------------------------------------------ */
export type CommandProcessorOutput =
{
/**
* @property commandRoot
* The stdout of the command.
* @property commandParts
* The stderr of the command.
* @property status
* The exit code of the program/command after execution.
*/
stdout : string,
stderr : string,
status : string
}

Просмотреть файл

@ -3,229 +3,244 @@
* The .NET Foundation licenses this file to you under the MIT license.
* Licensed under the MIT License. See License.txt in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import * as eol from 'eol';
import * as fs from 'fs';
import * as path from 'path';
import * as os from 'os';
import * as proc from 'child_process';
import * as crypto from 'crypto';
import * as eol from 'eol';
import * as fs from 'fs';
import * as path from 'path';
import * as os from 'os';
import * as proc from 'child_process';
import * as crypto from 'crypto';
import { IFileUtilities } from './IFileUtilities';
import * as lockfile from 'proper-lockfile';
import * as lockfile from 'proper-lockfile';
import { IEventStream } from '../EventStream/EventStream';
import { DotnetCommandFallbackArchitectureEvent,
DotnetCommandFallbackOSEvent,
DotnetFileWriteRequestEvent,
DotnetLockAcquiredEvent,
DotnetLockAttemptingAcquireEvent,
DotnetLockErrorEvent,
DotnetLockReleasedEvent,
SuppressedAcquisitionError
DotnetCommandFallbackOSEvent,
DotnetFileWriteRequestEvent,
DotnetLockAcquiredEvent,
DotnetLockAttemptingAcquireEvent,
DotnetLockErrorEvent,
DotnetLockReleasedEvent,
SuppressedAcquisitionError
} from '../EventStream/EventStreamEvents';
/* tslint:disable:no-any */
export class FileUtilities extends IFileUtilities
{
public async writeFileOntoDisk(scriptContent: string, filePath: string, eventStream : IEventStream)
{
eventStream.post(new DotnetFileWriteRequestEvent(`Request to write`, new Date().toISOString(), filePath));
public async writeFileOntoDisk(scriptContent: string, filePath: string, alreadyHoldingLock = false, eventStream? : IEventStream)
{
eventStream?.post(new DotnetFileWriteRequestEvent(`Request to write`, new Date().toISOString(), filePath));
if (!fs.existsSync(path.dirname(filePath))) {
fs.mkdirSync(path.dirname(filePath), { recursive: true });
}
// Prepare to lock directory so we can check file exists atomically
const directoryLock = 'dir.lock';
const directoryLockPath = path.join(path.dirname(filePath), directoryLock);
if (!fs.existsSync(path.dirname(filePath))) {
fs.mkdirSync(path.dirname(filePath), { recursive: true });
}
// Prepare to lock directory so we can check file exists atomically
const directoryLock = 'dir.lock';
const directoryLockPath = path.join(path.dirname(filePath), directoryLock);
// Begin Critical Section
// This check is part of a RACE CONDITION, it is technically part of the critical section as you will fail if the file DNE,
// but you cant lock the file until it exists. Since there is no context in which files written by this are deleted while this can run,
// theoretically, this ok. The library SHOULD provide a RAII based system for locks, but it does not.
if(!fs.existsSync(filePath))
{
// Create an empty file, as proper-lockfile fails to lock a file if file dne
eventStream.post(new DotnetFileWriteRequestEvent(`File did not exist upon write request.`, new Date().toISOString(), filePath));
fs.writeFileSync(filePath, '');
}
// Begin Critical Section
// This check is part of a RACE CONDITION, it is technically part of the critical section as you will fail if the file DNE,
// but you cant lock the file until it exists. Since there is no context in which files written by this are deleted while this can run,
// theoretically, this ok. The library SHOULD provide a RAII based system for locks, but it does not.
if(!fs.existsSync(filePath))
{
// Create an empty file, as proper-lockfile fails to lock a file if file dne
eventStream?.post(new DotnetFileWriteRequestEvent(`File did not exist upon write request.`, new Date().toISOString(), filePath));
fs.writeFileSync(filePath, '');
}
eventStream.post(new DotnetLockAttemptingAcquireEvent(`Lock Acquisition request to begin.`, new Date().toISOString(), directoryLockPath, filePath));
await lockfile.lock(filePath, { lockfilePath: directoryLockPath, retries: { retries: 10, maxTimeout: 1000 } } )
.then(async (release) =>
{
eventStream.post(new DotnetLockAcquiredEvent(`Lock Acquired.`, new Date().toISOString(), directoryLockPath, filePath));
if(!alreadyHoldingLock)
{
eventStream?.post(new DotnetLockAttemptingAcquireEvent(`Lock Acquisition request to begin.`, new Date().toISOString(), directoryLockPath, filePath));
await lockfile.lock(filePath, { lockfilePath: directoryLockPath, retries: { retries: 10, maxTimeout: 1000 } } )
.then(async (release) =>
{
eventStream?.post(new DotnetLockAcquiredEvent(`Lock Acquired.`, new Date().toISOString(), directoryLockPath, filePath));
// We would like to unlock the directory, but we can't grab a lock on the file if the directory is locked.
// Theoretically you could: add a new file-writer lock as a 3rd party lock ...
// Then, lock the file-writer, unlock the directory, then lock the file, then unlock file-writer, ...
// operate, then unlock file once the operation is done.
// For now, keep the entire directory locked.
// We would like to unlock the directory, but we can't grab a lock on the file if the directory is locked.
// Theoretically you could: add a new file-writer lock as a 3rd party lock ...
// Then, lock the file-writer, unlock the directory, then lock the file, then unlock file-writer, ...
// operate, then unlock file once the operation is done.
// For now, keep the entire directory locked.
scriptContent = eol.auto(scriptContent);
const existingScriptContent = fs.readFileSync(filePath).toString();
// fs.writeFile will replace the file if it exists.
// https://nodejs.org/api/fs.html#fswritefilefile-data-options-callback
if(scriptContent !== existingScriptContent)
{
fs.writeFileSync(filePath, scriptContent);
eventStream.post(new DotnetFileWriteRequestEvent(`File content needed to be updated.`, new Date().toISOString(), filePath));
}
else
{
eventStream.post(new DotnetFileWriteRequestEvent(`File content is an exact match, not writing file.`, new Date().toISOString(), filePath));
}
this.innerWriteFile(scriptContent, filePath, eventStream);
fs.chmodSync(filePath, 0o744);
eventStream.post(new DotnetLockReleasedEvent(`Lock about to be released.`, new Date().toISOString(), directoryLockPath, filePath));
return release();
})
.catch((e : Error) =>
{
// Either the lock could not be acquired or releasing it failed
eventStream.post(new DotnetLockErrorEvent(e, e.message, new Date().toISOString(), directoryLockPath, filePath));
});
// End Critical Section
}
eventStream?.post(new DotnetLockReleasedEvent(`Lock about to be released.`, new Date().toISOString(), directoryLockPath, filePath));
return release();
})
.catch((e : Error) =>
{
// Either the lock could not be acquired or releasing it failed
eventStream?.post(new DotnetLockErrorEvent(e, e.message, new Date().toISOString(), directoryLockPath, filePath));
});
}
else
{
this.innerWriteFile(scriptContent, filePath, eventStream);
}
// End Critical Section
}
/**
* @param directoryToWipe the directory to delete all of the files in if privilege to do so exists.
*/
public wipeDirectory(directoryToWipe : string, eventStream : IEventStream)
{
if(!fs.existsSync(directoryToWipe))
{
return;
}
private innerWriteFile(scriptContent: string, filePath: string, eventStream? : IEventStream)
{
scriptContent = eol.auto(scriptContent);
const existingScriptContent = fs.readFileSync(filePath).toString();
// fs.writeFile will replace the file if it exists.
// https://nodejs.org/api/fs.html#fswritefilefile-data-options-callback
if(scriptContent !== existingScriptContent)
{
fs.writeFileSync(filePath, scriptContent);
eventStream?.post(new DotnetFileWriteRequestEvent(`File content needed to be updated.`, new Date().toISOString(), filePath));
}
else
{
eventStream?.post(new DotnetFileWriteRequestEvent(`File content is an exact match, not writing file.`, new Date().toISOString(), filePath));
}
// Use rimraf to delete all of the items in a directory without the directory itself.
fs.readdirSync(directoryToWipe).forEach(f =>
{
try
{
fs.rmSync(`${directoryToWipe}/${f}`);
}
catch(error : any)
{
eventStream.post(new SuppressedAcquisitionError(error, `Failed to delete ${f} when marked for deletion.`));
}
});
}
fs.chmodSync(filePath, 0o744);
}
/**
*
* @param nodeArchitecture the architecture in node style string of what to install
* @returns the architecture in the style that .net / the .net install scripts expect
*
* Node - amd64 is documented as an option for install scripts but its no longer used.
* s390x is also no longer used.
* ppc64le is supported but this version of node has no distinction of the endianness of the process.
* It has no mapping to mips or other node architectures.
*
* @remarks Falls back to string 'auto' if a mapping does not exist which is not a valid architecture.
*/
public nodeArchToDotnetArch(nodeArchitecture : string, eventStream : IEventStream)
{
switch(nodeArchitecture)
{
case 'x64': {
return nodeArchitecture;
}
case 'ia32': {
return 'x86';
}
case 'x86': {
// In case the function is called twice
return 'x86';
}
case 'arm': {
return nodeArchitecture;
}
case 'arm64': {
return nodeArchitecture;
}
case 's390x': {
return 's390x';
}
default: {
eventStream.post(new DotnetCommandFallbackArchitectureEvent(`The architecture ${os.arch()} of the platform is unexpected, falling back to auto-arch.`));
return 'auto';
}
}
}
/**
* @param directoryToWipe the directory to delete all of the files in if privilege to do so exists.
* @param fileExtensionsToDelete - if undefined, delete all files. if not, delete only files with extensions in this array in lower case.
*/
public wipeDirectory(directoryToWipe : string, eventStream? : IEventStream, fileExtensionsToDelete? : string[])
{
if(!fs.existsSync(directoryToWipe))
{
return;
}
/**
*
* @param nodeOS the OS in node style string of what to install
* @returns the OS in the style that .net / the .net install scripts expect
*
*/
public nodeOSToDotnetOS(nodeOS : string, eventStream : IEventStream)
{
switch(nodeOS)
{
case 'win32': {
return 'win';
}
case 'darwin': {
return 'osx';
}
case 'linux': {
return nodeOS;
}
default: {
eventStream.post(new DotnetCommandFallbackOSEvent(`The OS ${os.platform()} of the platform is unexpected, falling back to auto-os.`));
return 'auto'
}
}
}
// Use rimraf to delete all of the items in a directory without the directory itself.
fs.readdirSync(directoryToWipe).forEach(f =>
{
try
{
if(!fileExtensionsToDelete || path.extname(f).toLocaleLowerCase() in fileExtensionsToDelete)
fs.rmSync(`${directoryToWipe}/${f}`);
}
catch(error : any)
{
eventStream?.post(new SuppressedAcquisitionError(error, `Failed to delete ${f} when marked for deletion.`));
}
});
}
/**
*
* @returns true if the process is running with admin privileges
*/
public isElevated(eventStream? : IEventStream) : boolean
{
if(os.platform() !== 'win32')
{
try
{
const commandResult = proc.spawnSync('id', ['-u']);
return commandResult.status === 0;
}
catch(error : any)
{
eventStream?.post(new SuppressedAcquisitionError(error, `Failed to run 'id' to check for privilege, running without privilege.`))
return false;
}
}
/**
*
* @param nodeArchitecture the architecture in node style string of what to install
* @returns the architecture in the style that .net / the .net install scripts expect
*
* Node - amd64 is documented as an option for install scripts but its no longer used.
* s390x is also no longer used.
* ppc64le is supported but this version of node has no distinction of the endianness of the process.
* It has no mapping to mips or other node architectures.
*
* @remarks Falls back to string 'auto' if a mapping does not exist which is not a valid architecture.
*/
public nodeArchToDotnetArch(nodeArchitecture : string, eventStream : IEventStream)
{
switch(nodeArchitecture)
{
case 'x64': {
return nodeArchitecture;
}
case 'ia32': {
return 'x86';
}
case 'x86': {
// In case the function is called twice
return 'x86';
}
case 'arm': {
return nodeArchitecture;
}
case 'arm64': {
return nodeArchitecture;
}
case 's390x': {
return 's390x';
}
default: {
eventStream.post(new DotnetCommandFallbackArchitectureEvent(`The architecture ${os.arch()} of the platform is unexpected, falling back to auto-arch.`));
return 'auto';
}
}
}
try
{
// If we can execute this command on Windows then we have admin rights.
proc.execFileSync( 'net', ['session'], { 'stdio': 'ignore' } );
return true;
}
catch ( error : any )
{
eventStream?.post(new SuppressedAcquisitionError(error, `Failed to run 'net' to check for privilege, running without privilege.`))
return false;
}
}
/**
*
* @param nodeOS the OS in node style string of what to install
* @returns the OS in the style that .net / the .net install scripts expect
*
*/
public nodeOSToDotnetOS(nodeOS : string, eventStream : IEventStream)
{
switch(nodeOS)
{
case 'win32': {
return 'win';
}
case 'darwin': {
return 'osx';
}
case 'linux': {
return nodeOS;
}
default: {
eventStream.post(new DotnetCommandFallbackOSEvent(`The OS ${os.platform()} of the platform is unexpected, falling back to auto-os.`));
return 'auto'
}
}
}
private sha512Hasher(filePath : string)
{
return new Promise<string>((resolve, reject) =>
{
const hash = crypto.createHash('sha512');
const fileStream = fs.createReadStream(filePath);
fileStream.on('error', err => reject(err));
fileStream.on('data', chunk => hash.update(chunk));
fileStream.on('end', () => resolve(hash.digest('hex')));
})
};
/**
*
* @returns true if the process is running with admin privileges
*/
public isElevated(eventStream? : IEventStream) : boolean
{
if(os.platform() !== 'win32')
{
try
{
const commandResult = proc.spawnSync('id', ['-u']);
return commandResult.status === 0;
}
catch(error : any)
{
eventStream?.post(new SuppressedAcquisitionError(error, `Failed to run 'id' to check for privilege, running without privilege.`))
return false;
}
}
public async getFileHash(filePath : string) : Promise<string | null>
{
const res = await this.sha512Hasher(filePath);
return res;
}
try
{
// If we can execute this command on Windows then we have admin rights.
proc.execFileSync( 'net', ['session'], { 'stdio': 'ignore' } );
return true;
}
catch ( error : any )
{
eventStream?.post(new SuppressedAcquisitionError(error, `Failed to run 'net' to check for privilege, running without privilege.`))
return false;
}
}
private sha512Hasher(filePath : string)
{
return new Promise<string>((resolve, reject) =>
{
const hash = crypto.createHash('sha512');
const fileStream = fs.createReadStream(filePath);
fileStream.on('error', err => reject(err));
fileStream.on('data', chunk => hash.update(chunk));
fileStream.on('end', () => resolve(hash.digest('hex')));
})
};
public async getFileHash(filePath : string) : Promise<string | null>
{
const res = await this.sha512Hasher(filePath);
return res;
}
}

Просмотреть файл

@ -8,12 +8,12 @@ import { IEventStream } from '../EventStream/EventStream';
export abstract class IFileUtilities
{
public abstract writeFileOntoDisk(scriptContent: string, filePath: string, eventStream : IEventStream) : void;
public abstract writeFileOntoDisk(scriptContent: string, filePath: string, alreadyHoldingLock : boolean, eventStream? : IEventStream) : void;
/**
* @param directoryToWipe the directory to delete all of the files in if privilege to do so exists.
*/
public abstract wipeDirectory(directoryToWipe : string, eventStream : IEventStream) : void;
public abstract wipeDirectory(directoryToWipe : string, eventStream? : IEventStream, fileExtensionsToDelete? : string[]) : void;
/**
*

Просмотреть файл

@ -335,6 +335,7 @@ export class MockCommandExecutor extends ICommandExecutor
if(!command.runUnderSudo && this.fakeReturnValue === '')
{
this.trueExecutor.returnStatus = this.returnStatus;
return this.trueExecutor.execute(command, options);
}
else if(this.otherCommandsToMock.some(x => x.includes(command.commandRoot)))
@ -368,14 +369,14 @@ export class MockFileUtilities extends IFileUtilities
{
private trueUtilities = new FileUtilities();
public writeFileOntoDisk(content : string, filePath : string)
public writeFileOntoDisk(content : string, filePath : string, alreadyHoldingLock = false)
{
return this.trueUtilities.writeFileOntoDisk(content, filePath, new MockEventStream());
return this.trueUtilities.writeFileOntoDisk(content, filePath, alreadyHoldingLock, new MockEventStream());
}
public wipeDirectory(directoryToWipe : string, eventSteam : IEventStream)
public wipeDirectory(directoryToWipe : string, eventSteam : IEventStream, fileExtensionsToDelete? : string[])
{
return this.trueUtilities.wipeDirectory(directoryToWipe, eventSteam);
return this.trueUtilities.wipeDirectory(directoryToWipe, eventSteam, fileExtensionsToDelete);
}
public isElevated()
@ -480,7 +481,7 @@ export class MockDistroProvider extends IDistroDotnetSDKProvider
return new GenericDistroSDKProvider(this.distroVersion, this.context, getMockUtilityContext()).JsonDotnetVersion(fullySpecifiedDotnetVersion);
}
protected isPackageFoundInSearch(resultOfSearchCommand: any): boolean {
protected isPackageFoundInSearch(resultOfSearchCommand: any, searchCommandExitCode : string): boolean {
return true;
}
}

Просмотреть файл

@ -104,7 +104,7 @@ Microsoft.NETCore.App 7.0.5 [/usr/lib/dotnet/shared/Microsoft.NETCore.App]`;
if(shouldRun)
{
await provider.getInstalledGlobalDotnetPathIfExists(installType);
assert.equal(mockExecutor.attemptedCommand, 'which dotnet');
assert.equal(mockExecutor.attemptedCommand, 'readlink -f /usr/bin/dotnet');
}
}).timeout(standardTimeoutTime);
@ -127,15 +127,15 @@ Microsoft.NETCore.App 7.0.5 [/usr/lib/dotnet/shared/Microsoft.NETCore.App]`;
if(shouldRun)
{
const recVersion = await provider.getRecommendedDotnetVersion(installType);
assert.equal(mockExecutor.attemptedCommand, 'apt-cache search dotnet-sdk-7.0');
assert.equal(recVersion, '7.0.1xx');
assert.equal(mockExecutor.attemptedCommand, 'dotnet --version', 'Searched for the newest package last with regex');
assert.equal(recVersion, '8.0.1xx', 'Resolved the most recent available version : will eventually break if the mock data is not updated');
}
}).timeout(standardTimeoutTime);
test('Gives Correct Version Support Info', async () => {
if(shouldRun)
{
let supported = await provider.isDotnetVersionSupported('8.0.101', installType);
let supported = await provider.isDotnetVersionSupported('11.0.101', installType);
// In the mock data, 8.0 is not supported, so it should be false.
assert.equal(supported, false);
supported = await provider.isDotnetVersionSupported('7.0.101', installType);

Просмотреть файл

@ -6,7 +6,7 @@
import * as chai from 'chai';
import * as os from 'os';
import { MockCommandExecutor, MockEventStream } from '../mocks/MockObjects';
import { DistroVersionPair, DotnetDistroSupportStatus } from '../../Acquisition/LinuxVersionResolver';
import { DistroVersionPair, DotnetDistroSupportStatus, LinuxVersionResolver } from '../../Acquisition/LinuxVersionResolver';
import { getMockAcquisitionContext, getMockUtilityContext } from './TestUtility';
import { LinuxInstallType } from '../../Acquisition/LinuxInstallType';
import { RedHatDistroSDKProvider } from '../../Acquisition/RedHatDistroSDKProvider';
@ -18,7 +18,8 @@ const acquisitionContext = getMockAcquisitionContext(false, mockVersion);
const mockExecutor = new MockCommandExecutor(acquisitionContext, getMockUtilityContext());
const pair : DistroVersionPair = { distro : 'Red Hat Enterprise Linux', version : '9.0' };
const provider : RedHatDistroSDKProvider = new RedHatDistroSDKProvider(pair, acquisitionContext, getMockUtilityContext(), mockExecutor);
const shouldRun = os.platform() === 'linux';
const versionResolver = new LinuxVersionResolver(acquisitionContext, getMockUtilityContext(), acquisitionContext.acquisitionContext!, mockExecutor);
let shouldRun = os.platform() === 'linux';
const installType : LinuxInstallType = 'sdk';
const noDotnetString = `
Command 'dotnet' not found, but can be installed with:
@ -33,11 +34,13 @@ Command 'dotnet' not found, but can be installed with:
suite('Red Hat For Linux Distro Logic Unit Tests', () =>
{
test('Package Check Succeeds', async () => {
shouldRun = os.platform() === 'linux' && (await versionResolver.getRunningDistro()).distro === 'Red Hat Enterprise Linux';
if(shouldRun)
{
// assert this passes : we don't want the test to be reliant on machine state for whether the package exists or not, so don't check output
await provider.dotnetPackageExistsOnSystem(mockVersion, installType);
assert.equal(mockExecutor.attemptedCommand, 'yum list install dotnet-sdk-7.0 -q');
assert.equal(mockExecutor.attemptedCommand, 'yum list install dotnet-sdk-9.0 -q');
}
}).timeout(standardTimeoutTime);
@ -104,7 +107,7 @@ Microsoft.NETCore.App 7.0.5 [/usr/lib/dotnet/shared/Microsoft.NETCore.App]`;
if(shouldRun)
{
await provider.getInstalledGlobalDotnetPathIfExists(installType);
assert.equal(mockExecutor.attemptedCommand, 'which dotnet');
assert.equal(mockExecutor.attemptedCommand, 'readlink -f /usr/bin/dotnet');
}
}).timeout(standardTimeoutTime);
@ -127,15 +130,15 @@ Microsoft.NETCore.App 7.0.5 [/usr/lib/dotnet/shared/Microsoft.NETCore.App]`;
if(shouldRun)
{
const recVersion = await provider.getRecommendedDotnetVersion(installType);
assert.equal(mockExecutor.attemptedCommand, 'yum search dotnet-sdk-7.0 -q');
assert.equal(recVersion, '7.0.1xx');
assert.equal(mockExecutor.attemptedCommand, 'dotnet --version', 'Correct command run to get recommended version, uses newest package in distro json');
assert.equal(recVersion, '8.0.1xx', 'The most in support version is suggested : will eventually break if not updated');
}
}).timeout(standardTimeoutTime);
test('Gives Correct Version Support Info', async () => {
if(shouldRun)
{
let supported = await provider.isDotnetVersionSupported('8.0.101', installType);
let supported = await provider.isDotnetVersionSupported('11.0.101', installType);
// In the mock data, 8.0 is not supported, so it should be false.
assert.equal(supported, false);
supported = await provider.isDotnetVersionSupported('7.0.101', installType);