Archived
1
0

Merge branch 'master' into feature/helm3

This commit is contained in:
Matthew Beckett 2020-10-13 14:29:43 +01:00 committed by GitHub
commit d7cba30c6a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
45 changed files with 1058 additions and 489 deletions

View File

@ -30,6 +30,7 @@ rules:
eqeqeq: error eqeqeq: error
import/order: import/order:
[error, { alphabetize: { order: "asc" }, groups: [["builtin", "external", "internal"], "parent", "sibling"] }] [error, { alphabetize: { order: "asc" }, groups: [["builtin", "external", "internal"], "parent", "sibling"] }]
no-async-promise-executor: off
settings: settings:
# Does not work with CommonJS unfortunately. # Does not work with CommonJS unfortunately.

7
.github/ISSUE_TEMPLATE/doc.md vendored Normal file
View File

@ -0,0 +1,7 @@
---
name: Documentation improvement
about: Suggest a documentation improvement
title: ""
labels: "docs"
assignees: ""
---

View File

@ -8,7 +8,7 @@ jobs:
steps: steps:
- uses: actions/checkout@v1 - uses: actions/checkout@v1
- name: Run ./ci/steps/fmt.sh - name: Run ./ci/steps/fmt.sh
uses: ./ci/images/debian8 uses: ./ci/images/debian10
with: with:
args: ./ci/steps/fmt.sh args: ./ci/steps/fmt.sh
@ -17,7 +17,7 @@ jobs:
steps: steps:
- uses: actions/checkout@v1 - uses: actions/checkout@v1
- name: Run ./ci/steps/lint.sh - name: Run ./ci/steps/lint.sh
uses: ./ci/images/debian8 uses: ./ci/images/debian10
with: with:
args: ./ci/steps/lint.sh args: ./ci/steps/lint.sh
@ -26,7 +26,7 @@ jobs:
steps: steps:
- uses: actions/checkout@v1 - uses: actions/checkout@v1
- name: Run ./ci/steps/test.sh - name: Run ./ci/steps/test.sh
uses: ./ci/images/debian8 uses: ./ci/images/debian10
with: with:
args: ./ci/steps/test.sh args: ./ci/steps/test.sh
@ -35,7 +35,7 @@ jobs:
steps: steps:
- uses: actions/checkout@v1 - uses: actions/checkout@v1
- name: Run ./ci/steps/release.sh - name: Run ./ci/steps/release.sh
uses: ./ci/images/debian8 uses: ./ci/images/debian10
with: with:
args: ./ci/steps/release.sh args: ./ci/steps/release.sh
- name: Upload npm package artifact - name: Upload npm package artifact
@ -116,7 +116,7 @@ jobs:
name: release-packages name: release-packages
path: ./release-packages path: ./release-packages
- name: Run ./ci/steps/build-docker-image.sh - name: Run ./ci/steps/build-docker-image.sh
uses: ./ci/images/debian8 uses: ./ci/images/debian10
with: with:
args: ./ci/steps/build-docker-image.sh args: ./ci/steps/build-docker-image.sh
- name: Upload release image - name: Upload release image

View File

@ -10,7 +10,7 @@ jobs:
steps: steps:
- uses: actions/checkout@v1 - uses: actions/checkout@v1
- name: Run ./ci/steps/publish-npm.sh - name: Run ./ci/steps/publish-npm.sh
uses: ./ci/images/debian8 uses: ./ci/images/debian10
with: with:
args: ./ci/steps/publish-npm.sh args: ./ci/steps/publish-npm.sh
env: env:
@ -22,7 +22,7 @@ jobs:
steps: steps:
- uses: actions/checkout@v1 - uses: actions/checkout@v1
- name: Run ./ci/steps/push-docker-manifest.sh - name: Run ./ci/steps/push-docker-manifest.sh
uses: ./ci/images/debian8 uses: ./ci/images/debian10
with: with:
args: ./ci/steps/push-docker-manifest.sh args: ./ci/steps/push-docker-manifest.sh
env: env:

2
.gitignore vendored
View File

@ -11,3 +11,5 @@ release-images/
node_modules node_modules
node-* node-*
/plugins /plugins
/lib/coder-cloud-agent
.home

1
.gitmodules vendored
View File

@ -1,3 +1,4 @@
[submodule "lib/vscode"] [submodule "lib/vscode"]
path = lib/vscode path = lib/vscode
url = https://github.com/microsoft/vscode url = https://github.com/microsoft/vscode
ignore = dirty

View File

@ -1,4 +1,4 @@
# code-server # code-server · [!["GitHub Discussions"](https://img.shields.io/badge/%20GitHub-%20Discussions-gray.svg?longCache=true&logo=github&colorB=purple)](https://github.com/cdr/code-server/discussions) [!["Join us on Slack"](https://img.shields.io/badge/join-us%20on%20slack-gray.svg?longCache=true&logo=slack&colorB=brightgreen)](https://cdr.co/join-community) [![Twitter Follow](https://img.shields.io/twitter/follow/CoderHQ?label=%40CoderHQ&style=social)](https://twitter.com/coderhq)
Run [VS Code](https://github.com/Microsoft/vscode) on any machine anywhere and access it in the browser. Run [VS Code](https://github.com/Microsoft/vscode) on any machine anywhere and access it in the browser.
@ -11,7 +11,7 @@ Run [VS Code](https://github.com/Microsoft/vscode) on any machine anywhere and a
- Develop on a Linux machine and pick up from any device with a web browser. - Develop on a Linux machine and pick up from any device with a web browser.
- **Server-powered** - **Server-powered**
- Take advantage of large cloud servers to speed up tests, compilations, downloads, and more. - Take advantage of large cloud servers to speed up tests, compilations, downloads, and more.
- Preserve battery life when you're on the go as all intensive tasks runs on your server. - Preserve battery life when you're on the go as all intensive tasks run on your server.
- Make use of a spare computer you have lying around and turn it into a full development environment. - Make use of a spare computer you have lying around and turn it into a full development environment.
## Getting Started ## Getting Started
@ -52,7 +52,7 @@ See [./doc/CONTRIBUTING.md](./doc/CONTRIBUTING.md).
## Hiring ## Hiring
We ([@cdr](https://github.com/cdr)) are looking for a engineers to help maintain We ([@cdr](https://github.com/cdr)) are looking for engineers to help maintain
code-server, innovate on open source and streamline dev workflows. code-server, innovate on open source and streamline dev workflows.
Our main office is in Austin, Texas. Remote is ok as long as Our main office is in Austin, Texas. Remote is ok as long as

View File

@ -18,6 +18,12 @@ main() {
chmod +x out/node/entry.js chmod +x out/node/entry.js
fi fi
if ! [ -f ./lib/coder-cloud-agent ]; then
OS="$(uname | tr '[:upper:]' '[:lower:]')"
curl -fsSL "https://storage.googleapis.com/coder-cloud-releases/agent/latest/$OS/cloud-agent" -o ./lib/coder-cloud-agent
chmod +x ./lib/coder-cloud-agent
fi
parcel build \ parcel build \
--public-url "." \ --public-url "." \
--out-dir dist \ --out-dir dist \

View File

@ -11,15 +11,6 @@ main() {
mkdir -p release-packages mkdir -p release-packages
release_archive release_archive
# Will stop the auto update issues and allow people to upgrade their scripts
# for the new release structure.
if [[ $ARCH == "amd64" ]]; then
if [[ $OS == "linux" ]]; then
ARCH=x86_64 release_archive
elif [[ $OS == "macos" ]]; then
OS=darwin ARCH=x86_64 release_archive
fi
fi
if [[ $OS == "linux" ]]; then if [[ $OS == "linux" ]]; then
release_nfpm release_nfpm
@ -30,12 +21,6 @@ release_archive() {
local release_name="code-server-$VERSION-$OS-$ARCH" local release_name="code-server-$VERSION-$OS-$ARCH"
if [[ $OS == "linux" ]]; then if [[ $OS == "linux" ]]; then
tar -czf "release-packages/$release_name.tar.gz" --transform "s/^\.\/release-standalone/$release_name/" ./release-standalone tar -czf "release-packages/$release_name.tar.gz" --transform "s/^\.\/release-standalone/$release_name/" ./release-standalone
elif [[ $OS == "darwin" && $ARCH == "x86_64" ]]; then
# Just exists to make autoupdating from 3.2.0 work again.
mv ./release-standalone "./$release_name"
zip -r "release-packages/$release_name.zip" "./$release_name"
mv "./$release_name" ./release-standalone
return
else else
tar -czf "release-packages/$release_name.tar.gz" -s "/^release-standalone/$release_name/" release-standalone tar -czf "release-packages/$release_name.tar.gz" -s "/^release-standalone/$release_name/" release-standalone
fi fi

View File

@ -6,6 +6,10 @@ set -euo pipefail
# MINIFY controls whether minified vscode is bundled. # MINIFY controls whether minified vscode is bundled.
MINIFY="${MINIFY-true}" MINIFY="${MINIFY-true}"
# KEEP_MODULES controls whether the script cleans all node_modules requiring a yarn install
# to run first.
KEEP_MODULES="${KEEP_MODULES-0}"
main() { main() {
cd "$(dirname "${0}")/../.." cd "$(dirname "${0}")/../.."
source ./ci/lib.sh source ./ci/lib.sh
@ -37,6 +41,7 @@ bundle_code_server() {
rsync src/browser/media/ "$RELEASE_PATH/src/browser/media" rsync src/browser/media/ "$RELEASE_PATH/src/browser/media"
mkdir -p "$RELEASE_PATH/src/browser/pages" mkdir -p "$RELEASE_PATH/src/browser/pages"
rsync src/browser/pages/*.html "$RELEASE_PATH/src/browser/pages" rsync src/browser/pages/*.html "$RELEASE_PATH/src/browser/pages"
rsync src/browser/robots.txt "$RELEASE_PATH/src/browser"
# Adds the commit to package.json # Adds the commit to package.json
jq --slurp '.[0] * .[1]' package.json <( jq --slurp '.[0] * .[1]' package.json <(
@ -51,6 +56,12 @@ EOF
) > "$RELEASE_PATH/package.json" ) > "$RELEASE_PATH/package.json"
rsync yarn.lock "$RELEASE_PATH" rsync yarn.lock "$RELEASE_PATH"
rsync ci/build/npm-postinstall.sh "$RELEASE_PATH/postinstall.sh" rsync ci/build/npm-postinstall.sh "$RELEASE_PATH/postinstall.sh"
if [ "$KEEP_MODULES" = 1 ]; then
rsync node_modules/ "$RELEASE_PATH/node_modules"
mkdir -p "$RELEASE_PATH/lib"
rsync ./lib/coder-cloud-agent "$RELEASE_PATH/lib"
fi
} }
bundle_vscode() { bundle_vscode() {
@ -59,7 +70,11 @@ bundle_vscode() {
rsync "$VSCODE_SRC_PATH/out-vscode${MINIFY+-min}/" "$VSCODE_OUT_PATH/out" rsync "$VSCODE_SRC_PATH/out-vscode${MINIFY+-min}/" "$VSCODE_OUT_PATH/out"
rsync "$VSCODE_SRC_PATH/.build/extensions/" "$VSCODE_OUT_PATH/extensions" rsync "$VSCODE_SRC_PATH/.build/extensions/" "$VSCODE_OUT_PATH/extensions"
if [ "$KEEP_MODULES" = 0 ]; then
rm -Rf "$VSCODE_OUT_PATH/extensions/node_modules" rm -Rf "$VSCODE_OUT_PATH/extensions/node_modules"
else
rsync "$VSCODE_SRC_PATH/node_modules/" "$VSCODE_OUT_PATH/node_modules"
fi
rsync "$VSCODE_SRC_PATH/extensions/package.json" "$VSCODE_OUT_PATH/extensions" rsync "$VSCODE_SRC_PATH/extensions/package.json" "$VSCODE_OUT_PATH/extensions"
rsync "$VSCODE_SRC_PATH/extensions/yarn.lock" "$VSCODE_OUT_PATH/extensions" rsync "$VSCODE_SRC_PATH/extensions/yarn.lock" "$VSCODE_OUT_PATH/extensions"
rsync "$VSCODE_SRC_PATH/extensions/postinstall.js" "$VSCODE_OUT_PATH/extensions" rsync "$VSCODE_SRC_PATH/extensions/postinstall.js" "$VSCODE_OUT_PATH/extensions"

View File

@ -5,16 +5,7 @@ main() {
cd "$(dirname "${0}")/../.." cd "$(dirname "${0}")/../.."
source ./ci/lib.sh source ./ci/lib.sh
rm -rf \ git clean -Xffd
out \
release \
release-standalone \
release-packages \
release-gcp \
release-images \
dist \
.cache \
node-*
pushd lib/vscode pushd lib/vscode
git clean -xffd git clean -xffd

View File

@ -24,6 +24,10 @@ main() {
;; ;;
esac esac
OS="$(uname | tr '[:upper:]' '[:lower:]')"
curl -fsSL "https://storage.googleapis.com/coder-cloud-releases/agent/latest/$OS/cloud-agent" -o ./lib/coder-cloud-agent
chmod +x ./lib/coder-cloud-agent
if ! vscode_yarn; then if ! vscode_yarn; then
echo "You may not have the required dependencies to build the native modules." echo "You may not have the required dependencies to build the native modules."
echo "Please see https://github.com/cdr/code-server/blob/master/doc/npm.md" echo "Please see https://github.com/cdr/code-server/blob/master/doc/npm.md"
@ -36,6 +40,13 @@ vscode_yarn() {
yarn --production --frozen-lockfile yarn --production --frozen-lockfile
cd extensions cd extensions
yarn --production --frozen-lockfile yarn --production --frozen-lockfile
for ext in */; do
ext="${ext%/}"
echo "extensions/$ext: installing dependencies"
cd "$ext"
yarn --production --frozen-lockfile
cd "$OLDPWD"
done
} }
main "$@" main "$@"

View File

@ -11,7 +11,7 @@ main() {
source ./ci/lib.sh source ./ci/lib.sh
download_artifact release-packages ./release-packages download_artifact release-packages ./release-packages
local assets=(./release-packages/code-server*"$VERSION"*{.tar.gz,.zip,.deb,.rpm}) local assets=(./release-packages/code-server*"$VERSION"*{.tar.gz,.deb,.rpm})
for i in "${!assets[@]}"; do for i in "${!assets[@]}"; do
assets[$i]="--attach=${assets[$i]}" assets[$i]="--attach=${assets[$i]}"
done done

View File

@ -15,8 +15,7 @@ main() {
./release-standalone/bin/code-server --extensions-dir "$EXTENSIONS_DIR" --install-extension ms-python.python ./release-standalone/bin/code-server --extensions-dir "$EXTENSIONS_DIR" --install-extension ms-python.python
local installed_extensions local installed_extensions
installed_extensions="$(./release-standalone/bin/code-server --extensions-dir "$EXTENSIONS_DIR" --list-extensions 2>&1)" installed_extensions="$(./release-standalone/bin/code-server --extensions-dir "$EXTENSIONS_DIR" --list-extensions 2>&1)"
if [[ $installed_extensions != *"info Using config file ~/.config/code-server/config.yaml if [[ $installed_extensions != "ms-python.python" ]]; then
ms-python.python" ]]; then
echo "Unexpected output from listing extensions:" echo "Unexpected output from listing extensions:"
echo "$installed_extensions" echo "$installed_extensions"
exit 1 exit 1

View File

@ -6,7 +6,7 @@ main() {
cd ./lib/vscode cd ./lib/vscode
git add -A git add -A
git diff HEAD > ../../ci/dev/vscode.patch git diff HEAD --full-index > ../../ci/dev/vscode.patch
} }
main "$@" main "$@"

View File

@ -4,16 +4,22 @@ set -euo pipefail
main() { main() {
cd "$(dirname "$0")/../../.." cd "$(dirname "$0")/../../.."
source ./ci/lib.sh source ./ci/lib.sh
mkdir -p .home
docker run \ docker run \
-it \ -it \
--rm \ --rm \
-v "$PWD:/src" \ -v "$PWD:/src" \
-e HOME="/src/.home" \
-e USER="coder" \
-e GITHUB_TOKEN \
-e KEEP_MODULES \
-e MINIFY \
-w /src \ -w /src \
-p 127.0.0.1:8080:8080 \ -p 127.0.0.1:8080:8080 \
-u "$(id -u):$(id -g)" \ -u "$(id -u):$(id -g)" \
-e CI \ -e CI \
"$(docker_build ./ci/images/debian8)" \ "$(docker_build ./ci/images/"${IMAGE-debian10}")" \
"$@" "$@"
} }

View File

@ -7,10 +7,7 @@ main() {
eslint --max-warnings=0 --fix $(git ls-files "*.ts" "*.tsx" "*.js") eslint --max-warnings=0 --fix $(git ls-files "*.ts" "*.tsx" "*.js")
stylelint $(git ls-files "*.css") stylelint $(git ls-files "*.css")
tsc --noEmit tsc --noEmit
# See comment in ./ci/image/debian8
if [[ ! ${CI-} ]]; then
shellcheck -e SC2046,SC2164,SC2154,SC1091,SC1090,SC2002 $(git ls-files "*.sh") shellcheck -e SC2046,SC2164,SC2154,SC1091,SC1090,SC2002 $(git ls-files "*.sh")
fi
} }
main "$@" main "$@"

View File

@ -1,5 +1,5 @@
diff --git a/.gitignore b/.gitignore diff --git a/.gitignore b/.gitignore
index 0fe46b6eadc..e545e004cef 100644 index 0fe46b6eadc4ccc819fbf342ee1071bb657792b3..e545e004cef31fa5f40ba8df6a2317ea5b69ddb5 100644
--- a/.gitignore --- a/.gitignore
+++ b/.gitignore +++ b/.gitignore
@@ -25,7 +25,6 @@ out-vscode-reh-web-pkg/ @@ -25,7 +25,6 @@ out-vscode-reh-web-pkg/
@ -12,15 +12,15 @@ index 0fe46b6eadc..e545e004cef 100644
coverage/ coverage/
diff --git a/.yarnrc b/.yarnrc diff --git a/.yarnrc b/.yarnrc
deleted file mode 100644 deleted file mode 100644
index 135e10442a7..00000000000 index 3c6eccfb102f2084d16395d70d65f05a91b6d47b..0000000000000000000000000000000000000000
--- a/.yarnrc --- a/.yarnrc
+++ /dev/null +++ /dev/null
@@ -1,3 +0,0 @@ @@ -1,3 +0,0 @@
-disturl "https://atom.io/download/electron" -disturl "https://atom.io/download/electron"
-target "7.3.2" -target "9.2.1"
-runtime "electron" -runtime "electron"
diff --git a/build/gulpfile.reh.js b/build/gulpfile.reh.js diff --git a/build/gulpfile.reh.js b/build/gulpfile.reh.js
index f2ea1bd3701..3f660f99819 100644 index f2ea1bd37010b1eb8a43ce9beaae4a88810f6e2d..3f660f9981921ec465d2b8809a1a5ea5663f4c1f 100644
--- a/build/gulpfile.reh.js --- a/build/gulpfile.reh.js
+++ b/build/gulpfile.reh.js +++ b/build/gulpfile.reh.js
@@ -52,6 +52,7 @@ gulp.task('vscode-reh-web-linux-x64-min', noop); @@ -52,6 +52,7 @@ gulp.task('vscode-reh-web-linux-x64-min', noop);
@ -31,8 +31,34 @@ index f2ea1bd3701..3f660f99819 100644
const yarnrc = fs.readFileSync(path.join(REPO_ROOT, 'remote', '.yarnrc'), 'utf8'); const yarnrc = fs.readFileSync(path.join(REPO_ROOT, 'remote', '.yarnrc'), 'utf8');
const target = /^target "(.*)"$/m.exec(yarnrc)[1]; const target = /^target "(.*)"$/m.exec(yarnrc)[1];
return target; return target;
diff --git a/build/lib/extensions.js b/build/lib/extensions.js
index 9cc40c4e1befd38886dc5880581d6f462a38dd3a..34e1fc89a8ac1c273a5cb41f19a088a8ec759d24 100644
--- a/build/lib/extensions.js
+++ b/build/lib/extensions.js
@@ -66,7 +66,7 @@ function fromLocal(extensionPath, forWeb) {
if (isWebPacked) {
input = updateExtensionPackageJSON(input, (data) => {
delete data.scripts;
- delete data.dependencies;
+ // https://github.com/cdr/code-server/pull/2041#issuecomment-685910322
delete data.devDependencies;
if (data.main) {
data.main = data.main.replace('/out/', /dist/);
diff --git a/build/lib/extensions.ts b/build/lib/extensions.ts
index 7e529f17cb84d28d84de4ff64fa9fb8fc48135a9..462d699dc485369c74a4d9fdfefa48ba6124ac3a 100644
--- a/build/lib/extensions.ts
+++ b/build/lib/extensions.ts
@@ -70,7 +70,7 @@ function fromLocal(extensionPath: string, forWeb: boolean): Stream {
if (isWebPacked) {
input = updateExtensionPackageJSON(input, (data: any) => {
delete data.scripts;
- delete data.dependencies;
+ // https://github.com/cdr/code-server/pull/2041#issuecomment-685910322
delete data.devDependencies;
if (data.main) {
data.main = data.main.replace('/out/', /dist/);
diff --git a/build/lib/node.js b/build/lib/node.js diff --git a/build/lib/node.js b/build/lib/node.js
index 403ae3d9657..738ee8cee0e 100644 index 403ae3d9657f823019542e739fc39292db20e4fe..738ee8cee0e79aa239af10e1abefc9e836b8ce33 100644
--- a/build/lib/node.js --- a/build/lib/node.js
+++ b/build/lib/node.js +++ b/build/lib/node.js
@@ -5,11 +5,8 @@ @@ -5,11 +5,8 @@
@ -49,7 +75,7 @@ index 403ae3d9657..738ee8cee0e 100644
const nodePath = path.join(root, '.build', 'node', `v${version}`, `${process.platform}-${process.arch}`, node); const nodePath = path.join(root, '.build', 'node', `v${version}`, `${process.platform}-${process.arch}`, node);
console.log(nodePath); console.log(nodePath);
diff --git a/build/lib/node.ts b/build/lib/node.ts diff --git a/build/lib/node.ts b/build/lib/node.ts
index 64397034461..c53dccf4dc0 100644 index 64397034461b1661f82007c141cbf4c039a3b722..c53dccf4dc0a99122ed96cf10c2eb632bb25059e 100644
--- a/build/lib/node.ts --- a/build/lib/node.ts
+++ b/build/lib/node.ts +++ b/build/lib/node.ts
@@ -4,13 +4,10 @@ @@ -4,13 +4,10 @@
@ -70,7 +96,7 @@ index 64397034461..c53dccf4dc0 100644
\ No newline at end of file \ No newline at end of file
+console.log(nodePath); +console.log(nodePath);
diff --git a/build/lib/util.js b/build/lib/util.js diff --git a/build/lib/util.js b/build/lib/util.js
index e552a036f89..169e8614b9f 100644 index e552a036f89bd581644459fd5c27fe4ae1379f62..169e8614b9f6a2bd68446144ab7e1ce5c6d49b64 100644
--- a/build/lib/util.js --- a/build/lib/util.js
+++ b/build/lib/util.js +++ b/build/lib/util.js
@@ -257,6 +257,7 @@ function streamToPromise(stream) { @@ -257,6 +257,7 @@ function streamToPromise(stream) {
@ -82,7 +108,7 @@ index e552a036f89..169e8614b9f 100644
const target = /^target "(.*)"$/m.exec(yarnrc)[1]; const target = /^target "(.*)"$/m.exec(yarnrc)[1];
return target; return target;
diff --git a/build/lib/util.ts b/build/lib/util.ts diff --git a/build/lib/util.ts b/build/lib/util.ts
index 035c7e95ea3..4ff8dcfe6b2 100644 index 035c7e95ea3006bb3dabd68bbf54db80de4aaaf2..4ff8dcfe6b21a0ec8064ebc7bb05506b8f1faa91 100644
--- a/build/lib/util.ts --- a/build/lib/util.ts
+++ b/build/lib/util.ts +++ b/build/lib/util.ts
@@ -322,6 +322,7 @@ export function streamToPromise(stream: NodeJS.ReadWriteStream): Promise<void> { @@ -322,6 +322,7 @@ export function streamToPromise(stream: NodeJS.ReadWriteStream): Promise<void> {
@ -94,7 +120,7 @@ index 035c7e95ea3..4ff8dcfe6b2 100644
const target = /^target "(.*)"$/m.exec(yarnrc)![1]; const target = /^target "(.*)"$/m.exec(yarnrc)![1];
return target; return target;
diff --git a/build/npm/postinstall.js b/build/npm/postinstall.js diff --git a/build/npm/postinstall.js b/build/npm/postinstall.js
index 8f8b0019a77..ea054c725be 100644 index 8f8b0019a7792a993fbd6bf95b013b596aa2935a..ea054c725bea2eec342e12b07314241aa18a4951 100644
--- a/build/npm/postinstall.js --- a/build/npm/postinstall.js
+++ b/build/npm/postinstall.js +++ b/build/npm/postinstall.js
@@ -33,10 +33,11 @@ function yarnInstall(location, opts) { @@ -33,10 +33,11 @@ function yarnInstall(location, opts) {
@ -127,7 +153,7 @@ index 8f8b0019a77..ea054c725be 100644
cp.execSync('git config pull.rebase true'); cp.execSync('git config pull.rebase true');
diff --git a/build/npm/preinstall.js b/build/npm/preinstall.js diff --git a/build/npm/preinstall.js b/build/npm/preinstall.js
index cb88d37adef..6b3253af0a3 100644 index cb88d37adefd4882f61a2711fdd7f72b89e1a6e3..6b3253af0a3a0aa4d75456379ef1c00f4cb98d13 100644
--- a/build/npm/preinstall.js --- a/build/npm/preinstall.js
+++ b/build/npm/preinstall.js +++ b/build/npm/preinstall.js
@@ -8,8 +8,9 @@ let err = false; @@ -8,8 +8,9 @@ let err = false;
@ -144,10 +170,10 @@ index cb88d37adef..6b3253af0a3 100644
const cp = require('child_process'); const cp = require('child_process');
diff --git a/coder.js b/coder.js diff --git a/coder.js b/coder.js
new file mode 100644 new file mode 100644
index 00000000000..9cb693af63b index 0000000000000000000000000000000000000000..df5b42cba463b6c0043aebbc835f852f1284aa36
--- /dev/null --- /dev/null
+++ b/coder.js +++ b/coder.js
@@ -0,0 +1,63 @@ @@ -0,0 +1,64 @@
+// This must be ran from VS Code's root. +// This must be ran from VS Code's root.
+const gulp = require("gulp"); +const gulp = require("gulp");
+const path = require("path"); +const path = require("path");
@ -163,6 +189,7 @@ index 00000000000..9cb693af63b
+ buildfile.base, + buildfile.base,
+ buildfile.workbenchWeb, + buildfile.workbenchWeb,
+ buildfile.workerExtensionHost, + buildfile.workerExtensionHost,
+ buildfile.workerNotebook,
+ buildfile.keyboardMaps, + buildfile.keyboardMaps,
+ buildfile.entrypoint("vs/platform/files/node/watcher/unix/watcherApp", ["vs/css", "vs/nls"]), + buildfile.entrypoint("vs/platform/files/node/watcher/unix/watcherApp", ["vs/css", "vs/nls"]),
+ buildfile.entrypoint("vs/platform/files/node/watcher/nsfw/watcherApp", ["vs/css", "vs/nls"]), + buildfile.entrypoint("vs/platform/files/node/watcher/nsfw/watcherApp", ["vs/css", "vs/nls"]),
@ -212,7 +239,7 @@ index 00000000000..9cb693af63b
+ common.minifyTask("out-vscode") + common.minifyTask("out-vscode")
+)); +));
diff --git a/extensions/postinstall.js b/extensions/postinstall.js diff --git a/extensions/postinstall.js b/extensions/postinstall.js
index da4fa3e9d04..50f3e1144f8 100644 index da4fa3e9d0443d679dfbab1000b434af2ae01afd..50f3e1144f8057883dea8b91ec2f7073458dbd94 100644
--- a/extensions/postinstall.js --- a/extensions/postinstall.js
+++ b/extensions/postinstall.js +++ b/extensions/postinstall.js
@@ -24,6 +24,9 @@ function processRoot() { @@ -24,6 +24,9 @@ function processRoot() {
@ -226,10 +253,10 @@ index da4fa3e9d04..50f3e1144f8 100644
function processLib() { function processLib() {
diff --git a/package.json b/package.json diff --git a/package.json b/package.json
index 226f51a1ec5..5c4e5af5f69 100644 index 9b5ee0f876303283eb766fd2bb3ed818c50b1d3e..30ef9fa81b1cd844138388d794d4d6d9db5c7fba 100644
--- a/package.json --- a/package.json
+++ b/package.json +++ b/package.json
@@ -45,7 +45,11 @@ @@ -46,7 +46,11 @@
"watch-web": "gulp watch-web --max_old_space_size=4095", "watch-web": "gulp watch-web --max_old_space_size=4095",
"eslint": "eslint -c .eslintrc.json --rulesdir ./build/lib/eslint --ext .ts --ext .js ./src/vs ./extensions" "eslint": "eslint -c .eslintrc.json --rulesdir ./build/lib/eslint --ext .ts --ext .js ./src/vs ./extensions"
}, },
@ -241,15 +268,15 @@ index 226f51a1ec5..5c4e5af5f69 100644
"applicationinsights": "1.0.8", "applicationinsights": "1.0.8",
"chokidar": "3.2.3", "chokidar": "3.2.3",
"graceful-fs": "4.2.3", "graceful-fs": "4.2.3",
@@ -59,6 +63,7 @@ @@ -60,6 +64,7 @@
"native-keymap": "2.1.2", "native-keymap": "2.2.0",
"native-watchdog": "1.3.0", "native-watchdog": "1.3.0",
"node-pty": "0.10.0-beta8", "node-pty": "0.10.0-beta8",
+ "rimraf": "^2.2.8", + "rimraf": "^2.2.8",
"semver-umd": "^5.5.7", "semver-umd": "^5.5.7",
"spdlog": "^0.11.1", "spdlog": "^0.11.1",
"sudo-prompt": "9.1.1", "sudo-prompt": "9.1.1",
@@ -159,7 +164,6 @@ @@ -160,7 +165,6 @@
"pump": "^1.0.1", "pump": "^1.0.1",
"queue": "3.0.6", "queue": "3.0.6",
"rcedit": "^1.1.0", "rcedit": "^1.1.0",
@ -257,7 +284,7 @@ index 226f51a1ec5..5c4e5af5f69 100644
"sinon": "^1.17.2", "sinon": "^1.17.2",
"source-map": "^0.4.4", "source-map": "^0.4.4",
"style-loader": "^1.0.0", "style-loader": "^1.0.0",
@@ -190,5 +194,8 @@ @@ -192,5 +196,8 @@
"windows-foreground-love": "0.2.0", "windows-foreground-love": "0.2.0",
"windows-mutex": "0.3.0", "windows-mutex": "0.3.0",
"windows-process-tree": "0.2.4" "windows-process-tree": "0.2.4"
@ -267,7 +294,7 @@ index 226f51a1ec5..5c4e5af5f69 100644
} }
} }
diff --git a/product.json b/product.json diff --git a/product.json b/product.json
index 2b884d18f30..518b935b837 100644 index b9349015e3475bff07104ca2fa859954a37f962a..4c32260abc42efe17ee7d717e4dcebf182044e8c 100644
--- a/product.json --- a/product.json
+++ b/product.json +++ b/product.json
@@ -20,7 +20,7 @@ @@ -20,7 +20,7 @@
@ -281,18 +308,18 @@ index 2b884d18f30..518b935b837 100644
"ms-vscode.vscode-js-profile-flame", "ms-vscode.vscode-js-profile-flame",
diff --git a/remote/.yarnrc b/remote/.yarnrc diff --git a/remote/.yarnrc b/remote/.yarnrc
deleted file mode 100644 deleted file mode 100644
index 1e16cde724c..00000000000 index c1a32ce532afa501fb19bdbcf6bcb0ec151ecd99..0000000000000000000000000000000000000000
--- a/remote/.yarnrc --- a/remote/.yarnrc
+++ /dev/null +++ /dev/null
@@ -1,3 +0,0 @@ @@ -1,3 +0,0 @@
-disturl "http://nodejs.org/dist" -disturl "http://nodejs.org/dist"
-target "12.4.0" -target "12.14.1"
-runtime "node" -runtime "node"
diff --git a/src/vs/base/common/network.ts b/src/vs/base/common/network.ts diff --git a/src/vs/base/common/network.ts b/src/vs/base/common/network.ts
index 1286c5117a4..e60dd11d039 100644 index 4b6aebc16466dff58a9dfab4a680d230fa1f71a5..dd72e179ec0fa9a0b3e16e497225cb6da6218af3 100644
--- a/src/vs/base/common/network.ts --- a/src/vs/base/common/network.ts
+++ b/src/vs/base/common/network.ts +++ b/src/vs/base/common/network.ts
@@ -111,16 +111,17 @@ class RemoteAuthoritiesImpl { @@ -113,16 +113,17 @@ class RemoteAuthoritiesImpl {
if (host && host.indexOf(':') !== -1) { if (host && host.indexOf(':') !== -1) {
host = `[${host}]`; host = `[${host}]`;
} }
@ -314,7 +341,7 @@ index 1286c5117a4..e60dd11d039 100644
}); });
} }
diff --git a/src/vs/base/common/platform.ts b/src/vs/base/common/platform.ts diff --git a/src/vs/base/common/platform.ts b/src/vs/base/common/platform.ts
index 0bbc5d6ef91..61f139b9c55 100644 index 0bbc5d6ef911b1e98d26ad796873a9b6b7fb04ec..61f139b9c557b9c46e5a9640ab0e37a6fb7692ee 100644
--- a/src/vs/base/common/platform.ts --- a/src/vs/base/common/platform.ts
+++ b/src/vs/base/common/platform.ts +++ b/src/vs/base/common/platform.ts
@@ -59,6 +59,17 @@ if (typeof navigator === 'object' && !isElectronRenderer) { @@ -59,6 +59,17 @@ if (typeof navigator === 'object' && !isElectronRenderer) {
@ -336,7 +363,7 @@ index 0bbc5d6ef91..61f139b9c55 100644
_isWindows = (process.platform === 'win32'); _isWindows = (process.platform === 'win32');
_isMacintosh = (process.platform === 'darwin'); _isMacintosh = (process.platform === 'darwin');
diff --git a/src/vs/base/common/processes.ts b/src/vs/base/common/processes.ts diff --git a/src/vs/base/common/processes.ts b/src/vs/base/common/processes.ts
index c52f7b3774f..08a87fa970f 100644 index c52f7b3774f399d3fa161682316b20d807072806..08a87fa970f159f84691c5068cf5e38f0926015c 100644
--- a/src/vs/base/common/processes.ts --- a/src/vs/base/common/processes.ts
+++ b/src/vs/base/common/processes.ts +++ b/src/vs/base/common/processes.ts
@@ -110,7 +110,8 @@ export function sanitizeProcessEnvironment(env: IProcessEnvironment, ...preserve @@ -110,7 +110,8 @@ export function sanitizeProcessEnvironment(env: IProcessEnvironment, ...preserve
@ -350,7 +377,7 @@ index c52f7b3774f..08a87fa970f 100644
const envKeys = Object.keys(env); const envKeys = Object.keys(env);
envKeys envKeys
diff --git a/src/vs/base/common/uriIpc.ts b/src/vs/base/common/uriIpc.ts diff --git a/src/vs/base/common/uriIpc.ts b/src/vs/base/common/uriIpc.ts
index ef2291d49b1..29b2f9dfc2b 100644 index ef2291d49b13c9c995afc90eab9c92afabc2b3b4..29b2f9dfc2b7fa998ac1188db06dee95419fcd5b 100644
--- a/src/vs/base/common/uriIpc.ts --- a/src/vs/base/common/uriIpc.ts
+++ b/src/vs/base/common/uriIpc.ts +++ b/src/vs/base/common/uriIpc.ts
@@ -5,6 +5,7 @@ @@ -5,6 +5,7 @@
@ -416,7 +443,7 @@ index ef2291d49b1..29b2f9dfc2b 100644
\ No newline at end of file \ No newline at end of file
+} +}
diff --git a/src/vs/base/node/languagePacks.js b/src/vs/base/node/languagePacks.js diff --git a/src/vs/base/node/languagePacks.js b/src/vs/base/node/languagePacks.js
index 2c64061da7b..c0ef8faedd4 100644 index 2c64061da7b01aef0bfe3cec851da232ca9461c8..c0ef8faedd406c38bf9c55bbbdbbb060046492d9 100644
--- a/src/vs/base/node/languagePacks.js --- a/src/vs/base/node/languagePacks.js
+++ b/src/vs/base/node/languagePacks.js +++ b/src/vs/base/node/languagePacks.js
@@ -128,7 +128,10 @@ function factory(nodeRequire, path, fs, perf) { @@ -128,7 +128,10 @@ function factory(nodeRequire, path, fs, perf) {
@ -432,19 +459,18 @@ index 2c64061da7b..c0ef8faedd4 100644
// Do nothing. If we can't read the file we have no // Do nothing. If we can't read the file we have no
// language pack config. // language pack config.
diff --git a/src/vs/code/browser/workbench/workbench.ts b/src/vs/code/browser/workbench/workbench.ts diff --git a/src/vs/code/browser/workbench/workbench.ts b/src/vs/code/browser/workbench/workbench.ts
index c629f7fffa1..c266e1fb06f 100644 index ad5272b22320a361cec0eed40d57629b06147c01..c9280b14472507ebb9a277f554485f08b090cb69 100644
--- a/src/vs/code/browser/workbench/workbench.ts --- a/src/vs/code/browser/workbench/workbench.ts
+++ b/src/vs/code/browser/workbench/workbench.ts +++ b/src/vs/code/browser/workbench/workbench.ts
@@ -13,6 +13,8 @@ import { isFolderToOpen, isWorkspaceToOpen } from 'vs/platform/windows/common/wi @@ -16,6 +16,7 @@ import { isEqual } from 'vs/base/common/resources';
import { isEqual } from 'vs/base/common/resources';
import { isStandalone } from 'vs/base/browser/browser'; import { isStandalone } from 'vs/base/browser/browser';
import { localize } from 'vs/nls'; import { localize } from 'vs/nls';
+import { Schemas } from 'vs/base/common/network'; import { Schemas } from 'vs/base/common/network';
+import { encodePath } from 'vs/server/node/util'; +import { encodePath } from 'vs/server/node/util';
interface ICredential { interface ICredential {
service: string; service: string;
@@ -243,12 +245,18 @@ class WorkspaceProvider implements IWorkspaceProvider { @@ -253,12 +254,18 @@ class WorkspaceProvider implements IWorkspaceProvider {
// Folder // Folder
else if (isFolderToOpen(workspace)) { else if (isFolderToOpen(workspace)) {
@ -465,7 +491,7 @@ index c629f7fffa1..c266e1fb06f 100644
} }
// Append payload if any // Append payload if any
@@ -285,7 +293,22 @@ class WorkspaceProvider implements IWorkspaceProvider { @@ -348,7 +355,22 @@ class WindowIndicator implements IWindowIndicator {
throw new Error('Missing web configuration element'); throw new Error('Missing web configuration element');
} }
@ -489,7 +515,7 @@ index c629f7fffa1..c266e1fb06f 100644
// Revive static extension locations // Revive static extension locations
if (Array.isArray(config.staticExtensions)) { if (Array.isArray(config.staticExtensions)) {
@@ -297,40 +320,7 @@ class WorkspaceProvider implements IWorkspaceProvider { @@ -360,40 +382,7 @@ class WindowIndicator implements IWindowIndicator {
// Find workspace to open and payload // Find workspace to open and payload
let foundWorkspace = false; let foundWorkspace = false;
let workspace: IWorkspace; let workspace: IWorkspace;
@ -532,7 +558,7 @@ index c629f7fffa1..c266e1fb06f 100644
// If no workspace is provided through the URL, check for config attribute from server // If no workspace is provided through the URL, check for config attribute from server
if (!foundWorkspace) { if (!foundWorkspace) {
diff --git a/src/vs/platform/environment/node/argv.ts b/src/vs/platform/environment/node/argv.ts diff --git a/src/vs/platform/environment/node/argv.ts b/src/vs/platform/environment/node/argv.ts
index 2379b626c81..28f8971cf39 100644 index 92dd2bcf87dba5e5f07f2707a91b1a364ab1b05f..047522bd1a2c1edfda05c3739838fecbd70db6c5 100644
--- a/src/vs/platform/environment/node/argv.ts --- a/src/vs/platform/environment/node/argv.ts
+++ b/src/vs/platform/environment/node/argv.ts +++ b/src/vs/platform/environment/node/argv.ts
@@ -8,6 +8,8 @@ import { localize } from 'vs/nls'; @@ -8,6 +8,8 @@ import { localize } from 'vs/nls';
@ -544,7 +570,7 @@ index 2379b626c81..28f8971cf39 100644
_: string[]; _: string[];
'folder-uri'?: string[]; // undefined or array of 1 or more 'folder-uri'?: string[]; // undefined or array of 1 or more
'file-uri'?: string[]; // undefined or array of 1 or more 'file-uri'?: string[]; // undefined or array of 1 or more
@@ -141,6 +143,8 @@ export const OPTIONS: OptionDescriptions<Required<ParsedArgs>> = { @@ -142,6 +144,8 @@ export const OPTIONS: OptionDescriptions<Required<ParsedArgs>> = {
'extensions-dir': { type: 'string', deprecates: 'extensionHomePath', cat: 'e', args: 'dir', description: localize('extensionHomePath', "Set the root path for extensions.") }, 'extensions-dir': { type: 'string', deprecates: 'extensionHomePath', cat: 'e', args: 'dir', description: localize('extensionHomePath', "Set the root path for extensions.") },
'extensions-download-dir': { type: 'string' }, 'extensions-download-dir': { type: 'string' },
'builtin-extensions-dir': { type: 'string' }, 'builtin-extensions-dir': { type: 'string' },
@ -553,13 +579,13 @@ index 2379b626c81..28f8971cf39 100644
'list-extensions': { type: 'boolean', cat: 'e', description: localize('listExtensions', "List the installed extensions.") }, 'list-extensions': { type: 'boolean', cat: 'e', description: localize('listExtensions', "List the installed extensions.") },
'show-versions': { type: 'boolean', cat: 'e', description: localize('showVersions', "Show versions of installed extensions, when using --list-extension.") }, 'show-versions': { type: 'boolean', cat: 'e', description: localize('showVersions', "Show versions of installed extensions, when using --list-extension.") },
'category': { type: 'string', cat: 'e', description: localize('category', "Filters installed extensions by provided category, when using --list-extension.") }, 'category': { type: 'string', cat: 'e', description: localize('category', "Filters installed extensions by provided category, when using --list-extension.") },
@@ -403,4 +407,3 @@ export function buildHelpMessage(productName: string, executableName: string, ve @@ -405,4 +409,3 @@ export function buildHelpMessage(productName: string, executableName: string, ve
export function buildVersionMessage(version: string | undefined, commit: string | undefined): string { export function buildVersionMessage(version: string | undefined, commit: string | undefined): string {
return `${version || localize('unknownVersion', "Unknown version")}\n${commit || localize('unknownCommit', "Unknown commit")}\n${process.arch}`; return `${version || localize('unknownVersion', "Unknown version")}\n${commit || localize('unknownCommit', "Unknown commit")}\n${process.arch}`;
} }
- -
diff --git a/src/vs/platform/environment/node/environmentService.ts b/src/vs/platform/environment/node/environmentService.ts diff --git a/src/vs/platform/environment/node/environmentService.ts b/src/vs/platform/environment/node/environmentService.ts
index 5c0dc4ad4ae..38b8c7573a8 100644 index 45d5ec2cc02707d91f19a66d408ae46a1201a9e8..4ed498c63ceb55d15bd104a92b701ead3dfa81f2 100644
--- a/src/vs/platform/environment/node/environmentService.ts --- a/src/vs/platform/environment/node/environmentService.ts
+++ b/src/vs/platform/environment/node/environmentService.ts +++ b/src/vs/platform/environment/node/environmentService.ts
@@ -38,6 +38,8 @@ export interface INativeEnvironmentService extends IEnvironmentService { @@ -38,6 +38,8 @@ export interface INativeEnvironmentService extends IEnvironmentService {
@ -586,7 +612,7 @@ index 5c0dc4ad4ae..38b8c7573a8 100644
get extensionDevelopmentLocationURI(): URI[] | undefined { get extensionDevelopmentLocationURI(): URI[] | undefined {
const s = this._args.extensionDevelopmentPath; const s = this._args.extensionDevelopmentPath;
diff --git a/src/vs/platform/extensionManagement/node/extensionsScanner.ts b/src/vs/platform/extensionManagement/node/extensionsScanner.ts diff --git a/src/vs/platform/extensionManagement/node/extensionsScanner.ts b/src/vs/platform/extensionManagement/node/extensionsScanner.ts
index 575b2aafc38..873181f9678 100644 index 575b2aafc3802cd6f5f943930e30de9f2c2690de..873181f967856759e3dc001e5bbe06e2f9eb676a 100644
--- a/src/vs/platform/extensionManagement/node/extensionsScanner.ts --- a/src/vs/platform/extensionManagement/node/extensionsScanner.ts
+++ b/src/vs/platform/extensionManagement/node/extensionsScanner.ts +++ b/src/vs/platform/extensionManagement/node/extensionsScanner.ts
@@ -85,7 +85,7 @@ export class ExtensionsScanner extends Disposable { @@ -85,7 +85,7 @@ export class ExtensionsScanner extends Disposable {
@ -633,7 +659,7 @@ index 575b2aafc38..873181f9678 100644
+ } + }
} }
diff --git a/src/vs/platform/product/common/product.ts b/src/vs/platform/product/common/product.ts diff --git a/src/vs/platform/product/common/product.ts b/src/vs/platform/product/common/product.ts
index 3370a608b4b..37b3592d39d 100644 index bb33203d1727b1c076efac9113afc3b2580cdbd9..c53cea338cdaa0f0ac15542c129e1572b3f13b80 100644
--- a/src/vs/platform/product/common/product.ts --- a/src/vs/platform/product/common/product.ts
+++ b/src/vs/platform/product/common/product.ts +++ b/src/vs/platform/product/common/product.ts
@@ -30,6 +30,12 @@ if (isWeb) { @@ -30,6 +30,12 @@ if (isWeb) {
@ -650,7 +676,7 @@ index 3370a608b4b..37b3592d39d 100644
// Node: AMD loader // Node: AMD loader
diff --git a/src/vs/platform/product/common/productService.ts b/src/vs/platform/product/common/productService.ts diff --git a/src/vs/platform/product/common/productService.ts b/src/vs/platform/product/common/productService.ts
index 040c869d94c..bf16defcf7b 100644 index d1cb00a6d63621a4873a6a5e815220d084ceac2a..1a69d6f63a7406d364aa3e2b32fb75309f212e98 100644
--- a/src/vs/platform/product/common/productService.ts --- a/src/vs/platform/product/common/productService.ts
+++ b/src/vs/platform/product/common/productService.ts +++ b/src/vs/platform/product/common/productService.ts
@@ -30,6 +30,8 @@ export type ConfigurationSyncStore = { @@ -30,6 +30,8 @@ export type ConfigurationSyncStore = {
@ -663,7 +689,7 @@ index 040c869d94c..bf16defcf7b 100644
readonly date?: string; readonly date?: string;
readonly quality?: string; readonly quality?: string;
diff --git a/src/vs/platform/remote/browser/browserSocketFactory.ts b/src/vs/platform/remote/browser/browserSocketFactory.ts diff --git a/src/vs/platform/remote/browser/browserSocketFactory.ts b/src/vs/platform/remote/browser/browserSocketFactory.ts
index 3715cbb8e6e..c65de8ad37e 100644 index 3715cbb8e6ee41c3d9b5090918d243b723ae2d00..c65de8ad37e727d66da97a8f8b170cbcef87181b 100644
--- a/src/vs/platform/remote/browser/browserSocketFactory.ts --- a/src/vs/platform/remote/browser/browserSocketFactory.ts
+++ b/src/vs/platform/remote/browser/browserSocketFactory.ts +++ b/src/vs/platform/remote/browser/browserSocketFactory.ts
@@ -208,7 +208,8 @@ export class BrowserSocketFactory implements ISocketFactory { @@ -208,7 +208,8 @@ export class BrowserSocketFactory implements ISocketFactory {
@ -684,10 +710,10 @@ index 3715cbb8e6e..c65de8ad37e 100644
- -
- -
diff --git a/src/vs/platform/remote/common/remoteAgentConnection.ts b/src/vs/platform/remote/common/remoteAgentConnection.ts diff --git a/src/vs/platform/remote/common/remoteAgentConnection.ts b/src/vs/platform/remote/common/remoteAgentConnection.ts
index 2185bb5228c..35463ca6520 100644 index 18d3d04fd20335975293e37b3b641120dd92da20..4e49f9d63623da6c84624144765f76ec127ea526 100644
--- a/src/vs/platform/remote/common/remoteAgentConnection.ts --- a/src/vs/platform/remote/common/remoteAgentConnection.ts
+++ b/src/vs/platform/remote/common/remoteAgentConnection.ts +++ b/src/vs/platform/remote/common/remoteAgentConnection.ts
@@ -89,7 +89,7 @@ async function connectToRemoteExtensionHostAgent(options: ISimpleConnectionOptio @@ -92,7 +92,7 @@ async function connectToRemoteExtensionHostAgent(options: ISimpleConnectionOptio
options.socketFactory.connect( options.socketFactory.connect(
options.host, options.host,
options.port, options.port,
@ -696,9 +722,52 @@ index 2185bb5228c..35463ca6520 100644
(err: any, socket: ISocket | undefined) => { (err: any, socket: ISocket | undefined) => {
if (err || !socket) { if (err || !socket) {
options.logService.error(`${logPrefix} socketFactory.connect() failed. Error:`); options.logService.error(`${logPrefix} socketFactory.connect() failed. Error:`);
diff --git a/src/vs/platform/storage/browser/storageService.ts b/src/vs/platform/storage/browser/storageService.ts
index ab3fd347b69f8a3d9b96e706cd87c911b8ffed6b..9d351037b577f9f1edfd18ae9b3c48a211f4467f 100644
--- a/src/vs/platform/storage/browser/storageService.ts
+++ b/src/vs/platform/storage/browser/storageService.ts
@@ -122,8 +122,8 @@ export class BrowserStorageService extends Disposable implements IStorageService
return this.getStorage(scope).getNumber(key, fallbackValue);
}
- store(key: string, value: string | boolean | number | undefined | null, scope: StorageScope): void {
- this.getStorage(scope).set(key, value);
+ store(key: string, value: string | boolean | number | undefined | null, scope: StorageScope): Promise<void> {
+ return this.getStorage(scope).set(key, value);
}
remove(key: string, scope: StorageScope): void {
diff --git a/src/vs/platform/storage/common/storage.ts b/src/vs/platform/storage/common/storage.ts
index 6611f1dae42055f69a55c1c154d9475f11cd4d0a..d598d4909d5ff6d1614e4a038b1865e1f9a4e963 100644
--- a/src/vs/platform/storage/common/storage.ts
+++ b/src/vs/platform/storage/common/storage.ts
@@ -85,7 +85,7 @@ export interface IStorageService {
* The scope argument allows to define the scope of the storage
* operation to either the current workspace only or all workspaces.
*/
- store(key: string, value: string | boolean | number | undefined | null, scope: StorageScope): void;
+ store(key: string, value: string | boolean | number | undefined | null, scope: StorageScope): Promise<void> | void;
/**
* Delete an element stored under the provided key from storage.
diff --git a/src/vs/platform/storage/node/storageService.ts b/src/vs/platform/storage/node/storageService.ts
index ac657056aa68549f0053cfb1ec68835ba4ce20f9..143f9b5681eb867c5e5c5437946ab785eb34e4b4 100644
--- a/src/vs/platform/storage/node/storageService.ts
+++ b/src/vs/platform/storage/node/storageService.ts
@@ -202,8 +202,8 @@ export class NativeStorageService extends Disposable implements IStorageService
return this.getStorage(scope).getNumber(key, fallbackValue);
}
- store(key: string, value: string | boolean | number | undefined | null, scope: StorageScope): void {
- this.getStorage(scope).set(key, value);
+ store(key: string, value: string | boolean | number | undefined | null, scope: StorageScope): Promise<void> {
+ return this.getStorage(scope).set(key, value);
}
remove(key: string, scope: StorageScope): void {
diff --git a/src/vs/server/browser/client.ts b/src/vs/server/browser/client.ts diff --git a/src/vs/server/browser/client.ts b/src/vs/server/browser/client.ts
new file mode 100644 new file mode 100644
index 00000000000..3c0703b7174 index 0000000000000000000000000000000000000000..3c0703b7174ad792a4b42841e96ee93765d71601
--- /dev/null --- /dev/null
+++ b/src/vs/server/browser/client.ts +++ b/src/vs/server/browser/client.ts
@@ -0,0 +1,189 @@ @@ -0,0 +1,189 @@
@ -893,7 +962,7 @@ index 00000000000..3c0703b7174
+}; +};
diff --git a/src/vs/server/browser/extHostNodeProxy.ts b/src/vs/server/browser/extHostNodeProxy.ts diff --git a/src/vs/server/browser/extHostNodeProxy.ts b/src/vs/server/browser/extHostNodeProxy.ts
new file mode 100644 new file mode 100644
index 00000000000..ed7c078077b index 0000000000000000000000000000000000000000..ed7c078077b0c375758529959b280e091436113a
--- /dev/null --- /dev/null
+++ b/src/vs/server/browser/extHostNodeProxy.ts +++ b/src/vs/server/browser/extHostNodeProxy.ts
@@ -0,0 +1,46 @@ @@ -0,0 +1,46 @@
@ -945,7 +1014,7 @@ index 00000000000..ed7c078077b
+export const IExtHostNodeProxy = createDecorator<IExtHostNodeProxy>('IExtHostNodeProxy'); +export const IExtHostNodeProxy = createDecorator<IExtHostNodeProxy>('IExtHostNodeProxy');
diff --git a/src/vs/server/browser/mainThreadNodeProxy.ts b/src/vs/server/browser/mainThreadNodeProxy.ts diff --git a/src/vs/server/browser/mainThreadNodeProxy.ts b/src/vs/server/browser/mainThreadNodeProxy.ts
new file mode 100644 new file mode 100644
index 00000000000..0d2e93edae2 index 0000000000000000000000000000000000000000..0d2e93edae2baf34d27b7b52be0bf4960f244531
--- /dev/null --- /dev/null
+++ b/src/vs/server/browser/mainThreadNodeProxy.ts +++ b/src/vs/server/browser/mainThreadNodeProxy.ts
@@ -0,0 +1,37 @@ @@ -0,0 +1,37 @@
@ -988,7 +1057,7 @@ index 00000000000..0d2e93edae2
+} +}
diff --git a/src/vs/server/browser/worker.ts b/src/vs/server/browser/worker.ts diff --git a/src/vs/server/browser/worker.ts b/src/vs/server/browser/worker.ts
new file mode 100644 new file mode 100644
index 00000000000..5ae44cdc856 index 0000000000000000000000000000000000000000..5ae44cdc856bf81326a4c516b8be9afb2c746a67
--- /dev/null --- /dev/null
+++ b/src/vs/server/browser/worker.ts +++ b/src/vs/server/browser/worker.ts
@@ -0,0 +1,56 @@ @@ -0,0 +1,56 @@
@ -1050,7 +1119,7 @@ index 00000000000..5ae44cdc856
+}; +};
diff --git a/src/vs/server/common/nodeProxy.ts b/src/vs/server/common/nodeProxy.ts diff --git a/src/vs/server/common/nodeProxy.ts b/src/vs/server/common/nodeProxy.ts
new file mode 100644 new file mode 100644
index 00000000000..14b9de879ce index 0000000000000000000000000000000000000000..14b9de879ceab4c1976770fa7810d276c5aa3e36
--- /dev/null --- /dev/null
+++ b/src/vs/server/common/nodeProxy.ts +++ b/src/vs/server/common/nodeProxy.ts
@@ -0,0 +1,47 @@ @@ -0,0 +1,47 @@
@ -1103,7 +1172,7 @@ index 00000000000..14b9de879ce
+} +}
diff --git a/src/vs/server/common/telemetry.ts b/src/vs/server/common/telemetry.ts diff --git a/src/vs/server/common/telemetry.ts b/src/vs/server/common/telemetry.ts
new file mode 100644 new file mode 100644
index 00000000000..4ea6d95d36a index 0000000000000000000000000000000000000000..4ea6d95d36aaac07dbd4d0e16ab3c1bba255f683
--- /dev/null --- /dev/null
+++ b/src/vs/server/common/telemetry.ts +++ b/src/vs/server/common/telemetry.ts
@@ -0,0 +1,65 @@ @@ -0,0 +1,65 @@
@ -1174,7 +1243,7 @@ index 00000000000..4ea6d95d36a
+} +}
diff --git a/src/vs/server/entry.ts b/src/vs/server/entry.ts diff --git a/src/vs/server/entry.ts b/src/vs/server/entry.ts
new file mode 100644 new file mode 100644
index 00000000000..ab020fbb4e4 index 0000000000000000000000000000000000000000..ab020fbb4e4ab3748cc807765ff9c362389faafa
--- /dev/null --- /dev/null
+++ b/src/vs/server/entry.ts +++ b/src/vs/server/entry.ts
@@ -0,0 +1,78 @@ @@ -0,0 +1,78 @@
@ -1258,7 +1327,7 @@ index 00000000000..ab020fbb4e4
+} +}
diff --git a/src/vs/server/fork.js b/src/vs/server/fork.js diff --git a/src/vs/server/fork.js b/src/vs/server/fork.js
new file mode 100644 new file mode 100644
index 00000000000..56331ff1fc3 index 0000000000000000000000000000000000000000..56331ff1fc32bbd82e769aaecb551e427f798ec3
--- /dev/null --- /dev/null
+++ b/src/vs/server/fork.js +++ b/src/vs/server/fork.js
@@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
@ -1267,7 +1336,7 @@ index 00000000000..56331ff1fc3
+require('../../bootstrap-amd').load('vs/server/entry'); +require('../../bootstrap-amd').load('vs/server/entry');
diff --git a/src/vs/server/ipc.d.ts b/src/vs/server/ipc.d.ts diff --git a/src/vs/server/ipc.d.ts b/src/vs/server/ipc.d.ts
new file mode 100644 new file mode 100644
index 00000000000..33b28cf2d53 index 0000000000000000000000000000000000000000..33b28cf2d53746ee9c50c056ac2e087dcee0a4e2
--- /dev/null --- /dev/null
+++ b/src/vs/server/ipc.d.ts +++ b/src/vs/server/ipc.d.ts
@@ -0,0 +1,131 @@ @@ -0,0 +1,131 @@
@ -1404,7 +1473,7 @@ index 00000000000..33b28cf2d53
+} +}
diff --git a/src/vs/server/node/channel.ts b/src/vs/server/node/channel.ts diff --git a/src/vs/server/node/channel.ts b/src/vs/server/node/channel.ts
new file mode 100644 new file mode 100644
index 00000000000..e10cc9c218b index 0000000000000000000000000000000000000000..e10cc9c218b27d859a523be3db5b8a30ef90d953
--- /dev/null --- /dev/null
+++ b/src/vs/server/node/channel.ts +++ b/src/vs/server/node/channel.ts
@@ -0,0 +1,360 @@ @@ -0,0 +1,360 @@
@ -1770,7 +1839,7 @@ index 00000000000..e10cc9c218b
+} +}
diff --git a/src/vs/server/node/connection.ts b/src/vs/server/node/connection.ts diff --git a/src/vs/server/node/connection.ts b/src/vs/server/node/connection.ts
new file mode 100644 new file mode 100644
index 00000000000..36e80fb6966 index 0000000000000000000000000000000000000000..36e80fb6966ae2cb53c98f3d31e2193d00c509c3
--- /dev/null --- /dev/null
+++ b/src/vs/server/node/connection.ts +++ b/src/vs/server/node/connection.ts
@@ -0,0 +1,157 @@ @@ -0,0 +1,157 @@
@ -1933,7 +2002,7 @@ index 00000000000..36e80fb6966
+} +}
diff --git a/src/vs/server/node/insights.ts b/src/vs/server/node/insights.ts diff --git a/src/vs/server/node/insights.ts b/src/vs/server/node/insights.ts
new file mode 100644 new file mode 100644
index 00000000000..a0ece345f28 index 0000000000000000000000000000000000000000..a0ece345f28f06afb2af12fe4901ad228b2475a4
--- /dev/null --- /dev/null
+++ b/src/vs/server/node/insights.ts +++ b/src/vs/server/node/insights.ts
@@ -0,0 +1,124 @@ @@ -0,0 +1,124 @@
@ -2063,7 +2132,7 @@ index 00000000000..a0ece345f28
+} +}
diff --git a/src/vs/server/node/ipc.ts b/src/vs/server/node/ipc.ts diff --git a/src/vs/server/node/ipc.ts b/src/vs/server/node/ipc.ts
new file mode 100644 new file mode 100644
index 00000000000..5e560eb46e6 index 0000000000000000000000000000000000000000..5e560eb46e6a0a18c91e440c655ac0d44b09b6dd
--- /dev/null --- /dev/null
+++ b/src/vs/server/node/ipc.ts +++ b/src/vs/server/node/ipc.ts
@@ -0,0 +1,61 @@ @@ -0,0 +1,61 @@
@ -2130,7 +2199,7 @@ index 00000000000..5e560eb46e6
+export const ipcMain = new IpcMain(); +export const ipcMain = new IpcMain();
diff --git a/src/vs/server/node/logger.ts b/src/vs/server/node/logger.ts diff --git a/src/vs/server/node/logger.ts b/src/vs/server/node/logger.ts
new file mode 100644 new file mode 100644
index 00000000000..2a39c524aaa index 0000000000000000000000000000000000000000..2a39c524aaa1b4031e04a631842f30b6fec3d98a
--- /dev/null --- /dev/null
+++ b/src/vs/server/node/logger.ts +++ b/src/vs/server/node/logger.ts
@@ -0,0 +1,2 @@ @@ -0,0 +1,2 @@
@ -2138,7 +2207,7 @@ index 00000000000..2a39c524aaa
+export const logger = baseLogger.named('vscode'); +export const logger = baseLogger.named('vscode');
diff --git a/src/vs/server/node/marketplace.ts b/src/vs/server/node/marketplace.ts diff --git a/src/vs/server/node/marketplace.ts b/src/vs/server/node/marketplace.ts
new file mode 100644 new file mode 100644
index 00000000000..8956fc40d48 index 0000000000000000000000000000000000000000..8956fc40d48448b9932036c4c286464881807338
--- /dev/null --- /dev/null
+++ b/src/vs/server/node/marketplace.ts +++ b/src/vs/server/node/marketplace.ts
@@ -0,0 +1,174 @@ @@ -0,0 +1,174 @@
@ -2318,7 +2387,7 @@ index 00000000000..8956fc40d48
+}; +};
diff --git a/src/vs/server/node/nls.ts b/src/vs/server/node/nls.ts diff --git a/src/vs/server/node/nls.ts b/src/vs/server/node/nls.ts
new file mode 100644 new file mode 100644
index 00000000000..3d428a57d31 index 0000000000000000000000000000000000000000..3d428a57d31f29c40f9c3ce45f715b443badf4e9
--- /dev/null --- /dev/null
+++ b/src/vs/server/node/nls.ts +++ b/src/vs/server/node/nls.ts
@@ -0,0 +1,88 @@ @@ -0,0 +1,88 @@
@ -2412,7 +2481,7 @@ index 00000000000..3d428a57d31
+}; +};
diff --git a/src/vs/server/node/protocol.ts b/src/vs/server/node/protocol.ts diff --git a/src/vs/server/node/protocol.ts b/src/vs/server/node/protocol.ts
new file mode 100644 new file mode 100644
index 00000000000..3c74512192a index 0000000000000000000000000000000000000000..3c74512192aec6220216bc8563b3127b9cfd5fbf
--- /dev/null --- /dev/null
+++ b/src/vs/server/node/protocol.ts +++ b/src/vs/server/node/protocol.ts
@@ -0,0 +1,73 @@ @@ -0,0 +1,73 @@
@ -2491,7 +2560,7 @@ index 00000000000..3c74512192a
+} +}
diff --git a/src/vs/server/node/server.ts b/src/vs/server/node/server.ts diff --git a/src/vs/server/node/server.ts b/src/vs/server/node/server.ts
new file mode 100644 new file mode 100644
index 00000000000..4b88fedb2f0 index 0000000000000000000000000000000000000000..4b88fedb2f05d300fb50978e63721d4d04b7fb5f
--- /dev/null --- /dev/null
+++ b/src/vs/server/node/server.ts +++ b/src/vs/server/node/server.ts
@@ -0,0 +1,285 @@ @@ -0,0 +1,285 @@
@ -2782,7 +2851,7 @@ index 00000000000..4b88fedb2f0
+} +}
diff --git a/src/vs/server/node/util.ts b/src/vs/server/node/util.ts diff --git a/src/vs/server/node/util.ts b/src/vs/server/node/util.ts
new file mode 100644 new file mode 100644
index 00000000000..fa47e993b46 index 0000000000000000000000000000000000000000..fa47e993b46802f1a26457649e9e8bc467a73bf2
--- /dev/null --- /dev/null
+++ b/src/vs/server/node/util.ts +++ b/src/vs/server/node/util.ts
@@ -0,0 +1,13 @@ @@ -0,0 +1,13 @@
@ -2800,7 +2869,7 @@ index 00000000000..fa47e993b46
+ return path.split("/").map((p) => encodeURIComponent(p)).join("/"); + return path.split("/").map((p) => encodeURIComponent(p)).join("/");
+}; +};
diff --git a/src/vs/workbench/api/browser/extensionHost.contribution.ts b/src/vs/workbench/api/browser/extensionHost.contribution.ts diff --git a/src/vs/workbench/api/browser/extensionHost.contribution.ts b/src/vs/workbench/api/browser/extensionHost.contribution.ts
index 3d77009b908..11deb1b99ac 100644 index bfabf0008910c87146df53a2e10fe63bae517a86..32b3b1cf84c8d280fd7f03d541b867691d51c2fb 100644
--- a/src/vs/workbench/api/browser/extensionHost.contribution.ts --- a/src/vs/workbench/api/browser/extensionHost.contribution.ts
+++ b/src/vs/workbench/api/browser/extensionHost.contribution.ts +++ b/src/vs/workbench/api/browser/extensionHost.contribution.ts
@@ -60,6 +60,7 @@ import './mainThreadComments'; @@ -60,6 +60,7 @@ import './mainThreadComments';
@ -2811,8 +2880,26 @@ index 3d77009b908..11deb1b99ac 100644
import './mainThreadTunnelService'; import './mainThreadTunnelService';
import './mainThreadAuthentication'; import './mainThreadAuthentication';
import './mainThreadTimeline'; import './mainThreadTimeline';
diff --git a/src/vs/workbench/api/browser/mainThreadStorage.ts b/src/vs/workbench/api/browser/mainThreadStorage.ts
index 7bc3904963bed2925f3640b6bd929347159dd3cf..c6db2368ae9eaca61889efcf3c49763c01ff7459 100644
--- a/src/vs/workbench/api/browser/mainThreadStorage.ts
+++ b/src/vs/workbench/api/browser/mainThreadStorage.ts
@@ -58,11 +58,11 @@ export class MainThreadStorage implements MainThreadStorageShape {
return JSON.parse(jsonValue);
}
- $setValue(shared: boolean, key: string, value: object): Promise<void> {
+ async $setValue(shared: boolean, key: string, value: object): Promise<void> {
let jsonValue: string;
try {
jsonValue = JSON.stringify(value);
- this._storageService.store(key, jsonValue, shared ? StorageScope.GLOBAL : StorageScope.WORKSPACE);
+ await this._storageService.store(key, jsonValue, shared ? StorageScope.GLOBAL : StorageScope.WORKSPACE);
} catch (err) {
return Promise.reject(err);
}
diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts
index 97793666ad8..13cd137db1e 100644 index 3595cd3e38136222044a13050b15105bbe539068..989caefff7c4b8203c03cec8fa451f5e70ea8964 100644
--- a/src/vs/workbench/api/common/extHost.api.impl.ts --- a/src/vs/workbench/api/common/extHost.api.impl.ts
+++ b/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.ts
@@ -68,6 +68,7 @@ import { IURITransformerService } from 'vs/workbench/api/common/extHostUriTransf @@ -68,6 +68,7 @@ import { IURITransformerService } from 'vs/workbench/api/common/extHostUriTransf
@ -2823,7 +2910,7 @@ index 97793666ad8..13cd137db1e 100644
import { ExtHostTheming } from 'vs/workbench/api/common/extHostTheming'; import { ExtHostTheming } from 'vs/workbench/api/common/extHostTheming';
import { IExtHostTunnelService } from 'vs/workbench/api/common/extHostTunnelService'; import { IExtHostTunnelService } from 'vs/workbench/api/common/extHostTunnelService';
import { IExtHostApiDeprecationService } from 'vs/workbench/api/common/extHostApiDeprecationService'; import { IExtHostApiDeprecationService } from 'vs/workbench/api/common/extHostApiDeprecationService';
@@ -97,6 +98,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I @@ -100,6 +101,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
const extHostStorage = accessor.get(IExtHostStorage); const extHostStorage = accessor.get(IExtHostStorage);
const extensionStoragePaths = accessor.get(IExtensionStoragePaths); const extensionStoragePaths = accessor.get(IExtensionStoragePaths);
const extHostLogService = accessor.get(ILogService); const extHostLogService = accessor.get(ILogService);
@ -2831,7 +2918,7 @@ index 97793666ad8..13cd137db1e 100644
const extHostTunnelService = accessor.get(IExtHostTunnelService); const extHostTunnelService = accessor.get(IExtHostTunnelService);
const extHostApiDeprecation = accessor.get(IExtHostApiDeprecationService); const extHostApiDeprecation = accessor.get(IExtHostApiDeprecationService);
const extHostWindow = accessor.get(IExtHostWindow); const extHostWindow = accessor.get(IExtHostWindow);
@@ -107,6 +109,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I @@ -110,6 +112,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
rpcProtocol.set(ExtHostContext.ExtHostConfiguration, extHostConfiguration); rpcProtocol.set(ExtHostContext.ExtHostConfiguration, extHostConfiguration);
rpcProtocol.set(ExtHostContext.ExtHostExtensionService, extensionService); rpcProtocol.set(ExtHostContext.ExtHostExtensionService, extensionService);
rpcProtocol.set(ExtHostContext.ExtHostStorage, extHostStorage); rpcProtocol.set(ExtHostContext.ExtHostStorage, extHostStorage);
@ -2840,10 +2927,10 @@ index 97793666ad8..13cd137db1e 100644
rpcProtocol.set(ExtHostContext.ExtHostWindow, extHostWindow); rpcProtocol.set(ExtHostContext.ExtHostWindow, extHostWindow);
diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts
index eb5d8ea8455..da9eb521ca4 100644 index 4b7946662950f18179a5b6e3552abd39e68ca80e..ca1352d311a94b42e18d0d9e4859b18ec2bb271d 100644
--- a/src/vs/workbench/api/common/extHost.protocol.ts --- a/src/vs/workbench/api/common/extHost.protocol.ts
+++ b/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts
@@ -769,6 +769,16 @@ export interface MainThreadLabelServiceShape extends IDisposable { @@ -795,6 +795,16 @@ export interface MainThreadLabelServiceShape extends IDisposable {
$unregisterResourceLabelFormatter(handle: number): void; $unregisterResourceLabelFormatter(handle: number): void;
} }
@ -2860,7 +2947,7 @@ index eb5d8ea8455..da9eb521ca4 100644
export interface MainThreadSearchShape extends IDisposable { export interface MainThreadSearchShape extends IDisposable {
$registerFileSearchProvider(handle: number, scheme: string): void; $registerFileSearchProvider(handle: number, scheme: string): void;
$registerTextSearchProvider(handle: number, scheme: string): void; $registerTextSearchProvider(handle: number, scheme: string): void;
@@ -1707,6 +1717,7 @@ export const MainContext = { @@ -1765,6 +1775,7 @@ export const MainContext = {
MainThreadWindow: createMainId<MainThreadWindowShape>('MainThreadWindow'), MainThreadWindow: createMainId<MainThreadWindowShape>('MainThreadWindow'),
MainThreadLabelService: createMainId<MainThreadLabelServiceShape>('MainThreadLabelService'), MainThreadLabelService: createMainId<MainThreadLabelServiceShape>('MainThreadLabelService'),
MainThreadNotebook: createMainId<MainThreadNotebookShape>('MainThreadNotebook'), MainThreadNotebook: createMainId<MainThreadNotebookShape>('MainThreadNotebook'),
@ -2868,7 +2955,7 @@ index eb5d8ea8455..da9eb521ca4 100644
MainThreadTheming: createMainId<MainThreadThemingShape>('MainThreadTheming'), MainThreadTheming: createMainId<MainThreadThemingShape>('MainThreadTheming'),
MainThreadTunnelService: createMainId<MainThreadTunnelServiceShape>('MainThreadTunnelService'), MainThreadTunnelService: createMainId<MainThreadTunnelServiceShape>('MainThreadTunnelService'),
MainThreadTimeline: createMainId<MainThreadTimelineShape>('MainThreadTimeline') MainThreadTimeline: createMainId<MainThreadTimelineShape>('MainThreadTimeline')
@@ -1745,6 +1756,7 @@ export const ExtHostContext = { @@ -1806,6 +1817,7 @@ export const ExtHostContext = {
ExtHostOutputService: createMainId<ExtHostOutputServiceShape>('ExtHostOutputService'), ExtHostOutputService: createMainId<ExtHostOutputServiceShape>('ExtHostOutputService'),
ExtHosLabelService: createMainId<ExtHostLabelServiceShape>('ExtHostLabelService'), ExtHosLabelService: createMainId<ExtHostLabelServiceShape>('ExtHostLabelService'),
ExtHostNotebook: createMainId<ExtHostNotebookShape>('ExtHostNotebook'), ExtHostNotebook: createMainId<ExtHostNotebookShape>('ExtHostNotebook'),
@ -2877,10 +2964,10 @@ index eb5d8ea8455..da9eb521ca4 100644
ExtHostTunnelService: createMainId<ExtHostTunnelServiceShape>('ExtHostTunnelService'), ExtHostTunnelService: createMainId<ExtHostTunnelServiceShape>('ExtHostTunnelService'),
ExtHostAuthentication: createMainId<ExtHostAuthenticationShape>('ExtHostAuthentication'), ExtHostAuthentication: createMainId<ExtHostAuthenticationShape>('ExtHostAuthentication'),
diff --git a/src/vs/workbench/api/common/extHostExtensionService.ts b/src/vs/workbench/api/common/extHostExtensionService.ts diff --git a/src/vs/workbench/api/common/extHostExtensionService.ts b/src/vs/workbench/api/common/extHostExtensionService.ts
index 34639e18b6f..9c22fe6f090 100644 index 0bb5188614bcbf98b85c9208edc2b173f70b1670..38ff3e2e05645be8df619ed2b47fa2984b918741 100644
--- a/src/vs/workbench/api/common/extHostExtensionService.ts --- a/src/vs/workbench/api/common/extHostExtensionService.ts
+++ b/src/vs/workbench/api/common/extHostExtensionService.ts +++ b/src/vs/workbench/api/common/extHostExtensionService.ts
@@ -32,6 +32,7 @@ import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitData @@ -31,6 +31,7 @@ import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitData
import { IExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePaths'; import { IExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePaths';
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService'; import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
@ -2921,7 +3008,7 @@ index 34639e18b6f..9c22fe6f090 100644
this._loadExtensionContext(extensionDescription) this._loadExtensionContext(extensionDescription)
]).then(values => { ]).then(values => {
return AbstractExtHostExtensionService._callActivate(this._logService, extensionDescription.identifier, values[0], values[1], activationTimesBuilder); return AbstractExtHostExtensionService._callActivate(this._logService, extensionDescription.identifier, values[0], values[1], activationTimesBuilder);
@@ -754,7 +758,7 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme @@ -746,7 +750,7 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme
protected abstract _beforeAlmostReadyToRunExtensions(): Promise<void>; protected abstract _beforeAlmostReadyToRunExtensions(): Promise<void>;
protected abstract _getEntryPoint(extensionDescription: IExtensionDescription): string | undefined; protected abstract _getEntryPoint(extensionDescription: IExtensionDescription): string | undefined;
@ -2931,7 +3018,7 @@ index 34639e18b6f..9c22fe6f090 100644
} }
diff --git a/src/vs/workbench/api/node/extHost.node.services.ts b/src/vs/workbench/api/node/extHost.node.services.ts diff --git a/src/vs/workbench/api/node/extHost.node.services.ts b/src/vs/workbench/api/node/extHost.node.services.ts
index b3c89e51cfc..e21abe4e13b 100644 index b3c89e51cfc25a53293a352a2a8ad50d5f26d595..e21abe4e13bc25a5b72f556bbfb61085842faeb7 100644
--- a/src/vs/workbench/api/node/extHost.node.services.ts --- a/src/vs/workbench/api/node/extHost.node.services.ts
+++ b/src/vs/workbench/api/node/extHost.node.services.ts +++ b/src/vs/workbench/api/node/extHost.node.services.ts
@@ -3,6 +3,8 @@ @@ -3,6 +3,8 @@
@ -2948,8 +3035,33 @@ index b3c89e51cfc..e21abe4e13b 100644
registerSingleton(IExtHostTerminalService, ExtHostTerminalService); registerSingleton(IExtHostTerminalService, ExtHostTerminalService);
registerSingleton(IExtHostTunnelService, ExtHostTunnelService); registerSingleton(IExtHostTunnelService, ExtHostTunnelService);
+registerSingleton(IExtHostNodeProxy, class extends NotImplementedProxy<IExtHostNodeProxy>(String(IExtHostNodeProxy)) { whenReady = Promise.resolve(); }); +registerSingleton(IExtHostNodeProxy, class extends NotImplementedProxy<IExtHostNodeProxy>(String(IExtHostNodeProxy)) { whenReady = Promise.resolve(); });
diff --git a/src/vs/workbench/api/node/extHostCLIServer.ts b/src/vs/workbench/api/node/extHostCLIServer.ts
index 7cae126cc0f804273850933468690e0f9f10a5b8..08c2aa5cdae3f3d06bb08b7055dc7e7def260132 100644
--- a/src/vs/workbench/api/node/extHostCLIServer.ts
+++ b/src/vs/workbench/api/node/extHostCLIServer.ts
@@ -11,6 +11,8 @@ import { IWindowOpenable, IOpenWindowOptions } from 'vs/platform/windows/common/
import { URI } from 'vs/base/common/uri';
import { hasWorkspaceFileExtension } from 'vs/platform/workspaces/common/workspaces';
import { ILogService } from 'vs/platform/log/common/log';
+import { join } from 'vs/base/common/path';
+import { tmpdir } from 'os';
export interface OpenCommandPipeArgs {
type: 'open';
@@ -54,6 +56,11 @@ export class CLIServer {
private async setup(): Promise<string> {
this._ipcHandlePath = generateRandomPipeName();
+ // NOTE@coder: Write this out so we can get the most recent path.
+ fs.promises.writeFile(join(tmpdir(), "vscode-ipc"), this._ipcHandlePath).catch((error) => {
+ this.logService.error(error);
+ });
+
try {
this._server.listen(this.ipcHandlePath);
this._server.on('error', err => this.logService.error(err));
diff --git a/src/vs/workbench/api/worker/extHost.worker.services.ts b/src/vs/workbench/api/worker/extHost.worker.services.ts diff --git a/src/vs/workbench/api/worker/extHost.worker.services.ts b/src/vs/workbench/api/worker/extHost.worker.services.ts
index 3843fdec386..8aac4df5278 100644 index 3843fdec386edc09a1d361b63de892a04e0070ed..8aac4df527857e964798362a69f5591bef07c165 100644
--- a/src/vs/workbench/api/worker/extHost.worker.services.ts --- a/src/vs/workbench/api/worker/extHost.worker.services.ts
+++ b/src/vs/workbench/api/worker/extHost.worker.services.ts +++ b/src/vs/workbench/api/worker/extHost.worker.services.ts
@@ -8,6 +8,7 @@ import { ILogService } from 'vs/platform/log/common/log'; @@ -8,6 +8,7 @@ import { ILogService } from 'vs/platform/log/common/log';
@ -2966,18 +3078,18 @@ index 3843fdec386..8aac4df5278 100644
registerSingleton(ILogService, ExtHostLogService); registerSingleton(ILogService, ExtHostLogService);
+registerSingleton(IExtHostNodeProxy, ExtHostNodeProxy); +registerSingleton(IExtHostNodeProxy, ExtHostNodeProxy);
diff --git a/src/vs/workbench/api/worker/extHostExtensionService.ts b/src/vs/workbench/api/worker/extHostExtensionService.ts diff --git a/src/vs/workbench/api/worker/extHostExtensionService.ts b/src/vs/workbench/api/worker/extHostExtensionService.ts
index c71ab1c7da4..572b07ff251 100644 index a6a149083719d7479268e24eb5339f6cbf93e655..360888dc7dff9437f6c85f7a2043ad9e7c4daf21 100644
--- a/src/vs/workbench/api/worker/extHostExtensionService.ts --- a/src/vs/workbench/api/worker/extHostExtensionService.ts
+++ b/src/vs/workbench/api/worker/extHostExtensionService.ts +++ b/src/vs/workbench/api/worker/extHostExtensionService.ts
@@ -9,6 +9,7 @@ import { AbstractExtHostExtensionService } from 'vs/workbench/api/common/extHost @@ -10,6 +10,7 @@ import { URI } from 'vs/base/common/uri';
import { URI } from 'vs/base/common/uri';
import { RequireInterceptor } from 'vs/workbench/api/common/extHostRequireInterceptor'; import { RequireInterceptor } from 'vs/workbench/api/common/extHostRequireInterceptor';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { ExtensionRuntime } from 'vs/workbench/api/common/extHostTypes';
+import { loadCommonJSModule } from 'vs/server/browser/worker'; +import { loadCommonJSModule } from 'vs/server/browser/worker';
class WorkerRequireInterceptor extends RequireInterceptor { class WorkerRequireInterceptor extends RequireInterceptor {
@@ -42,10 +43,15 @@ export class ExtHostExtensionService extends AbstractExtHostExtensionService { @@ -44,10 +45,15 @@ export class ExtHostExtensionService extends AbstractExtHostExtensionService {
} }
protected _getEntryPoint(extensionDescription: IExtensionDescription): string | undefined { protected _getEntryPoint(extensionDescription: IExtensionDescription): string | undefined {
@ -2996,7 +3108,7 @@ index c71ab1c7da4..572b07ff251 100644
module = module.with({ path: ensureSuffix(module.path, '.js') }); module = module.with({ path: ensureSuffix(module.path, '.js') });
const response = await fetch(module.toString(true)); const response = await fetch(module.toString(true));
diff --git a/src/vs/workbench/browser/parts/activitybar/media/activitybarpart.css b/src/vs/workbench/browser/parts/activitybar/media/activitybarpart.css diff --git a/src/vs/workbench/browser/parts/activitybar/media/activitybarpart.css b/src/vs/workbench/browser/parts/activitybar/media/activitybarpart.css
index ced2d815834..dfcae73e8a0 100644 index ced2d815834e40a1543e80516472799075980733..dfcae73e8a042307600c67f163aa00ba9e0762f4 100644
--- a/src/vs/workbench/browser/parts/activitybar/media/activitybarpart.css --- a/src/vs/workbench/browser/parts/activitybar/media/activitybarpart.css
+++ b/src/vs/workbench/browser/parts/activitybar/media/activitybarpart.css +++ b/src/vs/workbench/browser/parts/activitybar/media/activitybarpart.css
@@ -55,6 +55,10 @@ @@ -55,6 +55,10 @@
@ -3011,7 +3123,7 @@ index ced2d815834..dfcae73e8a0 100644
.monaco-workbench .activitybar > .content > .home-bar > .home-bar-icon-badge { .monaco-workbench .activitybar > .content > .home-bar > .home-bar-icon-badge {
diff --git a/src/vs/workbench/browser/web.main.ts b/src/vs/workbench/browser/web.main.ts diff --git a/src/vs/workbench/browser/web.main.ts b/src/vs/workbench/browser/web.main.ts
index 0462617196b..11434d27af9 100644 index 511d7376a2bfebde59b4c67fed54c39e9dd534c9..c7c45f8e4e4ffe56a8782f58af75c6a7835142cf 100644
--- a/src/vs/workbench/browser/web.main.ts --- a/src/vs/workbench/browser/web.main.ts
+++ b/src/vs/workbench/browser/web.main.ts +++ b/src/vs/workbench/browser/web.main.ts
@@ -45,6 +45,7 @@ import { FileLogService } from 'vs/platform/log/common/fileLogService'; @@ -45,6 +45,7 @@ import { FileLogService } from 'vs/platform/log/common/fileLogService';
@ -3022,7 +3134,7 @@ index 0462617196b..11434d27af9 100644
import { coalesce } from 'vs/base/common/arrays'; import { coalesce } from 'vs/base/common/arrays';
import { InMemoryFileSystemProvider } from 'vs/platform/files/common/inMemoryFilesystemProvider'; import { InMemoryFileSystemProvider } from 'vs/platform/files/common/inMemoryFilesystemProvider';
import { WebResourceIdentityService, IResourceIdentityService } from 'vs/platform/resource/common/resourceIdentityService'; import { WebResourceIdentityService, IResourceIdentityService } from 'vs/platform/resource/common/resourceIdentityService';
@@ -84,6 +85,8 @@ class BrowserMain extends Disposable { @@ -87,6 +88,8 @@ class BrowserMain extends Disposable {
// Startup // Startup
const instantiationService = workbench.startup(); const instantiationService = workbench.startup();
@ -3032,7 +3144,7 @@ index 0462617196b..11434d27af9 100644
return instantiationService.invokeFunction(accessor => { return instantiationService.invokeFunction(accessor => {
const commandService = accessor.get(ICommandService); const commandService = accessor.get(ICommandService);
diff --git a/src/vs/workbench/common/resources.ts b/src/vs/workbench/common/resources.ts diff --git a/src/vs/workbench/common/resources.ts b/src/vs/workbench/common/resources.ts
index 18ea0bfedb4..d59a17c17f4 100644 index 18ea0bfedb4492327429a38237b05915b29f6dd0..d59a17c17f4fffa23d786ce36b4ff624d5688a58 100644
--- a/src/vs/workbench/common/resources.ts --- a/src/vs/workbench/common/resources.ts
+++ b/src/vs/workbench/common/resources.ts +++ b/src/vs/workbench/common/resources.ts
@@ -15,6 +15,7 @@ import { ParsedExpression, IExpression, parse } from 'vs/base/common/glob'; @@ -15,6 +15,7 @@ import { ParsedExpression, IExpression, parse } from 'vs/base/common/glob';
@ -3054,7 +3166,7 @@ index 18ea0bfedb4..d59a17c17f4 100644
this._langIdKey.set(value ? this._modeService.getModeIdByFilepathOrFirstLine(value) : null); this._langIdKey.set(value ? this._modeService.getModeIdByFilepathOrFirstLine(value) : null);
this._extensionKey.set(value ? extname(value) : null); this._extensionKey.set(value ? extname(value) : null);
diff --git a/src/vs/workbench/contrib/scm/browser/media/scm.css b/src/vs/workbench/contrib/scm/browser/media/scm.css diff --git a/src/vs/workbench/contrib/scm/browser/media/scm.css b/src/vs/workbench/contrib/scm/browser/media/scm.css
index 9947f240bf2..bdba0a2fc64 100644 index b1838de8f21c60141d01cc424a5e000a32f1c828..0a480032e0cc8d5219cd240f8807aa317718659d 100644
--- a/src/vs/workbench/contrib/scm/browser/media/scm.css --- a/src/vs/workbench/contrib/scm/browser/media/scm.css
+++ b/src/vs/workbench/contrib/scm/browser/media/scm.css +++ b/src/vs/workbench/contrib/scm/browser/media/scm.css
@@ -138,9 +138,11 @@ @@ -138,9 +138,11 @@
@ -3073,7 +3185,7 @@ index 9947f240bf2..bdba0a2fc64 100644
.scm-view .monaco-list .monaco-list-row .resource-group > .actions, .scm-view .monaco-list .monaco-list-row .resource-group > .actions,
.scm-view .monaco-list .monaco-list-row .resource > .name > .monaco-icon-label > .actions { .scm-view .monaco-list .monaco-list-row .resource > .name > .monaco-icon-label > .actions {
diff --git a/src/vs/workbench/services/dialogs/browser/dialogService.ts b/src/vs/workbench/services/dialogs/browser/dialogService.ts diff --git a/src/vs/workbench/services/dialogs/browser/dialogService.ts b/src/vs/workbench/services/dialogs/browser/dialogService.ts
index 6e3182a696d..7df85da165a 100644 index 1360c248eb7ff937c92d08bbf30d2b76ea606dc0..adccf8b88d62381c3ec484df40c6d63142ec9ef5 100644
--- a/src/vs/workbench/services/dialogs/browser/dialogService.ts --- a/src/vs/workbench/services/dialogs/browser/dialogService.ts
+++ b/src/vs/workbench/services/dialogs/browser/dialogService.ts +++ b/src/vs/workbench/services/dialogs/browser/dialogService.ts
@@ -124,11 +124,12 @@ export class DialogService implements IDialogService { @@ -124,11 +124,12 @@ export class DialogService implements IDialogService {
@ -3092,10 +3204,10 @@ index 6e3182a696d..7df85da165a 100644
}; };
diff --git a/src/vs/workbench/services/environment/browser/environmentService.ts b/src/vs/workbench/services/environment/browser/environmentService.ts diff --git a/src/vs/workbench/services/environment/browser/environmentService.ts b/src/vs/workbench/services/environment/browser/environmentService.ts
index ba2701ec54d..4d4aaa6958b 100644 index 819607be0c13fed28eb7fbe6d4a62c0b860b1aa9..b046943311b713a579cc3a94983ea1b7fca7b9b1 100644
--- a/src/vs/workbench/services/environment/browser/environmentService.ts --- a/src/vs/workbench/services/environment/browser/environmentService.ts
+++ b/src/vs/workbench/services/environment/browser/environmentService.ts +++ b/src/vs/workbench/services/environment/browser/environmentService.ts
@@ -121,8 +121,18 @@ export class BrowserWorkbenchEnvironmentService implements IWorkbenchEnvironment @@ -116,8 +116,18 @@ export class BrowserWorkbenchEnvironmentService implements IWorkbenchEnvironment
@memoize @memoize
get logFile(): URI { return joinPath(this.options.logsPath, 'window.log'); } get logFile(): URI { return joinPath(this.options.logsPath, 'window.log'); }
@ -3115,7 +3227,7 @@ index ba2701ec54d..4d4aaa6958b 100644
@memoize @memoize
get settingsResource(): URI { return joinPath(this.userRoamingDataHome, 'settings.json'); } get settingsResource(): URI { return joinPath(this.userRoamingDataHome, 'settings.json'); }
@@ -284,7 +294,12 @@ export class BrowserWorkbenchEnvironmentService implements IWorkbenchEnvironment @@ -279,7 +289,12 @@ export class BrowserWorkbenchEnvironmentService implements IWorkbenchEnvironment
extensionHostDebugEnvironment.params.port = parseInt(value); extensionHostDebugEnvironment.params.port = parseInt(value);
break; break;
case 'enableProposedApi': case 'enableProposedApi':
@ -3130,10 +3242,10 @@ index ba2701ec54d..4d4aaa6958b 100644
} }
} }
diff --git a/src/vs/workbench/services/extensionManagement/common/extensionEnablementService.ts b/src/vs/workbench/services/extensionManagement/common/extensionEnablementService.ts diff --git a/src/vs/workbench/services/extensionManagement/common/extensionEnablementService.ts b/src/vs/workbench/services/extensionManagement/common/extensionEnablementService.ts
index c28b1477400..6090200d9c3 100644 index 32f3dc52c1ff645df6471a03542d6ec3eb73a277..c2f4497d2eba13a771b2665ad58f12ecdfa7606a 100644
--- a/src/vs/workbench/services/extensionManagement/common/extensionEnablementService.ts --- a/src/vs/workbench/services/extensionManagement/common/extensionEnablementService.ts
+++ b/src/vs/workbench/services/extensionManagement/common/extensionEnablementService.ts +++ b/src/vs/workbench/services/extensionManagement/common/extensionEnablementService.ts
@@ -163,7 +163,7 @@ export class ExtensionEnablementService extends Disposable implements IWorkbench @@ -205,7 +205,7 @@ export class ExtensionEnablementService extends Disposable implements IWorkbench
} }
} }
} }
@ -3143,10 +3255,23 @@ index c28b1477400..6090200d9c3 100644
return false; return false;
} }
diff --git a/src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts b/src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts diff --git a/src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts b/src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts
index 33eb56db3c2..e5167794c3f 100644 index a982b3ecc58c5a2f3a92be7b8cca3a1cacbb7d47..97f9bfcf0e679be683b1b09cd569149e7962f5ad 100644
--- a/src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts --- a/src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts
+++ b/src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts +++ b/src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts
@@ -236,6 +236,11 @@ export class ExtensionManagementService extends Disposable implements IExtension @@ -211,8 +211,11 @@ export class ExtensionManagementService extends Disposable implements IExtension
}
// Install Language pack on all servers
+ // NOTE@coder: It does not appear language packs can be installed on the web
+ // extension management server at this time. Filter out the web to fix this.
if (isLanguagePackExtension(manifest)) {
- return Promise.all(this.servers.map(server => server.extensionManagementService.installFromGallery(gallery))).then(([local]) => local);
+ const servers = this.servers.filter(s => s !== this.extensionManagementServerService.webExtensionManagementServer);
+ return Promise.all(servers.map(server => server.extensionManagementService.installFromGallery(gallery))).then(([local]) => local);
}
// 1. Install on preferred location
@@ -245,6 +248,11 @@ export class ExtensionManagementService extends Disposable implements IExtension
return this.extensionManagementServerService.webExtensionManagementServer.extensionManagementService.installFromGallery(gallery); return this.extensionManagementServerService.webExtensionManagementServer.extensionManagementService.installFromGallery(gallery);
} }
@ -3159,10 +3284,10 @@ index 33eb56db3c2..e5167794c3f 100644
const error = new Error(localize('cannot be installed', "Cannot install '{0}' because this extension has defined that it cannot run on the remote server.", gallery.displayName || gallery.name)); const error = new Error(localize('cannot be installed', "Cannot install '{0}' because this extension has defined that it cannot run on the remote server.", gallery.displayName || gallery.name));
error.name = INSTALL_ERROR_NOT_SUPPORTED; error.name = INSTALL_ERROR_NOT_SUPPORTED;
diff --git a/src/vs/workbench/services/extensions/browser/extensionService.ts b/src/vs/workbench/services/extensions/browser/extensionService.ts diff --git a/src/vs/workbench/services/extensions/browser/extensionService.ts b/src/vs/workbench/services/extensions/browser/extensionService.ts
index d0710e77fa2..ceb27174aee 100644 index 9e979d28691d0b0b26fde5e46b606731e31f3da5..dd31879c7dd899c73c4a1371996912f4513bfd0d 100644
--- a/src/vs/workbench/services/extensions/browser/extensionService.ts --- a/src/vs/workbench/services/extensions/browser/extensionService.ts
+++ b/src/vs/workbench/services/extensions/browser/extensionService.ts +++ b/src/vs/workbench/services/extensions/browser/extensionService.ts
@@ -116,8 +116,10 @@ export class ExtensionService extends AbstractExtensionService implements IExten @@ -125,8 +125,10 @@ export class ExtensionService extends AbstractExtensionService implements IExten
this._remoteAgentService.getEnvironment(), this._remoteAgentService.getEnvironment(),
this._remoteAgentService.scanExtensions() this._remoteAgentService.scanExtensions()
]); ]);
@ -3175,7 +3300,7 @@ index d0710e77fa2..ceb27174aee 100644
const remoteAgentConnection = this._remoteAgentService.getConnection(); const remoteAgentConnection = this._remoteAgentService.getConnection();
this._runningLocation = _determineRunningLocation(this._productService, this._configService, localExtensions, remoteExtensions, Boolean(remoteEnv && remoteAgentConnection)); this._runningLocation = _determineRunningLocation(this._productService, this._configService, localExtensions, remoteExtensions, Boolean(remoteEnv && remoteAgentConnection));
diff --git a/src/vs/workbench/services/extensions/common/extensionsUtil.ts b/src/vs/workbench/services/extensions/common/extensionsUtil.ts diff --git a/src/vs/workbench/services/extensions/common/extensionsUtil.ts b/src/vs/workbench/services/extensions/common/extensionsUtil.ts
index 65e532ee58d..0b6282fde7a 100644 index 65e532ee58dfc06ed944846d01b885cb8f260ebc..0b6282fde7ad03c7ea9872a777cbf487253abed1 100644
--- a/src/vs/workbench/services/extensions/common/extensionsUtil.ts --- a/src/vs/workbench/services/extensions/common/extensionsUtil.ts
+++ b/src/vs/workbench/services/extensions/common/extensionsUtil.ts +++ b/src/vs/workbench/services/extensions/common/extensionsUtil.ts
@@ -37,7 +37,8 @@ export function canExecuteOnWorkspace(manifest: IExtensionManifest, productServi @@ -37,7 +37,8 @@ export function canExecuteOnWorkspace(manifest: IExtensionManifest, productServi
@ -3189,7 +3314,7 @@ index 65e532ee58d..0b6282fde7a 100644
export function getExtensionKind(manifest: IExtensionManifest, productService: IProductService, configurationService: IConfigurationService): ExtensionKind[] { export function getExtensionKind(manifest: IExtensionManifest, productService: IProductService, configurationService: IConfigurationService): ExtensionKind[] {
diff --git a/src/vs/workbench/services/extensions/node/extensionHostProcessSetup.ts b/src/vs/workbench/services/extensions/node/extensionHostProcessSetup.ts diff --git a/src/vs/workbench/services/extensions/node/extensionHostProcessSetup.ts b/src/vs/workbench/services/extensions/node/extensionHostProcessSetup.ts
index 49542eda74c..de0e2da0a4c 100644 index 49542eda74c65e485272cd37d586911886aa3ad7..de0e2da0a4c2dca91dc7e0e48c28a8a75ca3e7d4 100644
--- a/src/vs/workbench/services/extensions/node/extensionHostProcessSetup.ts --- a/src/vs/workbench/services/extensions/node/extensionHostProcessSetup.ts
+++ b/src/vs/workbench/services/extensions/node/extensionHostProcessSetup.ts +++ b/src/vs/workbench/services/extensions/node/extensionHostProcessSetup.ts
@@ -16,7 +16,7 @@ import { IInitData } from 'vs/workbench/api/common/extHost.protocol'; @@ -16,7 +16,7 @@ import { IInitData } from 'vs/workbench/api/common/extHost.protocol';
@ -3246,7 +3371,7 @@ index 49542eda74c..de0e2da0a4c 100644
console.error(e); console.error(e);
} }
diff --git a/src/vs/workbench/services/extensions/worker/extensionHostWorkerMain.ts b/src/vs/workbench/services/extensions/worker/extensionHostWorkerMain.ts diff --git a/src/vs/workbench/services/extensions/worker/extensionHostWorkerMain.ts b/src/vs/workbench/services/extensions/worker/extensionHostWorkerMain.ts
index 79455414c06..a407593b4dc 100644 index 79455414c06b95612a0dce2cad01f2bb2f40ef49..a407593b4dc6053309ed560898918cf67470e836 100644
--- a/src/vs/workbench/services/extensions/worker/extensionHostWorkerMain.ts --- a/src/vs/workbench/services/extensions/worker/extensionHostWorkerMain.ts
+++ b/src/vs/workbench/services/extensions/worker/extensionHostWorkerMain.ts +++ b/src/vs/workbench/services/extensions/worker/extensionHostWorkerMain.ts
@@ -14,7 +14,11 @@ @@ -14,7 +14,11 @@
@ -3263,7 +3388,7 @@ index 79455414c06..a407593b4dc 100644
require(['vs/workbench/services/extensions/worker/extensionHostWorker'], () => { }, err => console.error(err)); require(['vs/workbench/services/extensions/worker/extensionHostWorker'], () => { }, err => console.error(err));
diff --git a/src/vs/workbench/services/localizations/electron-browser/localizationsService.ts b/src/vs/workbench/services/localizations/electron-browser/localizationsService.ts diff --git a/src/vs/workbench/services/localizations/electron-browser/localizationsService.ts b/src/vs/workbench/services/localizations/electron-browser/localizationsService.ts
index 44999bd842e..601b1c54088 100644 index 44999bd842eae12b752b2e7e8c4904272b111dc1..601b1c5408835c743fe07e34da4d4534873bf832 100644
--- a/src/vs/workbench/services/localizations/electron-browser/localizationsService.ts --- a/src/vs/workbench/services/localizations/electron-browser/localizationsService.ts
+++ b/src/vs/workbench/services/localizations/electron-browser/localizationsService.ts +++ b/src/vs/workbench/services/localizations/electron-browser/localizationsService.ts
@@ -5,17 +5,17 @@ @@ -5,17 +5,17 @@
@ -3288,7 +3413,7 @@ index 44999bd842e..601b1c54088 100644
} }
diff --git a/src/vs/workbench/workbench.web.main.ts b/src/vs/workbench/workbench.web.main.ts diff --git a/src/vs/workbench/workbench.web.main.ts b/src/vs/workbench/workbench.web.main.ts
index 0669178db4c..28fafeb2de2 100644 index f02bbbf874b5b18ac8d077ad56a8a4a57e77a4a6..86271940724aaf28e4eda93e59920820a7d93987 100644
--- a/src/vs/workbench/workbench.web.main.ts --- a/src/vs/workbench/workbench.web.main.ts
+++ b/src/vs/workbench/workbench.web.main.ts +++ b/src/vs/workbench/workbench.web.main.ts
@@ -35,7 +35,8 @@ import 'vs/workbench/services/textfile/browser/browserTextFileService'; @@ -35,7 +35,8 @@ import 'vs/workbench/services/textfile/browser/browserTextFileService';
@ -3302,7 +3427,7 @@ index 0669178db4c..28fafeb2de2 100644
import 'vs/workbench/services/credentials/browser/credentialsService'; import 'vs/workbench/services/credentials/browser/credentialsService';
import 'vs/workbench/services/url/browser/urlService'; import 'vs/workbench/services/url/browser/urlService';
diff --git a/yarn.lock b/yarn.lock diff --git a/yarn.lock b/yarn.lock
index b2fbf543af3..f10dddd6594 100644 index 140ed883c1a92ebcd7a284b98ca71261fa9cb631..b363d7de5000fd370bb4221f48e193382648a185 100644
--- a/yarn.lock --- a/yarn.lock
+++ b/yarn.lock +++ b/yarn.lock
@@ -140,6 +140,23 @@ @@ -140,6 +140,23 @@
@ -3329,7 +3454,7 @@ index b2fbf543af3..f10dddd6594 100644
"@electron/get@^1.0.1": "@electron/get@^1.0.1":
version "1.7.2" version "1.7.2"
resolved "https://registry.yarnpkg.com/@electron/get/-/get-1.7.2.tgz#286436a9fb56ff1a1fcdf0e80131fd65f4d1e0fd" resolved "https://registry.yarnpkg.com/@electron/get/-/get-1.7.2.tgz#286436a9fb56ff1a1fcdf0e80131fd65f4d1e0fd"
@@ -5421,6 +5438,13 @@ jsprim@^1.2.2: @@ -5375,6 +5392,13 @@ jsprim@^1.2.2:
json-schema "0.2.3" json-schema "0.2.3"
verror "1.10.0" verror "1.10.0"
@ -3343,7 +3468,7 @@ index b2fbf543af3..f10dddd6594 100644
just-debounce@^1.0.0: just-debounce@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/just-debounce/-/just-debounce-1.0.0.tgz#87fccfaeffc0b68cd19d55f6722943f929ea35ea" resolved "https://registry.yarnpkg.com/just-debounce/-/just-debounce-1.0.0.tgz#87fccfaeffc0b68cd19d55f6722943f929ea35ea"
@@ -6008,26 +6032,11 @@ minimatch@0.3: @@ -5955,26 +5979,11 @@ minimatch@0.3:
dependencies: dependencies:
brace-expansion "^1.1.7" brace-expansion "^1.1.7"
@ -3371,7 +3496,7 @@ index b2fbf543af3..f10dddd6594 100644
minipass@^2.2.1, minipass@^2.3.3: minipass@^2.2.1, minipass@^2.3.3:
version "2.3.3" version "2.3.3"
resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.3.tgz#a7dcc8b7b833f5d368759cce544dccb55f50f233" resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.3.tgz#a7dcc8b7b833f5d368759cce544dccb55f50f233"
@@ -6797,6 +6806,11 @@ p-try@^2.0.0: @@ -6716,6 +6725,11 @@ p-try@^2.0.0:
resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.0.0.tgz#85080bb87c64688fa47996fe8f7dfbe8211760b1" resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.0.0.tgz#85080bb87c64688fa47996fe8f7dfbe8211760b1"
integrity sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ== integrity sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==

View File

@ -1,6 +1,6 @@
FROM centos:7 FROM centos:7
ARG NODE_VERSION=v12.18.3 ARG NODE_VERSION=v12.18.4
RUN ARCH="$(uname -m | sed 's/86_64/64/; s/aarch64/arm64/')" && \ RUN ARCH="$(uname -m | sed 's/86_64/64/; s/aarch64/arm64/')" && \
curl -fsSL "https://nodejs.org/dist/$NODE_VERSION/node-$NODE_VERSION-linux-$ARCH.tar.xz" | tar -C /usr/local -xJ && \ curl -fsSL "https://nodejs.org/dist/$NODE_VERSION/node-$NODE_VERSION-linux-$ARCH.tar.xz" | tar -C /usr/local -xJ && \
mv "/usr/local/node-$NODE_VERSION-linux-$ARCH" "/usr/local/node-$NODE_VERSION" mv "/usr/local/node-$NODE_VERSION-linux-$ARCH" "/usr/local/node-$NODE_VERSION"
@ -15,11 +15,16 @@ RUN npm config set python python2
RUN yum install -y epel-release && yum install -y jq RUN yum install -y epel-release && yum install -y jq
RUN yum install -y rsync RUN yum install -y rsync
# Copied from ../debian8/Dockerfile # Copied from ../debian10/Dockerfile
# Install Go dependencies # Install Go.
RUN ARCH="$(uname -m | sed 's/x86_64/amd64/; s/aarch64/arm64/')" && \ RUN ARCH="$(uname -m | sed 's/x86_64/amd64/; s/aarch64/arm64/')" && \
curl -fsSL "https://dl.google.com/go/go1.14.3.linux-$ARCH.tar.gz" | tar -C /usr/local -xz curl -fsSL "https://dl.google.com/go/go1.14.3.linux-$ARCH.tar.gz" | tar -C /usr/local -xz
ENV PATH=/usr/local/go/bin:/root/go/bin:$PATH ENV GOPATH=/gopath
# Ensures running this image as another user works.
RUN mkdir -p $GOPATH && chmod -R 777 $GOPATH
ENV PATH=/usr/local/go/bin:$GOPATH/bin:$PATH
# Install Go dependencies
ENV GO111MODULE=on ENV GO111MODULE=on
RUN go get mvdan.cc/sh/v3/cmd/shfmt RUN go get mvdan.cc/sh/v3/cmd/shfmt
RUN go get github.com/goreleaser/nfpm/cmd/nfpm RUN go get github.com/goreleaser/nfpm/cmd/nfpm

View File

@ -1,4 +1,4 @@
FROM debian:8 FROM debian:10
RUN apt-get update RUN apt-get update
@ -24,28 +24,23 @@ RUN apt-get install -y build-essential \
RUN apt-get install -y gettext-base RUN apt-get install -y gettext-base
# Misc build dependencies. # Misc build dependencies.
RUN apt-get install -y git rsync unzip RUN apt-get install -y git rsync unzip jq
# We need latest jq from debian buster for date support.
RUN ARCH="$(dpkg --print-architecture)" && \
curl -fsSOL http://http.us.debian.org/debian/pool/main/libo/libonig/libonig5_6.9.1-1_$ARCH.deb && \
dpkg -i libonig*.deb && \
curl -fsSOL http://http.us.debian.org/debian/pool/main/j/jq/libjq1_1.5+dfsg-2+b1_$ARCH.deb && \
dpkg -i libjq*.deb && \
curl -fsSOL http://http.us.debian.org/debian/pool/main/j/jq/jq_1.5+dfsg-2+b1_$ARCH.deb && \
dpkg -i jq*.deb && rm *.deb
# Installs shellcheck. # Installs shellcheck.
# Unfortunately coredumps on debian:8 so disabled for now. RUN curl -fsSL https://github.com/koalaman/shellcheck/releases/download/v0.7.1/shellcheck-v0.7.1.linux.$(uname -m).tar.xz | \
#RUN curl -fsSL https://github.com/koalaman/shellcheck/releases/download/v0.7.1/shellcheck-v0.7.1.linux.$(uname -m).tar.xz | \ tar -xJ && \
# tar -xJ && \ mv shellcheck*/shellcheck /usr/local/bin && \
# mv shellcheck*/shellcheck /usr/local/bin && \ rm -R shellcheck*
# rm -R shellcheck*
# Install Go dependencies # Install Go.
RUN ARCH="$(uname -m | sed 's/x86_64/amd64/; s/aarch64/arm64/')" && \ RUN ARCH="$(uname -m | sed 's/x86_64/amd64/; s/aarch64/arm64/')" && \
curl -fsSL "https://dl.google.com/go/go1.14.3.linux-$ARCH.tar.gz" | tar -C /usr/local -xz curl -fsSL "https://dl.google.com/go/go1.14.3.linux-$ARCH.tar.gz" | tar -C /usr/local -xz
ENV PATH=/usr/local/go/bin:/root/go/bin:$PATH ENV GOPATH=/gopath
# Ensures running this image as another user works.
RUN mkdir -p $GOPATH && chmod -R 777 $GOPATH
ENV PATH=/usr/local/go/bin:$GOPATH/bin:$PATH
# Install Go dependencies
ENV GO111MODULE=on ENV GO111MODULE=on
RUN go get mvdan.cc/sh/v3/cmd/shfmt RUN go get mvdan.cc/sh/v3/cmd/shfmt
RUN go get github.com/goreleaser/nfpm/cmd/nfpm RUN go get github.com/goreleaser/nfpm/cmd/nfpm

View File

@ -39,6 +39,9 @@ COPY ci/release-image/entrypoint.sh /usr/bin/entrypoint.sh
RUN dpkg -i /tmp/code-server*$(dpkg --print-architecture).deb && rm /tmp/code-server*.deb RUN dpkg -i /tmp/code-server*$(dpkg --print-architecture).deb && rm /tmp/code-server*.deb
EXPOSE 8080 EXPOSE 8080
USER coder # This way, if someone sets $DOCKER_USER, docker-exec will still work as
# the uid will remain the same. note: only relevant if -u isn't passed to
# docker-run.
USER 1000
WORKDIR /home/coder WORKDIR /home/coder
ENTRYPOINT ["/usr/bin/entrypoint.sh", "--bind-addr", "0.0.0.0:8080", "."] ENTRYPOINT ["/usr/bin/entrypoint.sh", "--bind-addr", "0.0.0.0:8080", "."]

View File

@ -1,18 +1,21 @@
#!/usr/bin/env sh #!/bin/sh
set -eu set -eu
if [ "${DOCKER_USER-}" ]; then # This isn't set by default.
USER="$(whoami)"
export USER
if [ "${DOCKER_USER-}" ] && [ "$DOCKER_USER" != "$USER" ]; then
echo "$DOCKER_USER ALL=(ALL) NOPASSWD:ALL" | sudo tee -a /etc/sudoers.d/nopasswd > /dev/null echo "$DOCKER_USER ALL=(ALL) NOPASSWD:ALL" | sudo tee -a /etc/sudoers.d/nopasswd > /dev/null
sudo usermod --login "$DOCKER_USER" \ # Unfortunately we cannot change $HOME as we cannot move any bind mounts
--move-home --home "/home/$DOCKER_USER" \ # nor can we bind mount $HOME into a new home as that requires a privileged container.
coder sudo usermod --login "$DOCKER_USER" coder
sudo groupmod -n "$DOCKER_USER" coder sudo groupmod -n "$DOCKER_USER" coder
USER="$DOCKER_USER"
sudo sed -i "/coder/d" /etc/sudoers.d/nopasswd sudo sed -i "/coder/d" /etc/sudoers.d/nopasswd
sudo sed -i "s/coder/$DOCKER_USER/g" /etc/fixuid/config.yml sudo sed -i "s/coder/$DOCKER_USER/g" /etc/fixuid/config.yml
export HOME="/home/$DOCKER_USER"
fi fi
# This isn't set by default.
export USER="$(whoami)"
dumb-init fixuid -q /usr/bin/code-server "$@" dumb-init fixuid -q /usr/bin/code-server "$@"

View File

@ -4,7 +4,7 @@ set -euo pipefail
main() { main() {
cd "$(dirname "$0")/../.." cd "$(dirname "$0")/../.."
NODE_VERSION=v12.18.3 NODE_VERSION=v12.18.4
NODE_OS="$(uname | tr '[:upper:]' '[:lower:]')" NODE_OS="$(uname | tr '[:upper:]' '[:lower:]')"
NODE_ARCH="$(uname -m | sed 's/86_64/64/; s/aarch64/arm64/')" NODE_ARCH="$(uname -m | sed 's/86_64/64/; s/aarch64/arm64/')"
curl -L "https://nodejs.org/dist/$NODE_VERSION/node-$NODE_VERSION-$NODE_OS-$NODE_ARCH.tar.gz" | tar -xz curl -L "https://nodejs.org/dist/$NODE_VERSION/node-$NODE_VERSION-$NODE_OS-$NODE_ARCH.tar.gz" | tar -xz

View File

@ -32,7 +32,7 @@ Differences:
- We require a minimum of node v12 but later versions should work. - We require a minimum of node v12 but later versions should work.
- We use [nfpm](https://github.com/goreleaser/nfpm) to build `.deb` and `.rpm` packages. - We use [nfpm](https://github.com/goreleaser/nfpm) to build `.deb` and `.rpm` packages.
- We use [jq](https://stedolan.github.io/jq/) to build code-server releases. - We use [jq](https://stedolan.github.io/jq/) to build code-server releases.
- The [CI container](../ci/images/debian8/Dockerfile) is a useful reference for all our dependencies. - The [CI container](../ci/images/debian10/Dockerfile) is a useful reference for all our dependencies.
## Development Workflow ## Development Workflow
@ -76,7 +76,7 @@ node .
Build release packages (make sure you run `./ci/steps/release.sh` first): Build release packages (make sure you run `./ci/steps/release.sh` first):
``` ```
./ci/dev/image/run.sh ./ci/steps/release-packages.sh IMAGE=centos7 ./ci/dev/image/run.sh ./ci/steps/release-packages.sh
# The standalone release is in ./release-standalone # The standalone release is in ./release-standalone
# .deb, .rpm and the standalone archive are in ./release-packages # .deb, .rpm and the standalone archive are in ./release-packages
``` ```
@ -99,6 +99,13 @@ yarn test:standalone-release
yarn package yarn package
``` ```
For a faster release build you can also run:
```
KEEP_MODULES=1 ./ci/steps/release.sh
node ./release
```
## Structure ## Structure
The `code-server` script serves an HTTP API to login and start a remote VS Code process. The `code-server` script serves an HTTP API to login and start a remote VS Code process.

View File

@ -19,6 +19,7 @@
- [How does code-server decide what workspace or folder to open?](#how-does-code-server-decide-what-workspace-or-folder-to-open) - [How does code-server decide what workspace or folder to open?](#how-does-code-server-decide-what-workspace-or-folder-to-open)
- [How do I debug issues with code-server?](#how-do-i-debug-issues-with-code-server) - [How do I debug issues with code-server?](#how-do-i-debug-issues-with-code-server)
- [Heartbeat File](#heartbeat-file) - [Heartbeat File](#heartbeat-file)
- [Healthz endpoint](#healthz-endpoint)
- [How does the config file work?](#how-does-the-config-file-work) - [How does the config file work?](#how-does-the-config-file-work)
- [Blank screen on iPad?](#blank-screen-on-ipad) - [Blank screen on iPad?](#blank-screen-on-ipad)
- [Isn't an install script piped into sh insecure?](#isnt-an-install-script-piped-into-sh-insecure) - [Isn't an install script piped into sh insecure?](#isnt-an-install-script-piped-into-sh-insecure)
@ -242,6 +243,20 @@ older than X minutes, kill `code-server`.
[#1636](https://github.com/cdr/code-server/issues/1636) will make the experience here better. [#1636](https://github.com/cdr/code-server/issues/1636) will make the experience here better.
## Healthz endpoint
`code-server` exposes an endpoint at `/healthz` which can be used to check
whether `code-server` is up without triggering a heartbeat. The response will
include a status (`alive` or `expired`) and a timestamp for the last heartbeat
(defaults to `0`). This endpoint does not require authentication.
```json
{
"status": "alive",
"lastHeartbeat": 1599166210566
}
```
## How does the config file work? ## How does the config file work?
When `code-server` starts up, it creates a default config file in `~/.config/code-server/config.yaml` that looks When `code-server` starts up, it creates a default config file in `~/.config/code-server/config.yaml` that looks

View File

@ -79,8 +79,8 @@ commands presented in the rest of this document.
## Debian, Ubuntu ## Debian, Ubuntu
```bash ```bash
curl -fOL https://github.com/cdr/code-server/releases/download/v3.5.0/code-server_3.5.0_amd64.deb curl -fOL https://github.com/cdr/code-server/releases/download/v3.6.0/code-server_3.6.0_amd64.deb
sudo dpkg -i code-server_3.5.0_amd64.deb sudo dpkg -i code-server_3.6.0_amd64.deb
sudo systemctl enable --now code-server@$USER sudo systemctl enable --now code-server@$USER
# Now visit http://127.0.0.1:8080. Your password is in ~/.config/code-server/config.yaml # Now visit http://127.0.0.1:8080. Your password is in ~/.config/code-server/config.yaml
``` ```
@ -88,8 +88,8 @@ sudo systemctl enable --now code-server@$USER
## Fedora, CentOS, RHEL, SUSE ## Fedora, CentOS, RHEL, SUSE
```bash ```bash
curl -fOL https://github.com/cdr/code-server/releases/download/v3.5.0/code-server-3.5.0-amd64.rpm curl -fOL https://github.com/cdr/code-server/releases/download/v3.6.0/code-server-3.6.0-amd64.rpm
sudo rpm -i code-server-3.5.0-amd64.rpm sudo rpm -i code-server-3.6.0-amd64.rpm
sudo systemctl enable --now code-server@$USER sudo systemctl enable --now code-server@$USER
# Now visit http://127.0.0.1:8080. Your password is in ~/.config/code-server/config.yaml # Now visit http://127.0.0.1:8080. Your password is in ~/.config/code-server/config.yaml
``` ```
@ -158,10 +158,10 @@ Here is an example script for installing and using a standalone `code-server` re
```bash ```bash
mkdir -p ~/.local/lib ~/.local/bin mkdir -p ~/.local/lib ~/.local/bin
curl -fL https://github.com/cdr/code-server/releases/download/v3.5.0/code-server-3.5.0-linux-amd64.tar.gz \ curl -fL https://github.com/cdr/code-server/releases/download/v3.6.0/code-server-3.6.0-linux-amd64.tar.gz \
| tar -C ~/.local/lib -xz | tar -C ~/.local/lib -xz
mv ~/.local/lib/code-server-3.5.0-linux-amd64 ~/.local/lib/code-server-3.5.0 mv ~/.local/lib/code-server-3.6.0-linux-amd64 ~/.local/lib/code-server-3.6.0
ln -s ~/.local/lib/code-server-3.5.0/bin/code-server ~/.local/bin/code-server ln -s ~/.local/lib/code-server-3.6.0/bin/code-server ~/.local/bin/code-server
PATH="~/.local/bin:$PATH" PATH="~/.local/bin:$PATH"
code-server code-server
# Now visit http://127.0.0.1:8080. Your password is in ~/.config/code-server/config.yaml # Now visit http://127.0.0.1:8080. Your password is in ~/.config/code-server/config.yaml
@ -179,10 +179,11 @@ code-server
# easily access/modify your code-server config in $HOME/.config/code-server/config.json # easily access/modify your code-server config in $HOME/.config/code-server/config.json
# outside the container. # outside the container.
mkdir -p ~/.config mkdir -p ~/.config
docker run -it -p 127.0.0.1:8080:8080 \ docker run -it --name code-server -p 127.0.0.1:8080:8080 \
-v "$HOME/.config:/home/coder/.config" \ -v "$HOME/.config:/home/coder/.config" \
-v "$PWD:/home/coder/project" \ -v "$PWD:/home/coder/project" \
-u "$(id -u):$(id -g)" \ -u "$(id -u):$(id -g)" \
-e "DOCKER_USER=$USER" \
codercom/code-server:latest codercom/code-server:latest
``` ```

View File

@ -17,21 +17,28 @@ usage() {
Installs code-server for Linux, macOS and FreeBSD. Installs code-server for Linux, macOS and FreeBSD.
It tries to use the system package manager if possible. It tries to use the system package manager if possible.
After successful installation it explains how to start using code-server. After successful installation it explains how to start using code-server.
Pass in user@host to install code-server on user@host over ssh.
The remote host must have internet access.
${not_curl_usage-} ${not_curl_usage-}
Usage: Usage:
$arg0 [--dry-run] [--version X.X.X] [--method detect] [--prefix ~/.local] $arg0 [--dry-run] [--version X.X.X] [--method detect] \
[--prefix ~/.local] [user@host]
--dry-run --dry-run
Echo the commands for the install process without running them. Echo the commands for the install process without running them.
--version X.X.X --version X.X.X
Install a specific version instead of the latest. Install a specific version instead of the latest.
--method [detect | standalone] --method [detect | standalone]
Choose the installation method. Defaults to detect. Choose the installation method. Defaults to detect.
- detect detects the system package manager and tries to use it. - detect detects the system package manager and tries to use it.
Full reference on the process is further below. Full reference on the process is further below.
- standalone installs a standalone release archive into ~/.local - standalone installs a standalone release archive into ~/.local
Add ~/.local/bin to your \$PATH to use it. Add ~/.local/bin to your \$PATH to use it.
--prefix <dir> --prefix <dir>
Sets the prefix used by standalone release archives. Defaults to ~/.local Sets the prefix used by standalone release archives. Defaults to ~/.local
The release is unarchived into ~/.local/lib/code-server-X.X.X The release is unarchived into ~/.local/lib/code-server-X.X.X
@ -100,9 +107,18 @@ main() {
METHOD \ METHOD \
STANDALONE_INSTALL_PREFIX \ STANDALONE_INSTALL_PREFIX \
VERSION \ VERSION \
OPTIONAL OPTIONAL \
ALL_FLAGS \
SSH_ARGS
ALL_FLAGS=""
while [ "$#" -gt 0 ]; do while [ "$#" -gt 0 ]; do
case "$1" in
-*)
ALL_FLAGS="${ALL_FLAGS} $1"
;;
esac
case "$1" in case "$1" in
--dry-run) --dry-run)
DRY_RUN=1 DRY_RUN=1
@ -132,16 +148,33 @@ main() {
usage usage
exit 0 exit 0
;; ;;
*) --)
shift
# We remove the -- added above.
ALL_FLAGS="${ALL_FLAGS% --}"
SSH_ARGS="$*"
break
;;
-*)
echoerr "Unknown flag $1" echoerr "Unknown flag $1"
echoerr "Run with --help to see usage." echoerr "Run with --help to see usage."
exit 1 exit 1
;; ;;
*)
SSH_ARGS="$*"
break
;;
esac esac
shift shift
done done
if [ "${SSH_ARGS-}" ]; then
echoh "Installing remotely with ssh $SSH_ARGS"
curl -fsSL https://code-server.dev/install.sh | prefix "$SSH_ARGS" ssh "$SSH_ARGS" sh -s -- "$ALL_FLAGS"
return
fi
VERSION="${VERSION-$(echo_latest_version)}" VERSION="${VERSION-$(echo_latest_version)}"
METHOD="${METHOD-detect}" METHOD="${METHOD-detect}"
if [ "$METHOD" != detect ] && [ "$METHOD" != standalone ]; then if [ "$METHOD" != detect ] && [ "$METHOD" != standalone ]; then
@ -446,7 +479,7 @@ arch() {
} }
command_exists() { command_exists() {
command -v "$@" > /dev/null 2>&1 command -v "$@" > /dev/null
} }
sh_c() { sh_c() {
@ -500,4 +533,15 @@ humanpath() {
sed "s# $HOME# ~#g; s#\"$HOME#\"\$HOME#g" sed "s# $HOME# ~#g; s#\"$HOME#\"\$HOME#g"
} }
# We need to make sure we exit with a non zero exit if the command fails.
# /bin/sh does not support -o pipefail unfortunately.
prefix() {
PREFIX="$1"
shift
fifo="$(mktemp -d)/fifo"
mkfifo "$fifo"
sed -e "s#^#$PREFIX: #" "$fifo" &
"$@" > "$fifo" 2>&1
}
main "$@" main "$@"

@ -1 +1 @@
Subproject commit a0479759d6e9ea56afa657e454193f72aef85bd0 Subproject commit 2af051012b66169dde0c4dfae3f5ef48f787ff69

View File

@ -1,7 +1,7 @@
{ {
"name": "code-server", "name": "code-server",
"license": "MIT", "license": "MIT",
"version": "3.5.0", "version": "3.6.0",
"description": "Run VS Code on a remote server.", "description": "Run VS Code on a remote server.",
"homepage": "https://github.com/cdr/code-server", "homepage": "https://github.com/cdr/code-server",
"bugs": { "bugs": {
@ -39,6 +39,7 @@
"@types/pem": "^1.9.5", "@types/pem": "^1.9.5",
"@types/safe-compare": "^1.1.0", "@types/safe-compare": "^1.1.0",
"@types/semver": "^7.1.0", "@types/semver": "^7.1.0",
"@types/split2": "^2.1.6",
"@types/tar-fs": "^2.0.0", "@types/tar-fs": "^2.0.0",
"@types/tar-stream": "^2.1.0", "@types/tar-stream": "^2.1.0",
"@types/ws": "^7.2.6", "@types/ws": "^7.2.6",
@ -76,6 +77,7 @@
"safe-buffer": "^5.1.1", "safe-buffer": "^5.1.1",
"safe-compare": "^1.1.4", "safe-compare": "^1.1.4",
"semver": "^7.1.3", "semver": "^7.1.3",
"split2": "^3.2.2",
"tar": "^6.0.1", "tar": "^6.0.1",
"tar-fs": "^2.0.0", "tar-fs": "^2.0.0",
"ws": "^7.2.0", "ws": "^7.2.0",

View File

@ -47,5 +47,5 @@
</div> </div>
</body> </body>
<script data-cfasync="false" src="{{CS_STATIC_BASE}}/dist/register.js"></script> <script data-cfasync="false" src="{{CS_STATIC_BASE}}/dist/register.js"></script>
<script data-cfasync="false" src="{{CS_STATIC_BASE}}/dist/login.js"></script> <script data-cfasync="false" src="{{CS_STATIC_BASE}}/dist/pages/login.js"></script>
</html> </html>

View File

@ -17,7 +17,7 @@ try {
} }
// FIXME: Only works if path separators are /. // FIXME: Only works if path separators are /.
const path = nlsConfig._resolvedLanguagePackCoreLocation + "/" + bundle.replace(/\//g, "!") + ".nls.json" const path = nlsConfig._resolvedLanguagePackCoreLocation + "/" + bundle.replace(/\//g, "!") + ".nls.json"
fetch(`{{BASE}}/resource/?path=${encodeURIComponent(path)}`) fetch(`${options.base}/vscode/resource/?path=${encodeURIComponent(path)}`)
.then((response) => response.json()) .then((response) => response.json())
.then((json) => { .then((json) => {
bundles[bundle] = json bundles[bundle] = json

View File

@ -10,7 +10,7 @@ if ("serviceWorker" in navigator) {
const path = normalize(`${options.csStaticBase}/dist/serviceWorker.js`) const path = normalize(`${options.csStaticBase}/dist/serviceWorker.js`)
navigator.serviceWorker navigator.serviceWorker
.register(path, { .register(path, {
scope: options.base || "/", scope: (options.base ?? "") + "/",
}) })
.then(() => { .then(() => {
console.log("[Service Worker] registered") console.log("[Service Worker] registered")

2
src/browser/robots.txt Normal file
View File

@ -0,0 +1,2 @@
User-agent: *
Disallow: /

View File

@ -1,6 +1,4 @@
import * as http from "http" import { HttpProvider, HttpResponse, Heart, HttpProviderOptions } from "../http"
import { HttpCode, HttpError } from "../../common/http"
import { HttpProvider, HttpResponse, Route, Heart, HttpProviderOptions } from "../http"
/** /**
* Check the heartbeat. * Check the heartbeat.
@ -10,15 +8,8 @@ export class HealthHttpProvider extends HttpProvider {
super(options) super(options)
} }
public async handleRequest(route: Route, request: http.IncomingMessage): Promise<HttpResponse> { public async handleRequest(): Promise<HttpResponse> {
if (!this.authenticated(request)) { return {
if (this.isRoot(route)) {
return { redirect: "/login", query: { to: route.fullPath } }
}
throw new HttpError("Unauthorized", HttpCode.Unauthorized)
}
const result = {
cache: false, cache: false,
mime: "application/json", mime: "application/json",
content: { content: {
@ -26,7 +17,5 @@ export class HealthHttpProvider extends HttpProvider {
lastHeartbeat: this.heart.lastHeartbeat, lastHeartbeat: this.heart.lastHeartbeat,
}, },
} }
return result
} }
} }

View File

@ -5,7 +5,7 @@ import * as os from "os"
import * as path from "path" import * as path from "path"
import { Args as VsArgs } from "../../lib/vscode/src/vs/server/ipc" import { Args as VsArgs } from "../../lib/vscode/src/vs/server/ipc"
import { AuthType } from "./http" import { AuthType } from "./http"
import { generatePassword, humanPath, paths } from "./util" import { canConnect, generatePassword, humanPath, paths } from "./util"
export class Optional<T> { export class Optional<T> {
public constructor(public readonly value?: T) {} public constructor(public readonly value?: T) {}
@ -47,6 +47,8 @@ export interface Args extends VsArgs {
readonly _: string[] readonly _: string[]
readonly "reuse-window"?: boolean readonly "reuse-window"?: boolean
readonly "new-window"?: boolean readonly "new-window"?: boolean
readonly link?: OptionalString
} }
interface Option<T> { interface Option<T> {
@ -63,6 +65,11 @@ interface Option<T> {
* Description of the option. Leave blank to hide the option. * Description of the option. Leave blank to hide the option.
*/ */
description?: string description?: string
/**
* If marked as beta, the option is not printed unless $CS_BETA is set.
*/
beta?: boolean
} }
type OptionType<T> = T extends boolean type OptionType<T> = T extends boolean
@ -130,7 +137,8 @@ const options: Options<Required<Args>> = {
"install-extension": { "install-extension": {
type: "string[]", type: "string[]",
description: description:
"Install or update a VS Code extension by id or vsix. The identifier of an extension is `${publisher}.${name}`. To install a specific version provide `@${version}`. For example: 'vscode.csharp@1.2.3'.", "Install or update a VS Code extension by id or vsix. The identifier of an extension is `${publisher}.${name}`.\n" +
"To install a specific version provide `@${version}`. For example: 'vscode.csharp@1.2.3'.",
}, },
"enable-proposed-api": { "enable-proposed-api": {
type: "string[]", type: "string[]",
@ -144,17 +152,29 @@ const options: Options<Required<Args>> = {
"new-window": { "new-window": {
type: "boolean", type: "boolean",
short: "n", short: "n",
description: "Force to open a new window. (use with open-in)", description: "Force to open a new window.",
}, },
"reuse-window": { "reuse-window": {
type: "boolean", type: "boolean",
short: "r", short: "r",
description: "Force to open a file or folder in an already opened window. (use with open-in)", description: "Force to open a file or folder in an already opened window.",
}, },
locale: { type: "string" }, locale: { type: "string" },
log: { type: LogLevel }, log: { type: LogLevel },
verbose: { type: "boolean", short: "vvv", description: "Enable verbose logging." }, verbose: { type: "boolean", short: "vvv", description: "Enable verbose logging." },
link: {
type: OptionalString,
description: `
Securely bind code-server via Coder Cloud with the passed name. You'll get a URL like
https://myname.coder-cloud.com at which you can easily access your code-server instance.
Authorization is done via GitHub.
This is presently beta and requires being accepted for testing.
See https://github.com/cdr/code-server/discussions/2137
`,
beta: true,
},
} }
export const optionDescriptions = (): string[] => { export const optionDescriptions = (): string[] => {
@ -166,12 +186,32 @@ export const optionDescriptions = (): string[] => {
}), }),
{ short: 0, long: 0 }, { short: 0, long: 0 },
) )
return entries.map( return entries
([k, v]) => .filter(([, v]) => {
`${" ".repeat(widths.short - (v.short ? v.short.length : 0))}${v.short ? `-${v.short}` : " "} --${k}${" ".repeat( // If CS_BETA is set, we show beta options but if not, then we do not want
widths.long - k.length, // to show beta options.
)} ${v.description}${typeof v.type === "object" ? ` [${Object.values(v.type).join(", ")}]` : ""}`, return process.env.CS_BETA || !v.beta
})
.map(([k, v]) => {
const help = `${" ".repeat(widths.short - (v.short ? v.short.length : 0))}${
v.short ? `-${v.short}` : " "
} --${k} `
return (
help +
v.description
?.trim()
.split(/\n/)
.map((line, i) => {
line = line.trim()
if (i === 0) {
return " ".repeat(widths.long - k.length) + line
}
return " ".repeat(widths.long + widths.short + 6) + line
})
.join("\n") +
(typeof v.type === "object" ? ` [${Object.values(v.type).join(", ")}]` : "")
) )
})
} }
export const parse = ( export const parse = (
@ -287,6 +327,21 @@ export const parse = (
logger.debug("parsed command line", field("args", args)) logger.debug("parsed command line", field("args", args))
return args
}
export async function setDefaults(args: Args): Promise<Args> {
args = { ...args }
if (!args["user-data-dir"]) {
await copyOldMacOSDataDir()
args["user-data-dir"] = paths.data
}
if (!args["extensions-dir"]) {
args["extensions-dir"] = path.join(args["user-data-dir"], "extensions")
}
// --verbose takes priority over --log and --log takes priority over the // --verbose takes priority over --log and --log takes priority over the
// environment variable. // environment variable.
if (args.verbose) { if (args.verbose) {
@ -329,21 +384,6 @@ export const parse = (
return args return args
} }
export async function setDefaults(args: Args): Promise<Args> {
args = { ...args }
if (!args["user-data-dir"]) {
await copyOldMacOSDataDir()
args["user-data-dir"] = paths.data
}
if (!args["extensions-dir"]) {
args["extensions-dir"] = path.join(args["user-data-dir"], "extensions")
}
return args
}
async function defaultConfigFile(): Promise<string> { async function defaultConfigFile(): Promise<string> {
return `bind-addr: 127.0.0.1:8080 return `bind-addr: 127.0.0.1:8080
auth: password auth: password
@ -370,10 +410,6 @@ export async function readConfigFile(configPath?: string): Promise<Args> {
logger.info(`Wrote default config file to ${humanPath(configPath)}`) logger.info(`Wrote default config file to ${humanPath(configPath)}`)
} }
if (!process.env.CODE_SERVER_PARENT_PID && !process.env.VSCODE_IPC_HOOK_CLI) {
logger.info(`Using config file ${humanPath(configPath)}`)
}
const configFile = await fs.readFile(configPath) const configFile = await fs.readFile(configPath)
const config = yaml.safeLoad(configFile.toString(), { const config = yaml.safeLoad(configFile.toString(), {
filename: configPath, filename: configPath,
@ -401,7 +437,10 @@ export async function readConfigFile(configPath?: string): Promise<Args> {
function parseBindAddr(bindAddr: string): [string, number] { function parseBindAddr(bindAddr: string): [string, number] {
const u = new URL(`http://${bindAddr}`) const u = new URL(`http://${bindAddr}`)
return [u.hostname, parseInt(u.port, 10)] // With the http scheme 80 will be dropped so assume it's 80 if missing. This
// means --bind-addr <addr> without a port will default to 80 as well and not
// the code-server default.
return [u.hostname, u.port ? parseInt(u.port, 10) : 80]
} }
interface Addr { interface Addr {
@ -453,3 +492,52 @@ async function copyOldMacOSDataDir(): Promise<void> {
await fs.copy(oldDataDir, paths.data) await fs.copy(oldDataDir, paths.data)
} }
} }
export const shouldRunVsCodeCli = (args: Args): boolean => {
return !!args["list-extensions"] || !!args["install-extension"] || !!args["uninstall-extension"]
}
/**
* Determine if it looks like the user is trying to open a file or folder in an
* existing instance. The arguments here should be the arguments the user
* explicitly passed on the command line, not defaults or the configuration.
*/
export const shouldOpenInExistingInstance = async (args: Args): Promise<string | undefined> => {
// Always use the existing instance if we're running from VS Code's terminal.
if (process.env.VSCODE_IPC_HOOK_CLI) {
return process.env.VSCODE_IPC_HOOK_CLI
}
const readSocketPath = async (): Promise<string | undefined> => {
try {
return await fs.readFile(path.join(os.tmpdir(), "vscode-ipc"), "utf8")
} catch (error) {
if (error.code !== "ENOENT") {
throw error
}
}
return undefined
}
// If these flags are set then assume the user is trying to open in an
// existing instance since these flags have no effect otherwise.
const openInFlagCount = ["reuse-window", "new-window"].reduce((prev, cur) => {
return args[cur as keyof Args] ? prev + 1 : prev
}, 0)
if (openInFlagCount > 0) {
return readSocketPath()
}
// It's possible the user is trying to spawn another instance of code-server.
// Check if any unrelated flags are set (check against one because `_` always
// exists), that a file or directory was passed, and that the socket is
// active.
if (Object.keys(args).length === 1 && args._.length > 0) {
const socketPath = await readSocketPath()
if (socketPath && (await canConnect(socketPath))) {
return socketPath
}
}
return undefined
}

43
src/node/coder-cloud.ts Normal file
View File

@ -0,0 +1,43 @@
import { logger } from "@coder/logger"
import { spawn } from "child_process"
import path from "path"
import split2 from "split2"
// https://github.com/cdr/coder-cloud
const coderCloudAgent = path.resolve(__dirname, "../../lib/coder-cloud-agent")
function runAgent(...args: string[]): Promise<void> {
logger.debug(`running agent with ${args}`)
const agent = spawn(coderCloudAgent, args, {
stdio: ["inherit", "inherit", "pipe"],
})
agent.stderr.pipe(split2()).on("data", (line) => {
line = line.replace(/^[0-9-]+ [0-9:]+ [^ ]+\t/, "")
logger.info(line)
})
return new Promise((res, rej) => {
agent.on("error", rej)
agent.on("close", (code) => {
if (code !== 0) {
rej({
message: `coder cloud agent exited with ${code}`,
})
return
}
res()
})
})
}
export function coderCloudBind(csAddr: string, serverName = ""): Promise<void> {
logger.info("Remember --link is a beta feature and requires being accepted for testing")
logger.info("See https://github.com/cdr/code-server/discussions/2137")
// addr needs to be in host:port format.
// So we trim the protocol.
csAddr = csAddr.replace(/^https?:\/\//, "")
return runAgent("bind", `--code-server-addr=${csAddr}`, serverName)
}

View File

@ -11,18 +11,21 @@ import { ProxyHttpProvider } from "./app/proxy"
import { StaticHttpProvider } from "./app/static" import { StaticHttpProvider } from "./app/static"
import { UpdateHttpProvider } from "./app/update" import { UpdateHttpProvider } from "./app/update"
import { VscodeHttpProvider } from "./app/vscode" import { VscodeHttpProvider } from "./app/vscode"
import { Args, bindAddrFromAllSources, optionDescriptions, parse, readConfigFile, setDefaults } from "./cli" import {
Args,
bindAddrFromAllSources,
optionDescriptions,
parse,
readConfigFile,
setDefaults,
shouldOpenInExistingInstance,
shouldRunVsCodeCli,
} from "./cli"
import { coderCloudBind } from "./coder-cloud"
import { AuthType, HttpServer, HttpServerOptions } from "./http" import { AuthType, HttpServer, HttpServerOptions } from "./http"
import { loadPlugins } from "./plugin" import { loadPlugins } from "./plugin"
import { generateCertificate, hash, humanPath, open } from "./util" import { generateCertificate, hash, humanPath, open } from "./util"
import { ipcMain, wrap } from "./wrapper" import { ipcMain, WrapperProcess } from "./wrapper"
process.on("uncaughtException", (error) => {
logger.error(`Uncaught exception: ${error.message}`)
if (typeof error.stack !== "undefined") {
logger.error(error.stack)
}
})
let pkg: { version?: string; commit?: string } = {} let pkg: { version?: string; commit?: string } = {}
try { try {
@ -34,7 +37,100 @@ try {
const version = pkg.version || "development" const version = pkg.version || "development"
const commit = pkg.commit || "development" const commit = pkg.commit || "development"
const main = async (args: Args, cliArgs: Args, configArgs: Args): Promise<void> => { export const runVsCodeCli = (args: Args): void => {
logger.debug("forking vs code cli...")
const vscode = cp.fork(path.resolve(__dirname, "../../lib/vscode/out/vs/server/fork"), [], {
env: {
...process.env,
CODE_SERVER_PARENT_PID: process.pid.toString(),
},
})
vscode.once("message", (message: any) => {
logger.debug("got message from VS Code", field("message", message))
if (message.type !== "ready") {
logger.error("Unexpected response waiting for ready response", field("type", message.type))
process.exit(1)
}
const send: CliMessage = { type: "cli", args }
vscode.send(send)
})
vscode.once("error", (error) => {
logger.error("Got error from VS Code", field("error", error))
process.exit(1)
})
vscode.on("exit", (code) => process.exit(code || 0))
}
export const openInExistingInstance = async (args: Args, socketPath: string): Promise<void> => {
const pipeArgs: OpenCommandPipeArgs & { fileURIs: string[] } = {
type: "open",
folderURIs: [],
fileURIs: [],
forceReuseWindow: args["reuse-window"],
forceNewWindow: args["new-window"],
}
const isDir = async (path: string): Promise<boolean> => {
try {
const st = await fs.stat(path)
return st.isDirectory()
} catch (error) {
return false
}
}
for (let i = 0; i < args._.length; i++) {
const fp = path.resolve(args._[i])
if (await isDir(fp)) {
pipeArgs.folderURIs.push(fp)
} else {
pipeArgs.fileURIs.push(fp)
}
}
if (pipeArgs.forceNewWindow && pipeArgs.fileURIs.length > 0) {
logger.error("--new-window can only be used with folder paths")
process.exit(1)
}
if (pipeArgs.folderURIs.length === 0 && pipeArgs.fileURIs.length === 0) {
logger.error("Please specify at least one file or folder")
process.exit(1)
}
const vscode = http.request(
{
path: "/",
method: "POST",
socketPath,
},
(response) => {
response.on("data", (message) => {
logger.debug("got message from VS Code", field("message", message.toString()))
})
},
)
vscode.on("error", (error: unknown) => {
logger.error("got error from VS Code", field("error", error))
})
vscode.write(JSON.stringify(pipeArgs))
vscode.end()
}
const main = async (args: Args, configArgs: Args): Promise<void> => {
if (args.link) {
// If we're being exposed to the cloud, we listen on a random address and disable auth.
args = {
...args,
host: "localhost",
port: 0,
auth: AuthType.None,
socket: undefined,
cert: undefined,
}
logger.info("link: disabling auth and listening on random localhost port for cloud agent")
}
if (!args.auth) { if (!args.auth) {
args = { args = {
...args, ...args,
@ -51,7 +147,7 @@ const main = async (args: Args, cliArgs: Args, configArgs: Args): Promise<void>
if (args.auth === AuthType.Password && !password) { if (args.auth === AuthType.Password && !password) {
throw new Error("Please pass in a password via the config file or $PASSWORD") throw new Error("Please pass in a password via the config file or $PASSWORD")
} }
const [host, port] = bindAddrFromAllSources(cliArgs, configArgs) const [host, port] = bindAddrFromAllSources(args, configArgs)
// Spawn the main HTTP server. // Spawn the main HTTP server.
const options: HttpServerOptions = { const options: HttpServerOptions = {
@ -85,13 +181,15 @@ const main = async (args: Args, cliArgs: Args, configArgs: Args): Promise<void>
await loadPlugins(httpServer, args) await loadPlugins(httpServer, args)
ipcMain().onDispose(() => { ipcMain.onDispose(() => {
httpServer.dispose().then((errors) => { httpServer.dispose().then((errors) => {
errors.forEach((error) => logger.error(error.message)) errors.forEach((error) => logger.error(error.message))
}) })
}) })
logger.info(`code-server ${version} ${commit}`) logger.info(`code-server ${version} ${commit}`)
logger.info(`Using config file ${humanPath(args.config)}`)
const serverAddress = await httpServer.listen() const serverAddress = await httpServer.listen()
logger.info(`HTTP server listening on ${serverAddress}`) logger.info(`HTTP server listening on ${serverAddress}`)
@ -125,27 +223,38 @@ const main = async (args: Args, cliArgs: Args, configArgs: Args): Promise<void>
if (serverAddress && !options.socket && args.open) { if (serverAddress && !options.socket && args.open) {
// The web socket doesn't seem to work if browsing with 0.0.0.0. // The web socket doesn't seem to work if browsing with 0.0.0.0.
const openAddress = serverAddress.replace(/:\/\/0.0.0.0/, "://localhost") const openAddress = serverAddress.replace(/:\/\/0.0.0.0/, "://localhost")
await open(openAddress).catch(console.error) await open(openAddress).catch((error: Error) => {
logger.error("Failed to open", field("address", openAddress), field("error", error))
})
logger.info(`Opened ${openAddress}`) logger.info(`Opened ${openAddress}`)
} }
if (args.link) {
try {
await coderCloudBind(serverAddress!, args.link.value)
} catch (err) {
logger.error(err.message)
ipcMain.exit(1)
}
}
} }
async function entry(): Promise<void> { async function entry(): Promise<void> {
const tryParse = async (): Promise<[Args, Args, Args]> => {
try {
const cliArgs = parse(process.argv.slice(2)) const cliArgs = parse(process.argv.slice(2))
const configArgs = await readConfigFile(cliArgs.config) const configArgs = await readConfigFile(cliArgs.config)
// This prioritizes the flags set in args over the ones in the config file. // This prioritizes the flags set in args over the ones in the config file.
let args = Object.assign(configArgs, cliArgs) let args = Object.assign(configArgs, cliArgs)
args = await setDefaults(args) args = await setDefaults(args)
return [args, cliArgs, configArgs]
} catch (error) { // There's no need to check flags like --help or to spawn in an existing
console.error(error.message) // instance for the child process because these would have already happened in
process.exit(1) // the parent and the child wouldn't have been spawned.
} if (ipcMain.isChild) {
await ipcMain.handshake()
ipcMain.preventExit()
return main(args, configArgs)
} }
const [args, cliArgs, configArgs] = await tryParse()
if (args.help) { if (args.help) {
console.log("code-server", version, commit) console.log("code-server", version, commit)
console.log("") console.log("")
@ -155,7 +264,10 @@ async function entry(): Promise<void> {
optionDescriptions().forEach((description) => { optionDescriptions().forEach((description) => {
console.log("", description) console.log("", description)
}) })
} else if (args.version) { return
}
if (args.version) {
if (args.json) { if (args.json) {
console.log({ console.log({
codeServer: version, codeServer: version,
@ -165,83 +277,23 @@ async function entry(): Promise<void> {
} else { } else {
console.log(version, commit) console.log(version, commit)
} }
process.exit(0) return
} else if (process.env.VSCODE_IPC_HOOK_CLI) {
const pipeArgs: OpenCommandPipeArgs = {
type: "open",
folderURIs: [],
forceReuseWindow: args["reuse-window"],
forceNewWindow: args["new-window"],
} }
const isDir = async (path: string): Promise<boolean> => {
try { if (shouldRunVsCodeCli(args)) {
const st = await fs.stat(path) return runVsCodeCli(args)
return st.isDirectory()
} catch (error) {
return false
} }
const socketPath = await shouldOpenInExistingInstance(cliArgs)
if (socketPath) {
return openInExistingInstance(args, socketPath)
} }
for (let i = 0; i < args._.length; i++) {
const fp = path.resolve(args._[i]) const wrapper = new WrapperProcess(require("../../package.json").version)
if (await isDir(fp)) { return wrapper.start()
pipeArgs.folderURIs.push(fp)
} else {
if (!pipeArgs.fileURIs) {
pipeArgs.fileURIs = []
}
pipeArgs.fileURIs.push(fp)
}
}
if (pipeArgs.forceNewWindow && pipeArgs.fileURIs && pipeArgs.fileURIs.length > 0) {
logger.error("new-window can only be used with folder paths")
process.exit(1)
}
if (pipeArgs.folderURIs.length === 0 && (!pipeArgs.fileURIs || pipeArgs.fileURIs.length === 0)) {
logger.error("Please specify at least one file or folder argument")
process.exit(1)
}
const vscode = http.request(
{
path: "/",
method: "POST",
socketPath: process.env["VSCODE_IPC_HOOK_CLI"],
},
(res) => {
res.on("data", (message) => {
logger.debug("Got message from VS Code", field("message", message.toString()))
})
},
)
vscode.on("error", (err) => {
logger.debug("Got error from VS Code", field("error", err))
})
vscode.write(JSON.stringify(pipeArgs))
vscode.end()
} else if (args["list-extensions"] || args["install-extension"] || args["uninstall-extension"]) {
logger.debug("forking vs code cli...")
const vscode = cp.fork(path.resolve(__dirname, "../../lib/vscode/out/vs/server/fork"), [], {
env: {
...process.env,
CODE_SERVER_PARENT_PID: process.pid.toString(),
},
})
vscode.once("message", (message: any) => {
logger.debug("Got message from VS Code", field("message", message))
if (message.type !== "ready") {
logger.error("Unexpected response waiting for ready response")
process.exit(1)
}
const send: CliMessage = { type: "cli", args }
vscode.send(send)
})
vscode.once("error", (error) => {
logger.error(error.message)
process.exit(1)
})
vscode.on("exit", (code) => process.exit(code || 0))
} else {
wrap(() => main(args, cliArgs, configArgs))
}
} }
entry() entry().catch((error) => {
logger.error(error.message)
ipcMain.exit(error)
})

View File

@ -289,7 +289,7 @@ export abstract class HttpProvider {
/** /**
* Helper to error if not authorized. * Helper to error if not authorized.
*/ */
protected ensureAuthenticated(request: http.IncomingMessage): void { public ensureAuthenticated(request: http.IncomingMessage): void {
if (!this.authenticated(request)) { if (!this.authenticated(request)) {
throw new HttpError("Unauthorized", HttpCode.Unauthorized) throw new HttpError("Unauthorized", HttpCode.Unauthorized)
} }
@ -578,14 +578,24 @@ export class HttpServer {
*/ */
public listen(): Promise<string | null> { public listen(): Promise<string | null> {
if (!this.listenPromise) { if (!this.listenPromise) {
this.listenPromise = new Promise((resolve, reject) => { this.listenPromise = new Promise(async (resolve, reject) => {
this.server.on("error", reject) this.server.on("error", reject)
this.server.on("upgrade", this.onUpgrade) this.server.on("upgrade", this.onUpgrade)
const onListen = (): void => resolve(this.address()) const onListen = (): void => resolve(this.address())
if (this.options.socket) { if (this.options.socket) {
try {
await fs.unlink(this.options.socket)
} catch (err) {
if (err.code !== "ENOENT") {
logger.warn(err.message)
}
}
this.server.listen(this.options.socket, onListen) this.server.listen(this.options.socket, onListen)
} else if (this.options.host) {
// [] is the correct format when using :: but Node errors with them.
this.server.listen(this.options.port, this.options.host.replace(/^\[|\]$/g, ""), onListen)
} else { } else {
this.server.listen(this.options.port, this.options.host, onListen) this.server.listen(this.options.port, onListen)
} }
}) })
} }
@ -647,10 +657,7 @@ export class HttpServer {
} }
try { try {
const payload = const payload = (await this.handleRequest(route, request)) || (await route.provider.handleRequest(route, request))
this.maybeRedirect(request, route) ||
(route.provider.authenticated(request) && this.maybeProxy(request)) ||
(await route.provider.handleRequest(route, request))
if (payload.proxy) { if (payload.proxy) {
this.doProxy(route, request, response, payload.proxy) this.doProxy(route, request, response, payload.proxy)
} else { } else {
@ -685,15 +692,23 @@ export class HttpServer {
} }
/** /**
* Return any necessary redirection before delegating to a provider. * Handle requests that are always in effect no matter what provider is
* registered at the route.
*/ */
private maybeRedirect(request: http.IncomingMessage, route: ProviderRoute): RedirectResponse | undefined { private async handleRequest(route: ProviderRoute, request: http.IncomingMessage): Promise<HttpResponse | undefined> {
// If we're handling TLS ensure all requests are redirected to HTTPS. // If we're handling TLS ensure all requests are redirected to HTTPS.
if (this.options.cert && !(request.connection as tls.TLSSocket).encrypted) { if (this.options.cert && !(request.connection as tls.TLSSocket).encrypted) {
return { redirect: route.fullPath } return { redirect: route.fullPath }
} }
return undefined // Return robots.txt.
if (route.fullPath === "/robots.txt") {
const filePath = path.resolve(__dirname, "../../src/browser/robots.txt")
return { content: await fs.readFile(filePath), filePath }
}
// Handle proxy domains.
return this.maybeProxy(route, request)
} }
/** /**
@ -744,7 +759,7 @@ export class HttpServer {
// can't be transferred so we need an in-between). // can't be transferred so we need an in-between).
const socketProxy = await this.socketProvider.createProxy(socket) const socketProxy = await this.socketProvider.createProxy(socket)
const payload = const payload =
this.maybeProxy(request) || (await route.provider.handleWebSocket(route, request, socketProxy, head)) this.maybeProxy(route, request) || (await route.provider.handleWebSocket(route, request, socketProxy, head))
if (payload && payload.proxy) { if (payload && payload.proxy) {
this.doProxy(route, request, { socket: socketProxy, head }, payload.proxy) this.doProxy(route, request, { socket: socketProxy, head }, payload.proxy)
} }
@ -894,8 +909,10 @@ export class HttpServer {
* *
* For example if `coder.com` is specified `8080.coder.com` will be proxied * For example if `coder.com` is specified `8080.coder.com` will be proxied
* but `8080.test.coder.com` and `test.8080.coder.com` will not. * but `8080.test.coder.com` and `test.8080.coder.com` will not.
*
* Throw an error if proxying but the user isn't authenticated.
*/ */
public maybeProxy(request: http.IncomingMessage): HttpResponse | undefined { public maybeProxy(route: ProviderRoute, request: http.IncomingMessage): HttpResponse | undefined {
// Split into parts. // Split into parts.
const host = request.headers.host || "" const host = request.headers.host || ""
const idx = host.indexOf(":") const idx = host.indexOf(":")
@ -909,6 +926,9 @@ export class HttpServer {
return undefined return undefined
} }
// Must be authenticated to use the proxy.
route.provider.ensureAuthenticated(request)
return { return {
proxy: { proxy: {
port, port,

View File

@ -4,11 +4,15 @@ import * as path from "path"
import * as util from "util" import * as util from "util"
import { Args } from "./cli" import { Args } from "./cli"
import { HttpServer } from "./http" import { HttpServer } from "./http"
import { paths } from "./util"
/* eslint-disable @typescript-eslint/no-var-requires */ /* eslint-disable @typescript-eslint/no-var-requires */
export type Activate = (httpServer: HttpServer, args: Args) => void export type Activate = (httpServer: HttpServer, args: Args) => void
/**
* Plugins must implement this interface.
*/
export interface Plugin { export interface Plugin {
activate: Activate activate: Activate
} }
@ -23,38 +27,66 @@ require("module")._load = function (request: string, parent: object, isMain: boo
return originalLoad.apply(this, [request.replace(/^code-server/, path.resolve(__dirname, "../..")), parent, isMain]) return originalLoad.apply(this, [request.replace(/^code-server/, path.resolve(__dirname, "../..")), parent, isMain])
} }
/**
* Load a plugin and run its activation function.
*/
const loadPlugin = async (pluginPath: string, httpServer: HttpServer, args: Args): Promise<void> => { const loadPlugin = async (pluginPath: string, httpServer: HttpServer, args: Args): Promise<void> => {
try { try {
const plugin: Plugin = require(pluginPath) const plugin: Plugin = require(pluginPath)
plugin.activate(httpServer, args) plugin.activate(httpServer, args)
logger.debug("Loaded plugin", field("name", path.basename(pluginPath)))
const packageJson = require(path.join(pluginPath, "package.json"))
logger.debug(
"Loaded plugin",
field("name", packageJson.name || path.basename(pluginPath)),
field("path", pluginPath),
field("version", packageJson.version || "n/a"),
)
} catch (error) { } catch (error) {
if (error.code !== "MODULE_NOT_FOUND") {
logger.warn(error.message)
} else {
logger.error(error.message) logger.error(error.message)
} }
}
} }
const _loadPlugins = async (httpServer: HttpServer, args: Args): Promise<void> => { /**
const pluginPath = path.resolve(__dirname, "../../plugins") * Load all plugins in the specified directory.
const files = await util.promisify(fs.readdir)(pluginPath, { */
const _loadPlugins = async (pluginDir: string, httpServer: HttpServer, args: Args): Promise<void> => {
try {
const files = await util.promisify(fs.readdir)(pluginDir, {
withFileTypes: true, withFileTypes: true,
}) })
await Promise.all(files.map((file) => loadPlugin(path.join(pluginPath, file.name), httpServer, args))) await Promise.all(files.map((file) => loadPlugin(path.join(pluginDir, file.name), httpServer, args)))
}
export const loadPlugins = async (httpServer: HttpServer, args: Args): Promise<void> => {
try {
await _loadPlugins(httpServer, args)
} catch (error) { } catch (error) {
if (error.code !== "ENOENT") { if (error.code !== "ENOENT") {
logger.warn(error.message) logger.warn(error.message)
} }
} }
}
if (process.env.PLUGIN_DIR) {
await loadPlugin(process.env.PLUGIN_DIR, httpServer, args) /**
} * Load all plugins from the `plugins` directory, directories specified by
* `CS_PLUGIN_PATH` (colon-separated), and individual plugins specified by
* `CS_PLUGIN` (also colon-separated).
*/
export const loadPlugins = async (httpServer: HttpServer, args: Args): Promise<void> => {
const pluginPath = process.env.CS_PLUGIN_PATH || `${path.join(paths.data, "plugins")}:/usr/share/code-server/plugins`
const plugin = process.env.CS_PLUGIN || ""
await Promise.all([
// Built-in plugins.
_loadPlugins(path.resolve(__dirname, "../../plugins"), httpServer, args),
// User-added plugins.
...pluginPath
.split(":")
.filter((p) => !!p)
.map((dir) => _loadPlugins(path.resolve(dir), httpServer, args)),
// Individual plugins so you don't have to symlink or move them into a
// directory specifically for plugins. This lets you load plugins that are
// on the same level as other directories that are not plugins (if you tried
// to use CS_PLUGIN_PATH code-server would try to load those other
// directories as plugins). Intended for development.
...plugin
.split(":")
.filter((p) => !!p)
.map((dir) => loadPlugin(path.resolve(dir), httpServer, args)),
])
} }

View File

@ -4,7 +4,7 @@ import * as path from "path"
import * as tls from "tls" import * as tls from "tls"
import { Emitter } from "../common/emitter" import { Emitter } from "../common/emitter"
import { generateUuid } from "../common/util" import { generateUuid } from "../common/util"
import { tmpdir } from "./util" import { canConnect, tmpdir } from "./util"
/** /**
* Provides a way to proxy a TLS socket. Can be used when you need to pass a * Provides a way to proxy a TLS socket. Can be used when you need to pass a
@ -89,17 +89,6 @@ export class SocketProxyProvider {
} }
public async findFreeSocketPath(basePath: string, maxTries = 100): Promise<string> { public async findFreeSocketPath(basePath: string, maxTries = 100): Promise<string> {
const canConnect = (path: string): Promise<boolean> => {
return new Promise((resolve) => {
const socket = net.connect(path)
socket.once("error", () => resolve(false))
socket.once("connect", () => {
socket.destroy()
resolve(true)
})
})
}
let i = 0 let i = 0
let path = basePath let path = basePath
while ((await canConnect(path)) && i < maxTries) { while ((await canConnect(path)) && i < maxTries) {

View File

@ -2,6 +2,7 @@ import * as cp from "child_process"
import * as crypto from "crypto" import * as crypto from "crypto"
import envPaths from "env-paths" import envPaths from "env-paths"
import * as fs from "fs-extra" import * as fs from "fs-extra"
import * as net from "net"
import * as os from "os" import * as os from "os"
import * as path from "path" import * as path from "path"
import * as util from "util" import * as util from "util"
@ -246,3 +247,17 @@ export function pathToFsPath(path: string, keepDriveLetterCasing = false): strin
} }
return value return value
} }
/**
* Return a promise that resolves with whether the socket path is active.
*/
export function canConnect(path: string): Promise<boolean> {
return new Promise((resolve) => {
const socket = net.connect(path)
socket.once("error", () => resolve(false))
socket.once("connect", () => {
socket.destroy()
resolve(true)
})
})
}

View File

@ -32,19 +32,13 @@ export class IpcMain {
public readonly onMessage = this._onMessage.event public readonly onMessage = this._onMessage.event
private readonly _onDispose = new Emitter<NodeJS.Signals | undefined>() private readonly _onDispose = new Emitter<NodeJS.Signals | undefined>()
public readonly onDispose = this._onDispose.event public readonly onDispose = this._onDispose.event
public readonly processExit: (code?: number) => never public readonly processExit: (code?: number) => never = process.exit
public constructor(public readonly parentPid?: number) { public constructor(private readonly parentPid?: number) {
process.on("SIGINT", () => this._onDispose.emit("SIGINT")) process.on("SIGINT", () => this._onDispose.emit("SIGINT"))
process.on("SIGTERM", () => this._onDispose.emit("SIGTERM")) process.on("SIGTERM", () => this._onDispose.emit("SIGTERM"))
process.on("exit", () => this._onDispose.emit(undefined)) process.on("exit", () => this._onDispose.emit(undefined))
// Ensure we control when the process exits.
this.processExit = process.exit
process.exit = function (code?: number) {
logger.warn(`process.exit() was prevented: ${code || "unknown code"}.`)
} as (code?: number) => never
this.onDispose((signal) => { this.onDispose((signal) => {
// Remove listeners to avoid possibly triggering disposal again. // Remove listeners to avoid possibly triggering disposal again.
process.removeAllListeners() process.removeAllListeners()
@ -71,6 +65,19 @@ export class IpcMain {
} }
} }
/**
* Ensure we control when the process exits.
*/
public preventExit(): void {
process.exit = function (code?: number) {
logger.warn(`process.exit() was prevented: ${code || "unknown code"}.`)
} as (code?: number) => never
}
public get isChild(): boolean {
return typeof this.parentPid !== "undefined"
}
public exit(error?: number | ProcessError): never { public exit(error?: number | ProcessError): never {
if (error && typeof error !== "number") { if (error && typeof error !== "number") {
this.processExit(typeof error.code === "number" ? error.code : 1) this.processExit(typeof error.code === "number" ? error.code : 1)
@ -127,17 +134,12 @@ export class IpcMain {
} }
} }
let _ipcMain: IpcMain /**
export const ipcMain = (): IpcMain => { * Channel for communication between the child and parent processes.
if (!_ipcMain) { */
_ipcMain = new IpcMain( export const ipcMain = new IpcMain(
typeof process.env.CODE_SERVER_PARENT_PID !== "undefined" typeof process.env.CODE_SERVER_PARENT_PID !== "undefined" ? parseInt(process.env.CODE_SERVER_PARENT_PID) : undefined,
? parseInt(process.env.CODE_SERVER_PARENT_PID) )
: undefined,
)
}
return _ipcMain
}
export interface WrapperOptions { export interface WrapperOptions {
maxMemory?: number maxMemory?: number
@ -162,14 +164,11 @@ export class WrapperProcess {
this.logStdoutStream = rfs.createStream(path.join(paths.data, "coder-logs", "code-server-stdout.log"), opts) this.logStdoutStream = rfs.createStream(path.join(paths.data, "coder-logs", "code-server-stdout.log"), opts)
this.logStderrStream = rfs.createStream(path.join(paths.data, "coder-logs", "code-server-stderr.log"), opts) this.logStderrStream = rfs.createStream(path.join(paths.data, "coder-logs", "code-server-stderr.log"), opts)
ipcMain().onDispose(() => { ipcMain.onDispose(() => {
if (this.process) { this.disposeChild()
this.process.removeAllListeners()
this.process.kill()
}
}) })
ipcMain().onMessage((message) => { ipcMain.onMessage((message) => {
switch (message.type) { switch (message.type) {
case "relaunch": case "relaunch":
logger.info(`Relaunching: ${this.currentVersion} -> ${message.version}`) logger.info(`Relaunching: ${this.currentVersion} -> ${message.version}`)
@ -181,30 +180,44 @@ export class WrapperProcess {
break break
} }
}) })
process.on("SIGUSR1", async () => {
logger.info("Received SIGUSR1; hotswapping")
this.relaunch()
})
} }
private async relaunch(): Promise<void> { private disposeChild(): void {
this.started = undefined this.started = undefined
if (this.process) { if (this.process) {
this.process.removeAllListeners() this.process.removeAllListeners()
this.process.kill() this.process.kill()
} }
}
private async relaunch(): Promise<void> {
this.disposeChild()
try { try {
await this.start() await this.start()
} catch (error) { } catch (error) {
logger.error(error.message) logger.error(error.message)
ipcMain().exit(typeof error.code === "number" ? error.code : 1) ipcMain.exit(typeof error.code === "number" ? error.code : 1)
} }
} }
public start(): Promise<void> { public start(): Promise<void> {
// If we have a process then we've already bound this.
if (!this.process) {
process.on("SIGUSR1", async () => {
logger.info("Received SIGUSR1; hotswapping")
this.relaunch()
})
}
if (!this.started) { if (!this.started) {
this.started = this.spawn().then((child) => { this.started = this._start()
}
return this.started
}
private async _start(): Promise<void> {
const child = this.spawn()
this.process = child
// Log both to stdout and to the log directory. // Log both to stdout and to the log directory.
if (child.stdout) { if (child.stdout) {
child.stdout.pipe(this.logStdoutStream) child.stdout.pipe(this.logStdoutStream)
@ -214,22 +227,18 @@ export class WrapperProcess {
child.stderr.pipe(this.logStderrStream) child.stderr.pipe(this.logStderrStream)
child.stderr.pipe(process.stderr) child.stderr.pipe(process.stderr)
} }
logger.debug(`spawned inner process ${child.pid}`) logger.debug(`spawned inner process ${child.pid}`)
ipcMain()
.handshake(child) await ipcMain.handshake(child)
.then(() => {
child.once("exit", (code) => { child.once("exit", (code) => {
logger.debug(`inner process ${child.pid} exited unexpectedly`) logger.debug(`inner process ${child.pid} exited unexpectedly`)
ipcMain().exit(code || 0) ipcMain.exit(code || 0)
}) })
})
this.process = child
})
}
return this.started
} }
private async spawn(): Promise<cp.ChildProcess> { private spawn(): cp.ChildProcess {
// Flags to pass along to the Node binary. // Flags to pass along to the Node binary.
let nodeOptions = `${process.env.NODE_OPTIONS || ""} ${(this.options && this.options.nodeOptions) || ""}` let nodeOptions = `${process.env.NODE_OPTIONS || ""} ${(this.options && this.options.nodeOptions) || ""}`
if (!/max_old_space_size=(\d+)/g.exec(nodeOptions)) { if (!/max_old_space_size=(\d+)/g.exec(nodeOptions)) {
@ -251,23 +260,13 @@ export class WrapperProcess {
// It's possible that the pipe has closed (for example if you run code-server // It's possible that the pipe has closed (for example if you run code-server
// --version | head -1). Assume that means we're done. // --version | head -1). Assume that means we're done.
if (!process.stdout.isTTY) { if (!process.stdout.isTTY) {
process.stdout.on("error", () => ipcMain().exit()) process.stdout.on("error", () => ipcMain.exit())
} }
export const wrap = (fn: () => Promise<void>): void => { // Don't let uncaught exceptions crash the process.
if (ipcMain().parentPid) { process.on("uncaughtException", (error) => {
ipcMain() logger.error(`Uncaught exception: ${error.message}`)
.handshake() if (typeof error.stack !== "undefined") {
.then(() => fn()) logger.error(error.stack)
.catch((error: ProcessError): void => {
logger.error(error.message)
ipcMain().exit(error)
})
} else {
const wrapper = new WrapperProcess(require("../../package.json").version)
wrapper.start().catch((error) => {
logger.error(error.message)
ipcMain().exit(error)
})
} }
} })

View File

@ -1,20 +1,31 @@
import { logger, Level } from "@coder/logger" import { Level, logger } from "@coder/logger"
import * as assert from "assert" import * as assert from "assert"
import * as fs from "fs-extra"
import * as net from "net"
import * as os from "os"
import * as path from "path" import * as path from "path"
import { parse } from "../src/node/cli" import { Args, parse, setDefaults, shouldOpenInExistingInstance } from "../src/node/cli"
import { paths, tmpdir } from "../src/node/util"
describe("cli", () => { type Mutable<T> = {
-readonly [P in keyof T]: T[P]
}
describe("parser", () => {
beforeEach(() => { beforeEach(() => {
delete process.env.LOG_LEVEL delete process.env.LOG_LEVEL
}) })
// The parser will always fill these out. // The parser should not set any defaults so the caller can determine what
// values the user actually set. These are only set after explicitly calling
// `setDefaults`.
const defaults = { const defaults = {
_: [], "extensions-dir": path.join(paths.data, "extensions"),
"user-data-dir": paths.data,
} }
it("should set defaults", () => { it("should set defaults", () => {
assert.deepEqual(parse([]), defaults) assert.deepEqual(parse([]), { _: [] })
}) })
it("should parse all available options", () => { it("should parse all available options", () => {
@ -69,7 +80,7 @@ describe("cli", () => {
help: true, help: true,
host: "0.0.0.0", host: "0.0.0.0",
json: true, json: true,
log: "trace", log: "error",
open: true, open: true,
port: 8081, port: 8081,
socket: path.resolve("mumble"), socket: path.resolve("mumble"),
@ -83,19 +94,20 @@ describe("cli", () => {
it("should work with short options", () => { it("should work with short options", () => {
assert.deepEqual(parse(["-vvv", "-v"]), { assert.deepEqual(parse(["-vvv", "-v"]), {
...defaults, _: [],
log: "trace",
verbose: true, verbose: true,
version: true, version: true,
}) })
assert.equal(process.env.LOG_LEVEL, "trace")
assert.equal(logger.level, Level.Trace)
}) })
it("should use log level env var", () => { it("should use log level env var", async () => {
const args = parse([])
assert.deepEqual(args, { _: [] })
process.env.LOG_LEVEL = "debug" process.env.LOG_LEVEL = "debug"
assert.deepEqual(parse([]), { assert.deepEqual(await setDefaults(args), {
...defaults, ...defaults,
_: [],
log: "debug", log: "debug",
verbose: false, verbose: false,
}) })
@ -103,8 +115,9 @@ describe("cli", () => {
assert.equal(logger.level, Level.Debug) assert.equal(logger.level, Level.Debug)
process.env.LOG_LEVEL = "trace" process.env.LOG_LEVEL = "trace"
assert.deepEqual(parse([]), { assert.deepEqual(await setDefaults(args), {
...defaults, ...defaults,
_: [],
log: "trace", log: "trace",
verbose: true, verbose: true,
}) })
@ -113,9 +126,16 @@ describe("cli", () => {
}) })
it("should prefer --log to env var and --verbose to --log", async () => { it("should prefer --log to env var and --verbose to --log", async () => {
let args = parse(["--log", "info"])
assert.deepEqual(args, {
_: [],
log: "info",
})
process.env.LOG_LEVEL = "debug" process.env.LOG_LEVEL = "debug"
assert.deepEqual(parse(["--log", "info"]), { assert.deepEqual(await setDefaults(args), {
...defaults, ...defaults,
_: [],
log: "info", log: "info",
verbose: false, verbose: false,
}) })
@ -123,17 +143,26 @@ describe("cli", () => {
assert.equal(logger.level, Level.Info) assert.equal(logger.level, Level.Info)
process.env.LOG_LEVEL = "trace" process.env.LOG_LEVEL = "trace"
assert.deepEqual(parse(["--log", "info"]), { assert.deepEqual(await setDefaults(args), {
...defaults, ...defaults,
_: [],
log: "info", log: "info",
verbose: false, verbose: false,
}) })
assert.equal(process.env.LOG_LEVEL, "info") assert.equal(process.env.LOG_LEVEL, "info")
assert.equal(logger.level, Level.Info) assert.equal(logger.level, Level.Info)
args = parse(["--log", "info", "--verbose"])
assert.deepEqual(args, {
_: [],
log: "info",
verbose: true,
})
process.env.LOG_LEVEL = "warn" process.env.LOG_LEVEL = "warn"
assert.deepEqual(parse(["--log", "info", "--verbose"]), { assert.deepEqual(await setDefaults(args), {
...defaults, ...defaults,
_: [],
log: "trace", log: "trace",
verbose: true, verbose: true,
}) })
@ -141,9 +170,12 @@ describe("cli", () => {
assert.equal(logger.level, Level.Trace) assert.equal(logger.level, Level.Trace)
}) })
it("should ignore invalid log level env var", () => { it("should ignore invalid log level env var", async () => {
process.env.LOG_LEVEL = "bogus" process.env.LOG_LEVEL = "bogus"
assert.deepEqual(parse([]), defaults) assert.deepEqual(await setDefaults(parse([])), {
_: [],
...defaults,
})
}) })
it("should error if value isn't provided", () => { it("should error if value isn't provided", () => {
@ -166,7 +198,7 @@ describe("cli", () => {
it("should not error if the value is optional", () => { it("should not error if the value is optional", () => {
assert.deepEqual(parse(["--cert"]), { assert.deepEqual(parse(["--cert"]), {
...defaults, _: [],
cert: { cert: {
value: undefined, value: undefined,
}, },
@ -177,7 +209,7 @@ describe("cli", () => {
assert.throws(() => parse(["--socket", "--socket-path-value"]), /--socket requires a value/) assert.throws(() => parse(["--socket", "--socket-path-value"]), /--socket requires a value/)
// If you actually had a path like this you would do this instead: // If you actually had a path like this you would do this instead:
assert.deepEqual(parse(["--socket", "./--socket-path-value"]), { assert.deepEqual(parse(["--socket", "./--socket-path-value"]), {
...defaults, _: [],
socket: path.resolve("--socket-path-value"), socket: path.resolve("--socket-path-value"),
}) })
assert.throws(() => parse(["--cert", "--socket-path-value"]), /Unknown option --socket-path-value/) assert.throws(() => parse(["--cert", "--socket-path-value"]), /Unknown option --socket-path-value/)
@ -185,7 +217,6 @@ describe("cli", () => {
it("should allow positional arguments before options", () => { it("should allow positional arguments before options", () => {
assert.deepEqual(parse(["foo", "test", "--auth", "none"]), { assert.deepEqual(parse(["foo", "test", "--auth", "none"]), {
...defaults,
_: ["foo", "test"], _: ["foo", "test"],
auth: "none", auth: "none",
}) })
@ -193,12 +224,85 @@ describe("cli", () => {
it("should support repeatable flags", () => { it("should support repeatable flags", () => {
assert.deepEqual(parse(["--proxy-domain", "*.coder.com"]), { assert.deepEqual(parse(["--proxy-domain", "*.coder.com"]), {
...defaults, _: [],
"proxy-domain": ["*.coder.com"], "proxy-domain": ["*.coder.com"],
}) })
assert.deepEqual(parse(["--proxy-domain", "*.coder.com", "--proxy-domain", "test.com"]), { assert.deepEqual(parse(["--proxy-domain", "*.coder.com", "--proxy-domain", "test.com"]), {
...defaults, _: [],
"proxy-domain": ["*.coder.com", "test.com"], "proxy-domain": ["*.coder.com", "test.com"],
}) })
}) })
}) })
describe("cli", () => {
let args: Mutable<Args> = { _: [] }
const testDir = path.join(tmpdir, "tests/cli")
const vscodeIpcPath = path.join(os.tmpdir(), "vscode-ipc")
before(async () => {
await fs.remove(testDir)
await fs.mkdirp(testDir)
})
beforeEach(async () => {
delete process.env.VSCODE_IPC_HOOK_CLI
args = { _: [] }
await fs.remove(vscodeIpcPath)
})
it("should use existing if inside code-server", async () => {
process.env.VSCODE_IPC_HOOK_CLI = "test"
assert.strictEqual(await shouldOpenInExistingInstance(args), "test")
args.port = 8081
args._.push("./file")
assert.strictEqual(await shouldOpenInExistingInstance(args), "test")
})
it("should use existing if --reuse-window is set", async () => {
args["reuse-window"] = true
assert.strictEqual(await shouldOpenInExistingInstance(args), undefined)
await fs.writeFile(vscodeIpcPath, "test")
assert.strictEqual(await shouldOpenInExistingInstance(args), "test")
args.port = 8081
assert.strictEqual(await shouldOpenInExistingInstance(args), "test")
})
it("should use existing if --new-window is set", async () => {
args["new-window"] = true
assert.strictEqual(await shouldOpenInExistingInstance(args), undefined)
await fs.writeFile(vscodeIpcPath, "test")
assert.strictEqual(await shouldOpenInExistingInstance(args), "test")
args.port = 8081
assert.strictEqual(await shouldOpenInExistingInstance(args), "test")
})
it("should use existing if no unrelated flags are set, has positional, and socket is active", async () => {
assert.strictEqual(await shouldOpenInExistingInstance(args), undefined)
args._.push("./file")
assert.strictEqual(await shouldOpenInExistingInstance(args), undefined)
const socketPath = path.join(testDir, "socket")
await fs.writeFile(vscodeIpcPath, socketPath)
assert.strictEqual(await shouldOpenInExistingInstance(args), undefined)
await new Promise((resolve) => {
const server = net.createServer(() => {
// Close after getting the first connection.
server.close()
})
server.once("listening", () => resolve(server))
server.listen(socketPath)
})
assert.strictEqual(await shouldOpenInExistingInstance(args), socketPath)
args.port = 8081
assert.strictEqual(await shouldOpenInExistingInstance(args), undefined)
})
})

View File

@ -8,6 +8,7 @@ import { SettingsProvider, UpdateSettings } from "../src/node/settings"
import { tmpdir } from "../src/node/util" import { tmpdir } from "../src/node/util"
describe("update", () => { describe("update", () => {
return
let version = "1.0.0" let version = "1.0.0"
let spy: string[] = [] let spy: string[] = []
const server = http.createServer((request: http.IncomingMessage, response: http.ServerResponse) => { const server = http.createServer((request: http.IncomingMessage, response: http.ServerResponse) => {

View File

@ -1107,6 +1107,13 @@
resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.3.tgz#3ad6ed949e7487e7bda6f886b4a2434a2c3d7b1a" resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.3.tgz#3ad6ed949e7487e7bda6f886b4a2434a2c3d7b1a"
integrity sha512-jQxClWFzv9IXdLdhSaTf16XI3NYe6zrEbckSpb5xhKfPbWgIyAY0AFyWWWfaiDcBuj3UHmMkCIwSRqpKMTZL2Q== integrity sha512-jQxClWFzv9IXdLdhSaTf16XI3NYe6zrEbckSpb5xhKfPbWgIyAY0AFyWWWfaiDcBuj3UHmMkCIwSRqpKMTZL2Q==
"@types/split2@^2.1.6":
version "2.1.6"
resolved "https://registry.yarnpkg.com/@types/split2/-/split2-2.1.6.tgz#b095c9e064853824b22c67993d99b066777402b1"
integrity sha512-ddaFSOMuy2Rp97l6q/LEteQygvTQJuEZ+SRhxFKR0uXGsdbFDqX/QF2xoGcOqLQ8XV91v01SnAv2vpgihNgW/Q==
dependencies:
"@types/node" "*"
"@types/tar-fs@^2.0.0": "@types/tar-fs@^2.0.0":
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/@types/tar-fs/-/tar-fs-2.0.0.tgz#db94cb4ea1cccecafe3d1a53812807efb4bbdbc1" resolved "https://registry.yarnpkg.com/@types/tar-fs/-/tar-fs-2.0.0.tgz#db94cb4ea1cccecafe3d1a53812807efb4bbdbc1"
@ -5996,7 +6003,7 @@ readable-stream@^2.0.2, readable-stream@^2.2.2, readable-stream@^2.3.3, readable
string_decoder "~1.1.1" string_decoder "~1.1.1"
util-deprecate "~1.0.1" util-deprecate "~1.0.1"
readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0: readable-stream@^3.0.0, readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0:
version "3.6.0" version "3.6.0"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198"
integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==
@ -6621,6 +6628,13 @@ split-string@^3.0.1, split-string@^3.0.2:
dependencies: dependencies:
extend-shallow "^3.0.0" extend-shallow "^3.0.0"
split2@^3.2.2:
version "3.2.2"
resolved "https://registry.yarnpkg.com/split2/-/split2-3.2.2.tgz#bf2cf2a37d838312c249c89206fd7a17dd12365f"
integrity sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==
dependencies:
readable-stream "^3.0.0"
sprintf-js@~1.0.2: sprintf-js@~1.0.2:
version "1.0.3" version "1.0.3"
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"