Groundwork for language support

- Implement the localization service.
- Use the proper build process which generates the require JSON files.
- Implement getting the locale and language configuration.
This commit is contained in:
Asher 2019-08-02 19:26:41 -05:00
parent 60ed0653bc
commit 712274d912
No known key found for this signature in database
GPG Key ID: D63C1EF81242354A
14 changed files with 472 additions and 244 deletions

View File

@ -16,6 +16,8 @@ matrix:
- os: osx - os: osx
env: env:
- VSCODE_VERSION="1.36.1" MAJOR_VERSION="2" VERSION="$MAJOR_VERSION.$TRAVIS_BUILD_NUMBER" - VSCODE_VERSION="1.36.1" MAJOR_VERSION="2" VERSION="$MAJOR_VERSION.$TRAVIS_BUILD_NUMBER"
before_install:
- if [[ "$TRAVIS_BRANCH" == "master" ]]; then export MINIFY="true"; fi
script: script:
- scripts/ci.bash - scripts/ci.bash
before_deploy: before_deploy:

View File

@ -13,14 +13,10 @@ RUN npm install -g yarn@1.13
WORKDIR /src WORKDIR /src
COPY . . COPY . .
# In the future, we can use https://github.com/yarnpkg/rfcs/pull/53 to make
# yarn use the node_modules directly which should be fast as it is slow because
# it populates its own cache every time.
RUN yarn \ RUN yarn \
&& yarn build "${codeServerVersion}" "${vscodeVersion}" linux x64 \ && yarn build "${vscodeVersion}" "${codeServerVersion}" \
&& yarn binary "${codeServerVersion}" "${vscodeVersion}" linux x64 \ && yarn binary "${vscodeVersion}" "${codeServerVersion}" \
&& mv "/src/build/code-server${codeServerVersion}-vsc${vscodeVersion}-linux-x64" /src/build/code-server && mv "/src/build/code-server${codeServerVersion}-vsc${vscodeVersion}-linux-x86_64-built/code-server${codeServerVersion}-vsc${vscodeVersion}-linux-x86_64" /src/build/code-server
# We deploy with ubuntu so that devs have a familiar environment. # We deploy with ubuntu so that devs have a familiar environment.
FROM ubuntu:18.04 FROM ubuntu:18.04

View File

@ -44,8 +44,8 @@ arguments when launching code-server with Docker. See
it will build in this directory which will cause issues because `yarn watch` it will build in this directory which will cause issues because `yarn watch`
will try to compile the build directory as well. will try to compile the build directory as well.
- For now `@coder/nbin` is a global dependency. - For now `@coder/nbin` is a global dependency.
- Run `yarn build ${codeServerVersion} ${vscodeVersion} ${target} ${arch}` in - Run `yarn build ${vscodeVersion} ${codeServerVersion}` in this directory (for
this directory (for example: `yarn build development 1.36.0 linux x64`). example: `yarn build 1.36.0 development`).
- If you target the same VS Code version our Travis builds do everything will - If you target the same VS Code version our Travis builds do everything will
work but if you target some other version it might not (we have to do some work but if you target some other version it might not (we have to do some
patching to VS Code so different versions aren't always compatible). patching to VS Code so different versions aren't always compatible).
@ -93,6 +93,10 @@ yarn start
# Visit http://localhost:8443 # Visit http://localhost:8443
``` ```
If you run into issues about a different version of Node being used, try running
`npm rebuild` in the VS Code directory and ignore the error at the end from
`vscode-ripgrep`.
### Upgrading VS Code ### Upgrading VS Code
We have to patch VS Code to provide and fix some functionality. As the web We have to patch VS Code to provide and fix some functionality. As the web
portion of VS Code matures, we'll be able to shrink and maybe even entirely portion of VS Code matures, we'll be able to shrink and maybe even entirely
@ -121,6 +125,7 @@ Our changes include:
- Get telemetry working by adding a channel for it. - Get telemetry working by adding a channel for it.
- Change a regular expression used for mnemonics so it works on Firefox. - Change a regular expression used for mnemonics so it works on Firefox.
- Make it possible for us to load code on the client. - Make it possible for us to load code on the client.
- Modify the build process to include our code.
## License ## License
[MIT](LICENSE) [MIT](LICENSE)

View File

@ -8,7 +8,7 @@
"watch": "yarn ensure-in-vscode && cd ../../../ && yarn watch", "watch": "yarn ensure-in-vscode && cd ../../../ && yarn watch",
"build": "bash ./scripts/tasks.bash build", "build": "bash ./scripts/tasks.bash build",
"package": "bash ./scripts/tasks.bash package", "package": "bash ./scripts/tasks.bash package",
"vstar": "bash ./scripts/tasks.bash vstar", "package-prebuilt": "bash ./scripts/tasks.bash package-prebuilt",
"binary": "bash ./scripts/tasks.bash binary", "binary": "bash ./scripts/tasks.bash binary",
"patch:generate": "yarn ensure-in-vscode && cd ../../../ && git diff --staged > ./src/vs/server/scripts/vscode.patch", "patch:generate": "yarn ensure-in-vscode && cd ../../../ && git diff --staged > ./src/vs/server/scripts/vscode.patch",
"patch:apply": "yarn ensure-in-vscode && cd ../../../ && git apply ./src/vs/server/scripts/vscode.patch" "patch:apply": "yarn ensure-in-vscode && cd ../../../ && git apply ./src/vs/server/scripts/vscode.patch"

View File

@ -23,7 +23,7 @@ function docker-build() {
function docker-exec() { function docker-exec() {
local command="${1}" ; shift local command="${1}" ; shift
local args="'${codeServerVersion}' '${vscodeVersion}' '${target}' '${arch}'" local args="'${vscodeVersion}' '${codeServerVersion}'"
docker exec "${containerId}" \ docker exec "${containerId}" \
bash -c "cd /src && CI=true yarn ${command} ${args}" bash -c "cd /src && CI=true yarn ${command} ${args}"
} }
@ -41,8 +41,7 @@ function docker-build() {
function local-build() { function local-build() {
function local-exec() { function local-exec() {
local command="${1}" ; shift local command="${1}" ; shift
CI=true yarn "${command}" \ CI=true yarn "${command}" "${vscodeVersion}" "${codeServerVersion}"
"${codeServerVersion}" "${vscodeVersion}" "${target}" "${arch}"
} }
local-exec build local-exec build
@ -56,7 +55,6 @@ function main() {
local vscodeVersion="${VSCODE_VERSION:-}" local vscodeVersion="${VSCODE_VERSION:-}"
local ostype="${OSTYPE:-}" local ostype="${OSTYPE:-}"
local target="${TARGET:-}" local target="${TARGET:-}"
local arch=x64
if [[ -z "${codeServerVersion}" ]] ; then if [[ -z "${codeServerVersion}" ]] ; then
>&2 echo "Must set VERSION environment variable"; exit 1 >&2 echo "Must set VERSION environment variable"; exit 1

View File

@ -1,11 +1,10 @@
/* global require, __dirname, process */
const { Binary } = require("@coder/nbin"); const { Binary } = require("@coder/nbin");
const fs = require("fs"); const fs = require("fs");
const path = require("path"); const path = require("path");
const target = process.argv[2]; const source = process.argv[2];
const arch = process.argv[3]; const target = process.argv[3];
const source = process.argv[4]; const binaryName = process.argv[4];
const bin = new Binary({ const bin = new Binary({
mainFile: path.join(source, "out/vs/server/main.js"), mainFile: path.join(source, "out/vs/server/main.js"),
@ -15,7 +14,7 @@ const bin = new Binary({
bin.writeFiles(path.join(source, "**")); bin.writeFiles(path.join(source, "**"));
bin.build().then((binaryData) => { bin.build().then((binaryData) => {
const outputPath = path.join(source, "code-server"); const outputPath = path.join(source, binaryName);
fs.writeFileSync(outputPath, binaryData); fs.writeFileSync(outputPath, binaryData);
fs.chmodSync(outputPath, "755"); fs.chmodSync(outputPath, "755");
}).catch((ex) => { }).catch((ex) => {

View File

@ -1,5 +1,5 @@
#!/bin/bash #!/bin/bash
set -euo pipefail set -euox pipefail
function log() { function log() {
local message="${1}" ; shift local message="${1}" ; shift
@ -11,27 +11,12 @@ function log() {
fi fi
} }
function exit-if-ci() {
if [[ -n "${ci}" ]] ; then
log "Pre-built VS Code ${vscodeVersion}-${target}-${arch} is incorrectly built" "error"
exit 1
fi
}
# Copy code-server into VS Code along with its dependencies. # Copy code-server into VS Code along with its dependencies.
function copy-server() { function copy-server() {
log "Applying patch" local serverPath="${sourcePath}/src/vs/server"
cd "${vscodeSourcePath}"
git reset --hard
git clean -fd
git apply "${rootPath}/scripts/vscode.patch"
local serverPath="${vscodeSourcePath}/src/vs/server"
rm -rf "${serverPath}" rm -rf "${serverPath}"
mkdir -p "${serverPath}" mkdir -p "${serverPath}"
log "Copying code-server code"
cp -r "${rootPath}/src" "${serverPath}" cp -r "${rootPath}/src" "${serverPath}"
cp -r "${rootPath}/typings" "${serverPath}" cp -r "${rootPath}/typings" "${serverPath}"
cp "${rootPath}/main.js" "${serverPath}" cp "${rootPath}/main.js" "${serverPath}"
@ -39,14 +24,11 @@ function copy-server() {
cp "${rootPath}/yarn.lock" "${serverPath}" cp "${rootPath}/yarn.lock" "${serverPath}"
if [[ -d "${rootPath}/node_modules" ]] ; then if [[ -d "${rootPath}/node_modules" ]] ; then
log "Copying code-server build dependencies"
cp -r "${rootPath}/node_modules" "${serverPath}" cp -r "${rootPath}/node_modules" "${serverPath}"
else else
log "Installing code-server build dependencies"
cd "${serverPath}"
# Ignore scripts to avoid also installing VS Code dependencies which has # Ignore scripts to avoid also installing VS Code dependencies which has
# already been done. # already been done.
yarn --ignore-scripts cd "${serverPath}" && yarn --ignore-scripts
rm -r node_modules/@types/node # I keep getting type conflicts rm -r node_modules/@types/node # I keep getting type conflicts
fi fi
@ -58,164 +40,113 @@ function copy-server() {
# Prepend the nbin shim which enables finding files within the binary. # Prepend the nbin shim which enables finding files within the binary.
function prepend-loader() { function prepend-loader() {
local filePath="${codeServerBuildPath}/${1}" ; shift local filePath="${buildPath}/${1}" ; shift
cat "${rootPath}/scripts/nbin-shim.js" "${filePath}" > "${filePath}.temp" cat "${rootPath}/scripts/nbin-shim.js" "${filePath}" > "${filePath}.temp"
mv "${filePath}.temp" "${filePath}" mv "${filePath}.temp" "${filePath}"
# Using : as the delimiter so the escaping here is easier to read. # Using : as the delimiter so the escaping here is easier to read.
# ${parameter/pattern/string}, so the pattern is /: (if the pattern starts # ${parameter/pattern/string}, so the pattern is /: (if the pattern starts
# with / it matches all instances) and the string is \\: (results in \:). # with / it matches all instances) and the string is \\: (results in \:).
if [[ "${target}" == "darwin" ]] ; then if [[ "${target}" == "darwin" ]] ; then
sed -i "" -e "s:{{ROOT_PATH}}:${codeServerBuildPath//:/\\:}:g" "${filePath}" sed -i "" -e "s:{{ROOT_PATH}}:${buildPath//:/\\:}:g" "${filePath}"
else else
sed -i "s:{{ROOT_PATH}}:${codeServerBuildPath//:/\\:}:g" "${filePath}" sed -i "s:{{ROOT_PATH}}:${buildPath//:/\\:}:g" "${filePath}"
fi fi
} }
# Copy code-server into VS Code then build it. # Copy code-server into VS Code then build it.
function build-code-server() { function build-code-server() {
copy-server copy-server
local min=""
if [[ -n "${minify}" ]] ; then
min="-min"
yarn gulp minify-vscode --max-old-space-size=32384
else
yarn gulp optimize-vscode --max-old-space-size=32384
fi
# TODO: look into making it do the full minified build for just our code rm -rf "${buildPath}"
# (basically just want to skip extensions, target our server code, and get mkdir -p "${buildPath}"
# the same type of build you get with the vscode-linux-x64-min task).
# Something like: yarn gulp "vscode-server-${target}-${arch}-min"
log "Building code-server"
yarn gulp compile-client
rm -rf "${codeServerBuildPath}" # Rebuild to make sure native modules work on the target system.
mkdir -p "${codeServerBuildPath}" cp "${sourcePath}/remote/"{package.json,yarn.lock,.yarnrc} "${buildPath}"
cd "${buildPath}" && yarn --production --force --build-from-source
rm "${buildPath}/"{package.json,yarn.lock,.yarnrc}
local json="{\"codeServerVersion\": \"${codeServerVersion}\"}" local json="{\"codeServerVersion\": \"${codeServerVersion}\"}"
cp -r "${sourcePath}/.build/extensions" "${buildPath}"
node "${rootPath}/scripts/merge.js" "${sourcePath}/package.json" "${rootPath}/scripts/package.json" "${buildPath}/package.json" "${json}"
node "${rootPath}/scripts/merge.js" "${sourcePath}/product.json" "${rootPath}/scripts/product.json" "${buildPath}/product.json"
cp -r "${sourcePath}/out-vscode${min}" "${buildPath}/out"
cp -r "${vscodeBuildPath}/resources/app/extensions" "${codeServerBuildPath}" # Only keep production dependencies for the server.
node "${rootPath}/scripts/merge.js" "${vscodeBuildPath}/resources/app/package.json" "${rootPath}/scripts/package.json" "${codeServerBuildPath}/package.json" "${json}" cp "${rootPath}/"{package.json,yarn.lock} "${buildPath}/out/vs/server"
node "${rootPath}/scripts/merge.js" "${vscodeBuildPath}/resources/app/product.json" "${rootPath}/scripts/product.json" "${codeServerBuildPath}/product.json" cd "${buildPath}/out/vs/server" && yarn --production --ignore-scripts
cp -r "${vscodeSourcePath}/out" "${codeServerBuildPath}" rm "${buildPath}/out/vs/server/"{package.json,yarn.lock}
rm -rf "${codeServerBuildPath}/out/vs/server/typings"
# Rebuild to make sure the native modules work since at the moment all the
# pre-built packages are from one Linux system which compiles against the
# latest glibc. This means you must build on the target system.
log "Installing remote dependencies"
cd "${vscodeSourcePath}/remote"
yarn --production --force --build-from-source
mv "${vscodeSourcePath}/remote/node_modules" "${codeServerBuildPath}"
# Only keep the production dependencies.
cd "${codeServerBuildPath}/out/vs/server"
yarn --production --ignore-scripts
prepend-loader "out/vs/server/main.js" prepend-loader "out/vs/server/main.js"
prepend-loader "out/bootstrap-fork.js" prepend-loader "out/bootstrap-fork.js"
log "Final build: ${codeServerBuildPath}" log "Final build: ${buildPath}"
} }
# Build VS Code if it hasn't already been built. If we're in the CI and it's # Download and extract a tar from a URL with either curl or wget depending on
# not fully built, error and exit. # which is available.
function build-vscode() { function download-tar() {
if [[ ! -d "${vscodeSourcePath}" ]] ; then local url="${1}" ; shift
exit-if-ci if command -v wget &> /dev/null ; then
log "${vscodeSourceName} does not exist, cloning" wget "${url}" --quiet -O - | tar -C "${stagingPath}" -xz
else
curl "${url}" --silent --fail | tar -C "${stagingPath}" -xz
fi
}
# Download a pre-built package. If it doesn't exist and we are in the CI, exit.
# Otherwise the return will be whether it existed or not. The pre-built package
# is provided to reduce CI build time.
function download-pre-built() {
local archiveName="${1}" ; shift
local url="https://codesrv-ci.cdr.sh/${archiveName}"
if ! download-tar "${url}" ; then
if [[ -n "${ci}" ]] ; then
log "${url} does not exist" "error"
exit 1
fi
return 1
fi
return 0
}
# Fully build code-server.
function build-task() {
mkdir -p "${stagingPath}"
if [[ ! -d "${sourcePath}" ]] ; then
if ! download-pre-built "vscode-${vscodeVersion}.tar.gz" ; then
git clone https://github.com/microsoft/vscode --quiet \ git clone https://github.com/microsoft/vscode --quiet \
--branch "${vscodeVersion}" --single-branch --depth=1 \ --branch "${vscodeVersion}" --single-branch --depth=1 \
"${vscodeSourcePath}" "${sourcePath}"
else
log "${vscodeSourceName} already exists, skipping clone"
fi fi
cd "${vscodeSourcePath}"
if [[ ! -d "${vscodeSourcePath}/node_modules" ]] ; then
exit-if-ci
log "Installing VS Code dependencies"
yarn
# Keep just what we need to keep the pre-built archive smaller.
rm -rf "${vscodeSourcePath}/test"
rm -rf "${vscodeSourcePath}/remote/node_modules" # Will rebuild.
else
log "${vscodeSourceName}/node_modules already exists, skipping install"
fi fi
cd "${sourcePath}"
if [[ ! -d "${vscodeBuildPath}" ]] ; then git reset --hard && git clean -fd
exit-if-ci git apply "${rootPath}/scripts/vscode.patch"
log "${vscodeBuildName} does not exist, building" if [[ ! -d "${sourcePath}/node_modules" ]] ; then
local builtPath="${buildPath}/VSCode-${target}-${arch}" if [[ -n "${ci}" ]] ; then
rm -rf "${builtPath}" log "Pre-built VS Code ${vscodeVersion} has no node_modules" "error"
yarn gulp "vscode-${target}-${arch}-min" --max-old-space-size=32384
mkdir -p "${vscodeBuildPath}/resources/app"
# Copy just what we need to keep the pre-built archive smaller.
mv "${builtPath}/resources/app/extensions" "${vscodeBuildPath}/resources/app"
mv "${builtPath}/resources/app/"*.json "${vscodeBuildPath}/resources/app"
rm -rf "${builtPath}"
else
log "${vscodeBuildName} already exists, skipping build"
fi
}
# Download VS Code with either curl or wget depending on which is available.
function download-vscode() {
cd "${buildPath}"
if command -v wget &> /dev/null ; then
log "Attempting to download ${tarName} with wget"
wget "${vsSourceUrl}" --quiet --output-document "${tarName}"
else
log "Attempting to download ${tarName} with curl"
curl "${vsSourceUrl}" --silent --fail --output "${tarName}"
fi
}
# Download pre-built VS Code if necessary. Build if there is no available
# download but not when in the CI. The pre-built package basically just
# provides us the dependencies and extensions so we don't have to install and
# build them respectively which takes a long time.
function prepare-vscode() {
if [[ ! -d "${vscodeBuildPath}" || ! -d "${vscodeSourcePath}" ]] ; then
mkdir -p "${buildPath}"
# TODO: for now everything uses the Linux build and we rebuild the modules.
# This means you must build on the target system.
local tarName="vstar-${vscodeVersion}-${target}-${arch}.tar.gz"
local linuxTarName="vstar-${vscodeVersion}-linux-${arch}.tar.gz"
local linuxVscodeBuildName="vscode-${vscodeVersion}-linux-${arch}-built"
local vsSourceUrl="https://codesrv-ci.cdr.sh/${linuxTarName}"
if download-vscode ; then
cd "${buildPath}"
rm -rf "${vscodeBuildPath}"
tar -xzf "${tarName}"
rm "${tarName}"
if [[ "${target}" != "linux" ]] ; then
mv "${linuxVscodeBuildName}" "${vscodeBuildName}"
fi
elif [[ -n "${ci}" ]] ; then
log "Pre-built VS Code ${vscodeVersion}-${target}-${arch} does not exist" "error"
exit 1 exit 1
else
log "${tarName} does not exist, building"
build-vscode
return
fi fi
else yarn
log "VS Code is already downloaded or built" fi
if [[ ! -d "${sourcePath}/.build/extensions" ]] ; then
if [[ -n "${ci}" ]] ; then
log "Pre-built VS Code ${vscodeVersion} has no built extensions" "error"
exit 1
fi
yarn gulp extensions-build-package --max-old-space-size=32384
fi fi
log "Ensuring VS Code is fully built"
build-vscode
}
function build-task() {
prepare-vscode
build-code-server build-code-server
} }
function vstar-task() { # Package the binary into a tar or zip for release.
local archivePath="${releasePath}/vstar-${vscodeVersion}-${target}-${arch}.tar.gz"
rm -f "${archivePath}"
mkdir -p "${releasePath}"
tar -C "${buildPath}" -czf "${archivePath}" "${vscodeSourceName}" "${vscodeBuildName}"
log "Archive: ${archivePath}"
}
function package-task() { function package-task() {
local archivePath="${releasePath}/${binaryName}" local archivePath="${releasePath}/${binaryName}"
rm -rf "${archivePath}" rm -rf "${archivePath}"
@ -223,8 +154,8 @@ function package-task() {
cp "${buildPath}/${binaryName}" "${archivePath}/code-server" cp "${buildPath}/${binaryName}" "${archivePath}/code-server"
cp "${rootPath}/README.md" "${archivePath}" cp "${rootPath}/README.md" "${archivePath}"
cp "${vscodeSourcePath}/LICENSE.txt" "${archivePath}" cp "${sourcePath}/LICENSE.txt" "${archivePath}"
cp "${vscodeSourcePath}/ThirdPartyNotices.txt" "${archivePath}" cp "${sourcePath}/ThirdPartyNotices.txt" "${archivePath}"
cd "${releasePath}" cd "${releasePath}"
if [[ "${target}" == "darwin" ]] ; then if [[ "${target}" == "darwin" ]] ; then
@ -236,50 +167,37 @@ function package-task() {
fi fi
} }
# Package built code into a binary. # Bundle built code into a binary.
function binary-task() { function binary-task() {
# I had trouble getting VS Code to build with the @coder/nbin dependency due # I had trouble getting VS Code to build with the @coder/nbin dependency due
# to the types it installs (tons of conflicts), so for now it's a global # to the types it installs (tons of conflicts), so for now it's a global
# dependency. # dependency.
cd "${rootPath}" cd "${rootPath}"
npm link @coder/nbin npm link @coder/nbin
node "${rootPath}/scripts/nbin.js" "${target}" "${arch}" "${codeServerBuildPath}" node "${rootPath}/scripts/nbin.js" "${buildPath}" "${target}" "${binaryName}"
rm node_modules/@coder/nbin rm node_modules/@coder/nbin
mv "${codeServerBuildPath}/code-server" "${buildPath}/${binaryName}"
log "Binary: ${buildPath}/${binaryName}" log "Binary: ${buildPath}/${binaryName}"
} }
# Check if it looks like we are inside VS Code. # Check if it looks like we are inside VS Code.
function in-vscode () { function in-vscode () {
log "Checking if we are inside VS Code"
local dir="${1}" ; shift local dir="${1}" ; shift
local maybeVsCode
local maybeVscode
local dirName local dirName
maybeVscode="$(realpath "${dir}/../../..")" maybeVsCode="$(realpath "${dir}/../../..")"
dirName="$(basename "${maybeVscode}")" dirName="$(basename "${maybeVsCode}")"
if [[ "${dirName}" != "vscode" ]] ; then if [[ "${dirName}" != "vscode" ]] ; then
return 1 return 1
fi fi
if [[ ! -f "${maybeVscode}/package.json" ]] ; then if [[ ! -f "${maybeVsCode}/package.json" ]] ; then
return 1 return 1
fi fi
if ! grep '"name": "code-oss-dev"' "${maybeVscode}/package.json" --quiet ; then if ! grep '"name": "code-oss-dev"' "${maybeVsCode}/package.json" --quiet ; then
return 1 return 1
fi fi
return 0 return 0
} }
function ensure-in-vscode-task() {
if ! in-vscode "${rootPath}"; then
log "Not in vscode" "error"
exit 1
fi
exit 0
}
function main() { function main() {
local relativeRootPath local relativeRootPath
local rootPath local rootPath
@ -288,52 +206,55 @@ function main() {
local task="${1}" ; shift local task="${1}" ; shift
if [[ "${task}" == "ensure-in-vscode" ]] ; then if [[ "${task}" == "ensure-in-vscode" ]] ; then
ensure-in-vscode-task if ! in-vscode "${rootPath}"; then
log "Not in VS Code" "error"
exit 1
fi
exit 0
fi fi
local codeServerVersion="${1}" ; shift
local vscodeVersion="${1}" ; shift
local target="${1}" ; shift
local arch="${1}" ; shift
local ci="${CI:-}"
# This lets you build in a separate directory since building within this # This lets you build in a separate directory since building within this
# directory while developing makes it hard to keep developing since compiling # directory while developing makes it hard to keep developing since compiling
# will compile everything in the build directory as well. # will compile everything in the build directory as well.
local outPath="${OUT:-${rootPath}}" local outPath="${OUT:-${rootPath}}"
local releasePath="${outPath}/release"
local stagingPath="${outPath}/build"
# If we're inside a vscode directory, assume we want to develop. In that case # If we're inside a VS Code directory, assume we want to develop. In that case
# we should set an OUT directory and not build in this directory. # we should set an OUT directory and not build in this directory.
if in-vscode "${outPath}" ; then if in-vscode "${outPath}" ; then
log "Set the OUT environment variable to something outside of VS Code" "error" log "Set the OUT environment variable to something outside of VS Code" "error"
exit 1 exit 1
fi fi
local releasePath="${outPath}/release" local vscodeVersion="${1}" ; shift
local buildPath="${outPath}/build" local sourceName="vscode-${vscodeVersion}-source"
local sourcePath="${stagingPath}/${sourceName}"
local vscodeSourceName="vscode-${vscodeVersion}-source" if [[ "${task}" == "package-prebuilt" ]] ; then
local vscodeBuildName="vscode-${vscodeVersion}-${target}-${arch}-built" local archiveName="vscode-${vscodeVersion}.tar.gz"
local vscodeSourcePath="${buildPath}/${vscodeSourceName}" cd "${stagingPath}"
local vscodeBuildPath="${buildPath}/${vscodeBuildName}" git reset --hard && git clean -xfd -e '.build/extensions' -e 'node_modules'
tar -czf "${archiveName}" "${sourceName}"
local codeServerBuildName="code-server${codeServerVersion}-vsc${vscodeVersion}-${target}-${arch}-built" mkdir -p "${releasePath}" && mv -f "${archiveName}" "${releasePath}"
local codeServerBuildPath="${buildPath}/${codeServerBuildName}" exit 0
local binaryName="code-server${codeServerVersion}-vsc${vscodeVersion}-${target}-${arch}"
log "Running ${task} task"
log " rootPath: ${rootPath}"
log " outPath: ${outPath}"
log " codeServerVersion: ${codeServerVersion}"
log " vscodeVersion: ${vscodeVersion}"
log " target: ${target}"
log " arch: ${arch}"
if [[ -n "${ci}" ]] ; then
log " CI: yes"
else
log " CI: no"
fi fi
local ci="${CI:-}"
local minify="${MINIFY:-}"
local arch="x86_64"
local target="linux"
local ostype="${OSTYPE:-}"
if [[ "${ostype}" == "darwin"* ]] ; then
target="darwin"
else
arch=$(uname -m)
fi
local codeServerVersion="${1}" ; shift
local binaryName="code-server${codeServerVersion}-vsc${vscodeVersion}-${target}-${arch}"
local buildPath="${stagingPath}/${binaryName}-built"
"${task}-task" "$@" "${task}-task" "$@"
} }

View File

@ -1,3 +1,111 @@
diff --git a/build/gulpfile.compile.js b/build/gulpfile.compile.js
index 0dd2e5abf1..fc6875f3c2 100644
--- a/build/gulpfile.compile.js
+++ b/build/gulpfile.compile.js
@@ -12,6 +12,7 @@ const { compileExtensionsBuildTask } = require('./gulpfile.extensions');
// Full compile, including nls and inline sources in sourcemaps, for build
const compileClientBuildTask = task.define('compile-client-build', task.series(util.rimraf('out-build'), compilation.compileTask('src', 'out-build', true)));
+exports.compileClientBuildTask = compileClientBuildTask;
// All Build
const compileBuildTask = task.define('compile-build', task.parallel(compileClientBuildTask, compileExtensionsBuildTask));
diff --git a/build/gulpfile.vscode.js b/build/gulpfile.vscode.js
index 84a6be26e8..7fb43686cd 100644
--- a/build/gulpfile.vscode.js
+++ b/build/gulpfile.vscode.js
@@ -34,7 +34,8 @@ const deps = require('./dependencies');
const getElectronVersion = require('./lib/electron').getElectronVersion;
const createAsar = require('./lib/asar').createAsar;
const minimist = require('minimist');
-const { compileBuildTask } = require('./gulpfile.compile');
+const { /*compileBuildTask, */compileClientBuildTask } = require('./gulpfile.compile');
+const { compileExtensionsBuildTask } = require('./gulpfile.extensions');
const productionDependencies = deps.getProductionDependencies(path.dirname(__dirname));
// @ts-ignore
@@ -47,23 +48,28 @@ const nodeModules = ['electron', 'original-fs']
// Build
const vscodeEntryPoints = _.flatten([
- buildfile.entrypoint('vs/workbench/workbench.main'),
+ buildfile.entrypoint('vs/workbench/workbench.web.api'),
+ buildfile.entrypoint('vs/server/src/cli'),
+ buildfile.entrypoint('vs/workbench/services/keybinding/browser/keyboardLayouts/layout.contribution.linux'),
+ buildfile.entrypoint('vs/workbench/services/keybinding/browser/keyboardLayouts/layout.contribution.win'),
+ buildfile.entrypoint('vs/workbench/services/keybinding/browser/keyboardLayouts/layout.contribution.darwin'),
buildfile.base,
- buildfile.workbench,
- buildfile.code
+ buildfile.workbenchWeb,
+ // buildfile.code
]);
const vscodeResources = [
- 'out-build/main.js',
- 'out-build/cli.js',
- 'out-build/driver.js',
+ 'out-build/vs/server/main.js',
+ 'out-build/vs/server/src/uriTransformer.js',
+ // 'out-build/cli.js',
+ // 'out-build/driver.js',
'out-build/bootstrap.js',
'out-build/bootstrap-fork.js',
'out-build/bootstrap-amd.js',
'out-build/bootstrap-window.js',
'out-build/paths.js',
'out-build/vs/**/*.{svg,png,cur,html}',
- '!out-build/vs/code/browser/**/*.html',
+ // '!out-build/vs/code/browser/**/*.html',
'out-build/vs/base/common/performance.js',
'out-build/vs/base/node/languagePacks.js',
'out-build/vs/base/node/{stdForkStart.js,terminateProcess.sh,cpuUsage.sh,ps.sh}',
@@ -78,10 +84,11 @@ const vscodeResources = [
'out-build/vs/workbench/contrib/welcome/walkThrough/**/*.md',
'out-build/vs/workbench/services/files/**/*.exe',
'out-build/vs/workbench/services/files/**/*.md',
- 'out-build/vs/code/electron-browser/workbench/**',
- 'out-build/vs/code/electron-browser/sharedProcess/sharedProcess.js',
- 'out-build/vs/code/electron-browser/issue/issueReporter.js',
- 'out-build/vs/code/electron-browser/processExplorer/processExplorer.js',
+ 'out-build/vs/code/browser/workbench/**',
+ // 'out-build/vs/code/electron-browser/sharedProcess/sharedProcess.js',
+ // 'out-build/vs/code/electron-browser/issue/issueReporter.js',
+ // 'out-build/vs/code/electron-browser/processExplorer/processExplorer.js',
+ '!out-build/vs/server/doc/**',
'!**/test/**'
];
@@ -94,7 +101,7 @@ const BUNDLED_FILE_HEADER = [
const optimizeVSCodeTask = task.define('optimize-vscode', task.series(
task.parallel(
util.rimraf('out-vscode'),
- compileBuildTask
+ compileClientBuildTask // compileBuildTask
),
common.optimizeTask({
src: 'out-build',
@@ -127,6 +134,20 @@ const minifyVSCodeTask = task.define('minify-vscode', task.series(
common.minifyTask('out-vscode', `${sourceMappingURLBase}/core`)
));
+function packageExtensionsTask() {
+ return () => {
+ const destination = path.join(root, ".build");
+ const sources = ext.packageExtensionsStream();
+ return sources.pipe(vfs.dest(destination));
+ };
+}
+gulp.task(task.define('extensions-build-package', task.series(
+ compileExtensionsBuildTask,
+ packageExtensionsTask()
+)));
+gulp.task(optimizeVSCodeTask);
+gulp.task(minifyVSCodeTask);
+
// Package
// @ts-ignore JSON checking: darwinCredits is optional
diff --git a/src/typings/require.d.ts b/src/typings/require.d.ts diff --git a/src/typings/require.d.ts b/src/typings/require.d.ts
index 618861a5be..9d4fdea14e 100644 index 618861a5be..9d4fdea14e 100644
--- a/src/typings/require.d.ts --- a/src/typings/require.d.ts
@ -74,8 +182,33 @@ index a7466e641a..6d91e66ad3 100644
+ +
+ export const codeServer: string = 'code-server'; + export const codeServer: string = 'code-server';
} }
diff --git a/src/vs/base/common/platform.ts b/src/vs/base/common/platform.ts
index 4cba839fe5..b216c43bbc 100644
--- a/src/vs/base/common/platform.ts
+++ b/src/vs/base/common/platform.ts
@@ -53,8 +53,18 @@ if (typeof navigator === 'object' && !isElectronRenderer) {
_isMacintosh = userAgent.indexOf('Macintosh') >= 0;
_isLinux = userAgent.indexOf('Linux') >= 0;
_isWeb = true;
- _locale = navigator.language;
- _language = _locale;
+ _locale = LANGUAGE_DEFAULT;
+ _language = LANGUAGE_DEFAULT;
+ const rawNlsConfig = typeof document !== 'undefined'
+ && document.getElementById('vscode-remote-nls-configuration')!.getAttribute('data-settings')!;
+ if (rawNlsConfig) {
+ try {
+ const nlsConfig: NLSConfig = JSON.parse(rawNlsConfig);
+ _locale = nlsConfig.locale;
+ _translationsConfigFile = nlsConfig._translationsConfigFile;
+ _language = nlsConfig.availableLanguages['*'] || LANGUAGE_DEFAULT;
+ } catch (error) { /* Oh well. */ }
+ }
} else if (typeof process === 'object') {
_isWindows = (process.platform === 'win32');
_isMacintosh = (process.platform === 'darwin');
diff --git a/src/vs/code/browser/workbench/workbench.html b/src/vs/code/browser/workbench/workbench.html diff --git a/src/vs/code/browser/workbench/workbench.html b/src/vs/code/browser/workbench/workbench.html
index ff62e0a65a..21cd50eaf9 100644 index ff62e0a65a..924b65fa7a 100644
--- a/src/vs/code/browser/workbench/workbench.html --- a/src/vs/code/browser/workbench/workbench.html
+++ b/src/vs/code/browser/workbench/workbench.html +++ b/src/vs/code/browser/workbench/workbench.html
@@ -4,6 +4,8 @@ @@ -4,6 +4,8 @@
@ -87,6 +220,14 @@ index ff62e0a65a..21cd50eaf9 100644
<!-- Disable pinch zooming --> <!-- Disable pinch zooming -->
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" /> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
@@ -20,6 +22,7 @@
<!-- Workaround to pass remote connection token-->
<meta id="vscode-remote-connection-token" data-settings="{{CONNECTION_AUTH_TOKEN}}">
+ <meta id="vscode-remote-nls-configuration" data-settings="{{NLS_CONFIGURATION}}">
</head>
<body class="vs-dark" aria-label="">
diff --git a/src/vs/code/browser/workbench/workbench.js b/src/vs/code/browser/workbench/workbench.js diff --git a/src/vs/code/browser/workbench/workbench.js b/src/vs/code/browser/workbench/workbench.js
index 34f321f90d..b1bd6a4ac9 100644 index 34f321f90d..b1bd6a4ac9 100644
--- a/src/vs/code/browser/workbench/workbench.js --- a/src/vs/code/browser/workbench/workbench.js
@ -372,6 +513,35 @@ index e09049c5b9..7af2c20efd 100644
.then(extensions => { .then(extensions => {
const toRemove: ILocalExtension[] = []; const toRemove: ILocalExtension[] = [];
diff --git a/src/vs/platform/localizations/electron-browser/localizationsService.ts b/src/vs/platform/localizations/electron-browser/localizationsService.ts
index 353161166e..7d64fe93c7 100644
--- a/src/vs/platform/localizations/electron-browser/localizationsService.ts
+++ b/src/vs/platform/localizations/electron-browser/localizationsService.ts
@@ -6,8 +6,9 @@
import { IChannel } from 'vs/base/parts/ipc/common/ipc';
import { Event } from 'vs/base/common/event';
import { ILocalizationsService, LanguageType } from 'vs/platform/localizations/common/localizations';
-import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService';
+// import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService';
import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
+import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
export class LocalizationsService implements ILocalizationsService {
@@ -15,8 +16,11 @@ export class LocalizationsService implements ILocalizationsService {
private channel: IChannel;
- constructor(@ISharedProcessService sharedProcessService: ISharedProcessService) {
- this.channel = sharedProcessService.getChannel('localizations');
+ constructor(
+ // @ISharedProcessService sharedProcessService: ISharedProcessService
+ @IRemoteAgentService remoteAgentService: IRemoteAgentService,
+ ) {
+ this.channel = remoteAgentService.getConnection()!.getChannel('localizations');
}
get onDidLanguagesChange(): Event<void> { return this.channel.listen('onDidLanguagesChange'); }
diff --git a/src/vs/platform/log/common/logIpc.ts b/src/vs/platform/log/common/logIpc.ts diff --git a/src/vs/platform/log/common/logIpc.ts b/src/vs/platform/log/common/logIpc.ts
index 9f68b645b6..f0cae7111d 100644 index 9f68b645b6..f0cae7111d 100644
--- a/src/vs/platform/log/common/logIpc.ts --- a/src/vs/platform/log/common/logIpc.ts
@ -573,7 +743,7 @@ index 5a758eb786..7fcacb5ca7 100644
templateData.actionBar.context = (<TreeViewItemHandleArg>{ $treeViewId: this.treeViewId, $treeItemHandle: node.handle }); templateData.actionBar.context = (<TreeViewItemHandleArg>{ $treeViewId: this.treeViewId, $treeItemHandle: node.handle });
templateData.actionBar.push(this.menus.getResourceActions(node), { icon: true, label: false }); templateData.actionBar.push(this.menus.getResourceActions(node), { icon: true, label: false });
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 1986fb6642..453d3e3e48 100644 index 1986fb6642..70b0c789e3 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
@@ -35,6 +35,7 @@ import { SignService } from 'vs/platform/sign/browser/signService'; @@ -35,6 +35,7 @@ import { SignService } from 'vs/platform/sign/browser/signService';
@ -584,16 +754,15 @@ index 1986fb6642..453d3e3e48 100644
class CodeRendererMain extends Disposable { class CodeRendererMain extends Disposable {
@@ -71,6 +72,8 @@ class CodeRendererMain extends Disposable { @@ -49,6 +50,7 @@ class CodeRendererMain extends Disposable {
// Startup async open(): Promise<void> {
this.workbench.startup(); const services = await this.initServices();
+ + await initialize(services.serviceCollection);
+ initialize(services.serviceCollection);
}
private async initServices(): Promise<{ serviceCollection: ServiceCollection, logService: ILogService }> { await domContentLoaded();
@@ -114,7 +117,8 @@ class CodeRendererMain extends Disposable { mark('willStartWorkbench');
@@ -114,7 +116,8 @@ class CodeRendererMain extends Disposable {
const channel = connection.getChannel<IChannel>(REMOTE_FILE_SYSTEM_CHANNEL_NAME); const channel = connection.getChannel<IChannel>(REMOTE_FILE_SYSTEM_CHANNEL_NAME);
const remoteFileSystemProvider = this._register(new RemoteExtensionsFileSystemProvider(channel, remoteAgentService.getEnvironment())); const remoteFileSystemProvider = this._register(new RemoteExtensionsFileSystemProvider(channel, remoteAgentService.getEnvironment()));
@ -604,7 +773,7 @@ index 1986fb6642..453d3e3e48 100644
const payload = await this.resolveWorkspaceInitializationPayload(); const payload = await this.resolveWorkspaceInitializationPayload();
diff --git a/src/vs/workbench/browser/web.simpleservices.ts b/src/vs/workbench/browser/web.simpleservices.ts diff --git a/src/vs/workbench/browser/web.simpleservices.ts b/src/vs/workbench/browser/web.simpleservices.ts
index b253e573ae..7a230fa3bd 100644 index b253e573ae..94b2b7f287 100644
--- a/src/vs/workbench/browser/web.simpleservices.ts --- a/src/vs/workbench/browser/web.simpleservices.ts
+++ b/src/vs/workbench/browser/web.simpleservices.ts +++ b/src/vs/workbench/browser/web.simpleservices.ts
@@ -53,6 +53,14 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur @@ -53,6 +53,14 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur
@ -731,6 +900,14 @@ index b253e573ae..7a230fa3bd 100644
if (openFolderInNewWindow) { if (openFolderInNewWindow) {
window.open(newAddress); window.open(newAddress);
} else { } else {
@@ -1100,6 +1136,7 @@ export class SimpleWindowsService implements IWindowsService {
}
relaunch(_options: { addArgs?: string[], removeArgs?: string[] }): Promise<void> {
+ window.location.reload();
return Promise.resolve();
}
diff --git a/src/vs/workbench/contrib/comments/browser/commentNode.ts b/src/vs/workbench/contrib/comments/browser/commentNode.ts diff --git a/src/vs/workbench/contrib/comments/browser/commentNode.ts b/src/vs/workbench/contrib/comments/browser/commentNode.ts
index f4ac3fe8dd..3a3616b39e 100644 index f4ac3fe8dd..3a3616b39e 100644
--- a/src/vs/workbench/contrib/comments/browser/commentNode.ts --- a/src/vs/workbench/contrib/comments/browser/commentNode.ts
@ -1415,9 +1592,20 @@ index 306d58f915..58c603ad3d 100644
if (definition.fontCharacter || definition.fontColor) { if (definition.fontCharacter || definition.fontColor) {
let body = ''; let body = '';
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 c28adc0ad9..4517c308da 100644 index c28adc0ad9..f76612a4d7 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
@@ -72,8 +72,8 @@ import { BrowserLifecycleService } from 'vs/platform/lifecycle/browser/lifecycle
import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
import { DialogService } from 'vs/platform/dialogs/browser/dialogService';
-// import { ILocalizationsService } from 'vs/platform/localizations/common/localizations';
-// import { LocalizationsService } from 'vs/platform/localizations/electron-browser/localizationsService';
+import { ILocalizationsService } from 'vs/platform/localizations/common/localizations';
+import { LocalizationsService } from 'vs/platform/localizations/electron-browser/localizationsService';
// import { ISharedProcessService, SharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService';
// import { IProductService } from 'vs/platform/product/common/product';
// import { ProductService } from 'vs/platform/product/node/productService';
@@ -128,7 +128,7 @@ import 'vs/workbench/services/extensions/browser/extensionService'; @@ -128,7 +128,7 @@ import 'vs/workbench/services/extensions/browser/extensionService';
// import 'vs/workbench/services/contextmenu/electron-browser/contextmenuService'; // import 'vs/workbench/services/contextmenu/electron-browser/contextmenuService';
// import 'vs/workbench/services/extensions/node/multiExtensionManagement'; // import 'vs/workbench/services/extensions/node/multiExtensionManagement';
@ -1427,6 +1615,24 @@ index c28adc0ad9..4517c308da 100644
// import 'vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl'; // import 'vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl';
import 'vs/workbench/services/notification/common/notificationService'; import 'vs/workbench/services/notification/common/notificationService';
// import 'vs/workbench/services/window/electron-browser/windowService'; // import 'vs/workbench/services/window/electron-browser/windowService';
@@ -156,7 +156,7 @@ registerSingleton(IContextViewService, ContextViewService, true);
// registerSingleton(IExtensionGalleryService, ExtensionGalleryService, true);
// registerSingleton(IRequestService, RequestService, true);
registerSingleton(ILifecycleService, BrowserLifecycleService);
-// registerSingleton(ILocalizationsService, LocalizationsService);
+registerSingleton(ILocalizationsService, LocalizationsService);
// registerSingleton(ISharedProcessService, SharedProcessService, true);
// registerSingleton(IWindowsService, WindowsService);
// registerSingleton(IUpdateService, UpdateService);
@@ -194,7 +194,7 @@ import 'vs/workbench/services/files/common/workspaceWatcher';
import 'vs/workbench/contrib/telemetry/browser/telemetry.contribution';
// Localizations
-// import 'vs/workbench/contrib/localizations/browser/localizations.contribution';
+import 'vs/workbench/contrib/localizations/browser/localizations.contribution';
// Preferences
import 'vs/workbench/contrib/preferences/browser/preferences.contribution';
@@ -260,9 +260,9 @@ registerSingleton(IWebviewService, WebviewService, true); @@ -260,9 +260,9 @@ registerSingleton(IWebviewService, WebviewService, true);
registerSingleton(IWebviewEditorService, WebviewEditorService, true); registerSingleton(IWebviewEditorService, WebviewEditorService, true);

View File

@ -19,6 +19,7 @@ import { ITelemetryService } from "vs/platform/telemetry/common/telemetry";
import { ExtensionScanner, ExtensionScannerInput } from "vs/workbench/services/extensions/node/extensionPoints"; import { ExtensionScanner, ExtensionScannerInput } from "vs/workbench/services/extensions/node/extensionPoints";
import { DiskFileSystemProvider } from "vs/workbench/services/files/node/diskFileSystemProvider"; import { DiskFileSystemProvider } from "vs/workbench/services/files/node/diskFileSystemProvider";
import { getTranslations } from "vs/server/src/nls";
import { getUriTransformer } from "vs/server/src/util"; import { getUriTransformer } from "vs/server/src/util";
/** /**
@ -214,7 +215,7 @@ export class ExtensionEnvironmentChannel implements IServerChannel {
} }
private async scanExtensions(locale: string): Promise<IExtensionDescription[]> { private async scanExtensions(locale: string): Promise<IExtensionDescription[]> {
const translations = {}; // TODO: translations const translations = await getTranslations(locale, this.environment.userDataPath);
const scanMultiple = (isBuiltin: boolean, isUnderDevelopment: boolean, paths: string[]): Promise<IExtensionDescription[][]> => { const scanMultiple = (isBuiltin: boolean, isUnderDevelopment: boolean, paths: string[]): Promise<IExtensionDescription[][]> => {
return Promise.all(paths.map((path) => { return Promise.all(paths.map((path) => {

View File

@ -10,6 +10,7 @@ import product from "vs/platform/product/node/product";
import { MainServer } from "vs/server/src/server"; import { MainServer } from "vs/server/src/server";
import { enableExtensionTars } from "vs/server/src/tar"; import { enableExtensionTars } from "vs/server/src/tar";
import { AuthType, buildAllowedMessage, generateCertificate, generatePassword, localRequire, open, unpackExecutables } from "vs/server/src/util"; import { AuthType, buildAllowedMessage, generateCertificate, generatePassword, localRequire, open, unpackExecutables } from "vs/server/src/util";
import { main as vsCli } from "vs/code/node/cliProcessMain";
const { logger } = localRequire<typeof import("@coder/logger/out/index")>("@coder/logger/out/index"); const { logger } = localRequire<typeof import("@coder/logger/out/index")>("@coder/logger/out/index");
@ -65,10 +66,6 @@ options.push({ id: "socket", type: "string", cat: "o", description: "Listen on a
options.push(last); options.push(last);
interface IMainCli {
main: (argv: ParsedArgs) => Promise<void>;
}
const main = async (): Promise<void | void[]> => { const main = async (): Promise<void | void[]> => {
const args = validatePaths(parseMainProcessArgv(process.argv)) as Args; const args = validatePaths(parseMainProcessArgv(process.argv)) as Args;
["extra-extensions-dir", "extra-builtin-extensions-dir"].forEach((key) => { ["extra-extensions-dir", "extra-builtin-extensions-dir"].forEach((key) => {
@ -108,8 +105,7 @@ const main = async (): Promise<void | void[]> => {
}; };
if (shouldSpawnCliProcess()) { if (shouldSpawnCliProcess()) {
const cli = await new Promise<IMainCli>((c, e) => require(["vs/code/node/cliProcessMain"], c, e)); await vsCli(args);
await cli.main(args);
return process.exit(0); // There is a WriteStream instance keeping it open. return process.exit(0); // There is a WriteStream instance keeping it open.
} }

View File

@ -1,12 +1,14 @@
import { coderApi, vscodeApi } from "vs/server/src/api";
import "vs/css!./media/firefox";
import { ServiceCollection } from "vs/platform/instantiation/common/serviceCollection"; import { ServiceCollection } from "vs/platform/instantiation/common/serviceCollection";
import { coderApi, vscodeApi } from "vs/server/src/api";
import "vs/css!./media/firefox";
/** /**
* This is called by vs/workbench/browser/web.main.ts after the workbench has * This is called by vs/workbench/browser/web.main.ts after the workbench has
* been initialized so we can initialize our own client-side code. * been initialized so we can initialize our own client-side code.
*/ */
export const initialize = (services: ServiceCollection): void => { export const initialize = async (services: ServiceCollection): Promise<void> => {
const target = window as any; const target = window as any;
target.ide = coderApi(services); target.ide = coderApi(services);
target.vscode = vscodeApi(services); target.vscode = vscodeApi(services);

View File

@ -5,9 +5,11 @@ import { VSBuffer } from "vs/base/common/buffer";
import { Emitter } from "vs/base/common/event"; import { Emitter } from "vs/base/common/event";
import { ISocket } from "vs/base/parts/ipc/common/ipc.net"; import { ISocket } from "vs/base/parts/ipc/common/ipc.net";
import { NodeSocket } from "vs/base/parts/ipc/node/ipc.net"; import { NodeSocket } from "vs/base/parts/ipc/node/ipc.net";
import { IEnvironmentService } from "vs/platform/environment/common/environment";
import { ILogService } from "vs/platform/log/common/log"; import { ILogService } from "vs/platform/log/common/log";
import { IExtHostReadyMessage } from "vs/workbench/services/extensions/common/extensionHostProtocol"; import { IExtHostReadyMessage } from "vs/workbench/services/extensions/common/extensionHostProtocol";
import { getNlsConfiguration } from "vs/server/src/nls";
import { Protocol } from "vs/server/src/protocol"; import { Protocol } from "vs/server/src/protocol";
import { uriTransformerPath } from "vs/server/src/util"; import { uriTransformerPath } from "vs/server/src/util";
@ -57,19 +59,25 @@ export class ManagementConnection extends Connection {
} }
export class ExtensionHostConnection extends Connection { export class ExtensionHostConnection extends Connection {
private process: cp.ChildProcess; private process?: cp.ChildProcess;
public constructor(protocol: Protocol, buffer: VSBuffer, private readonly log: ILogService) { public constructor(
locale:string, protocol: Protocol, buffer: VSBuffer,
private readonly log: ILogService,
private readonly environment: IEnvironmentService,
) {
super(protocol); super(protocol);
this.protocol.dispose(); this.protocol.dispose();
this.process = this.spawn(buffer); this.spawn(locale, buffer).then((p) => this.process = p);
this.protocol.getUnderlyingSocket().pause(); this.protocol.getUnderlyingSocket().pause();
} }
protected dispose(): void { protected dispose(): void {
if (!this.disposed) { if (!this.disposed) {
this.disposed = true; this.disposed = true;
if (this.process) {
this.process.kill(); this.process.kill();
}
this.protocol.getSocket().end(); this.protocol.getSocket().end();
this._onClose.fire(); this._onClose.fire();
} }
@ -85,14 +93,15 @@ export class ExtensionHostConnection extends Connection {
private sendInitMessage(buffer: VSBuffer): void { private sendInitMessage(buffer: VSBuffer): void {
const socket = this.protocol.getUnderlyingSocket(); const socket = this.protocol.getUnderlyingSocket();
socket.pause(); socket.pause();
this.process.send({ this.process!.send({ // Process must be set at this point.
type: "VSCODE_EXTHOST_IPC_SOCKET", type: "VSCODE_EXTHOST_IPC_SOCKET",
initialDataChunk: (buffer.buffer as Buffer).toString("base64"), initialDataChunk: (buffer.buffer as Buffer).toString("base64"),
skipWebSocketFrames: this.protocol.getSocket() instanceof NodeSocket, skipWebSocketFrames: this.protocol.getSocket() instanceof NodeSocket,
}, socket); }, socket);
} }
private spawn(buffer: VSBuffer): cp.ChildProcess { private async spawn(locale: string, buffer: VSBuffer): Promise<cp.ChildProcess> {
const config = await getNlsConfiguration(locale, this.environment.userDataPath);
const proc = cp.fork( const proc = cp.fork(
getPathFromAmdModule(require, "bootstrap-fork"), getPathFromAmdModule(require, "bootstrap-fork"),
[ "--type=extensionHost", `--uriTransformerPath=${uriTransformerPath}` ], [ "--type=extensionHost", `--uriTransformerPath=${uriTransformerPath}` ],
@ -105,6 +114,7 @@ export class ExtensionHostConnection extends Connection {
VSCODE_EXTHOST_WILL_SEND_SOCKET: "true", VSCODE_EXTHOST_WILL_SEND_SOCKET: "true",
VSCODE_HANDLES_UNCAUGHT_ERRORS: "true", VSCODE_HANDLES_UNCAUGHT_ERRORS: "true",
VSCODE_LOG_STACK: "false", VSCODE_LOG_STACK: "false",
VSCODE_NLS_CONFIG: JSON.stringify(config),
}, },
silent: true, silent: true,
}, },

81
src/nls.ts Normal file
View File

@ -0,0 +1,81 @@
import * as path from "path";
import * as fs from "fs";
import * as util from "util";
import { getPathFromAmdModule } from "vs/base/common/amd";
import * as lp from "vs/base/node/languagePacks";
import product from "vs/platform/product/node/product";
import { Translations } from "vs/workbench/services/extensions/common/extensionPoints";
const configurations = new Map<string, Promise<lp.NLSConfiguration>>();
const metadataPath = path.join(getPathFromAmdModule(require, ""), "nls.metadata.json");
export const isInternalConfiguration = (config: lp.NLSConfiguration): config is lp.InternalNLSConfiguration => {
return config && !!(<lp.InternalNLSConfiguration>config)._languagePackId;
};
const DefaultConfiguration = {
locale: "en",
availableLanguages: {},
};
export const getNlsConfiguration = async (locale: string, userDataPath: string): Promise<lp.NLSConfiguration> => {
const id = `${locale}: ${userDataPath}`;
if (!configurations.has(id)) {
configurations.set(id, new Promise(async (resolve) => {
const config = product.commit && await util.promisify(fs.exists)(metadataPath)
? await lp.getNLSConfiguration(product.commit, userDataPath, metadataPath, locale)
: DefaultConfiguration;
if (isInternalConfiguration(config)) {
config._languagePackSupport = true;
}
resolve(config);
}));
}
return configurations.get(id)!;
};
export const getTranslations = async (locale: string, userDataPath: string): Promise<Translations> => {
const config = await getNlsConfiguration(locale, userDataPath);
if (isInternalConfiguration(config)) {
try {
return JSON.parse(await util.promisify(fs.readFile)(config._translationsConfigFile, "utf8"));
} catch (error) { /* Nothing yet. */}
}
return {};
};
export const getLocaleFromConfig = async (userDataPath: string): Promise<string> => {
let locale = "en";
try {
const localeConfigUri = path.join(userDataPath, "User/locale.json");
const content = stripComments(await util.promisify(fs.readFile)(localeConfigUri, "utf8"));
locale = JSON.parse(content).locale;
} catch (error) { /* Ignore. */ }
return locale;
};
// Taken from src/main.js in the main VS Code source.
const stripComments = (content: string): string => {
const regexp = /("(?:[^\\"]*(?:\\.)?)*")|('(?:[^\\']*(?:\\.)?)*')|(\/\*(?:\r?\n|.)*?\*\/)|(\/{2,}.*?(?:(?:\r?\n)|$))/g;
return content.replace(regexp, (match, _m1, _m2, m3, m4) => {
// Only one of m1, m2, m3, m4 matches
if (m3) {
// A block comment. Replace with nothing
return '';
} else if (m4) {
// A line comment. If it ends in \r?\n then keep it.
const length_1 = m4.length;
if (length_1 > 2 && m4[length_1 - 1] === '\n') {
return m4[length_1 - 2] === '\r' ? '\r\n' : '\n';
}
else {
return '';
}
} else {
// We match a string
return match;
}
});
};

View File

@ -14,8 +14,9 @@ import { sanitizeFilePath } from "vs/base/common/extpath";
import { UriComponents, URI } from "vs/base/common/uri"; import { UriComponents, URI } from "vs/base/common/uri";
import { generateUuid } from "vs/base/common/uuid"; import { generateUuid } from "vs/base/common/uuid";
import { getMachineId } from 'vs/base/node/id'; import { getMachineId } from 'vs/base/node/id';
import { IPCServer, ClientConnectionEvent, StaticRouter } from "vs/base/parts/ipc/common/ipc"; import { NLSConfiguration } from "vs/base/node/languagePacks";
import { mkdirp, rimraf } from "vs/base/node/pfs"; import { mkdirp, rimraf } from "vs/base/node/pfs";
import { IPCServer, ClientConnectionEvent, StaticRouter } from "vs/base/parts/ipc/common/ipc";
import { LogsDataCleaner } from "vs/code/electron-browser/sharedProcess/contrib/logsDataCleaner"; import { LogsDataCleaner } from "vs/code/electron-browser/sharedProcess/contrib/logsDataCleaner";
import { IConfigurationService } from "vs/platform/configuration/common/configuration"; import { IConfigurationService } from "vs/platform/configuration/common/configuration";
import { ConfigurationService } from "vs/platform/configuration/node/configurationService"; import { ConfigurationService } from "vs/platform/configuration/node/configurationService";
@ -33,6 +34,7 @@ import { InstantiationService } from "vs/platform/instantiation/common/instantia
import { ServiceCollection } from "vs/platform/instantiation/common/serviceCollection"; import { ServiceCollection } from "vs/platform/instantiation/common/serviceCollection";
import { ILocalizationsService } from "vs/platform/localizations/common/localizations"; import { ILocalizationsService } from "vs/platform/localizations/common/localizations";
import { LocalizationsService } from "vs/platform/localizations/node/localizations"; import { LocalizationsService } from "vs/platform/localizations/node/localizations";
import { LocalizationsChannel } from "vs/platform/localizations/node/localizationsIpc";
import { getLogLevel, ILogService } from "vs/platform/log/common/log"; import { getLogLevel, ILogService } from "vs/platform/log/common/log";
import { LogLevelSetterChannel } from "vs/platform/log/common/logIpc"; import { LogLevelSetterChannel } from "vs/platform/log/common/logIpc";
import { SpdLogService } from "vs/platform/log/node/spdlogService"; import { SpdLogService } from "vs/platform/log/node/spdlogService";
@ -56,6 +58,7 @@ import { IWorkbenchConstructionOptions } from "vs/workbench/workbench.web.api";
import { Connection, ManagementConnection, ExtensionHostConnection } from "vs/server/src/connection"; import { Connection, ManagementConnection, ExtensionHostConnection } from "vs/server/src/connection";
import { ExtensionEnvironmentChannel, FileProviderChannel , } from "vs/server/src/channel"; import { ExtensionEnvironmentChannel, FileProviderChannel , } from "vs/server/src/channel";
import { TelemetryClient } from "vs/server/src/insights"; import { TelemetryClient } from "vs/server/src/insights";
import { getNlsConfiguration, getLocaleFromConfig } from "vs/server/src/nls";
import { Protocol } from "vs/server/src/protocol"; import { Protocol } from "vs/server/src/protocol";
import { AuthType, getMediaMime, getUriTransformer, localRequire, tmpdir } from "vs/server/src/util"; import { AuthType, getMediaMime, getUriTransformer, localRequire, tmpdir } from "vs/server/src/util";
@ -74,6 +77,7 @@ export interface Options {
REMOTE_USER_DATA_URI: UriComponents | URI; REMOTE_USER_DATA_URI: UriComponents | URI;
PRODUCT_CONFIGURATION: IProductConfiguration | null; PRODUCT_CONFIGURATION: IProductConfiguration | null;
CONNECTION_AUTH_TOKEN: string; CONNECTION_AUTH_TOKEN: string;
NLS_CONFIGURATION: NLSConfiguration;
} }
export interface Response { export interface Response {
@ -456,7 +460,8 @@ export class MainServer extends Server {
util.promisify(fs.readFile)(filePath, "utf8"), util.promisify(fs.readFile)(filePath, "utf8"),
this.servicesPromise, this.servicesPromise,
]); ]);
const environment = this.services.get(IEnvironmentService) as IEnvironmentService;
const locale = environment.args.locale || await getLocaleFromConfig(environment.userDataPath);
const webviewEndpoint = this.address(request) + "/webview/"; const webviewEndpoint = this.address(request) + "/webview/";
const cwd = process.env.VSCODE_CWD || process.cwd(); const cwd = process.env.VSCODE_CWD || process.cwd();
const workspacePath = parsedUrl.query.workspace as string | undefined; const workspacePath = parsedUrl.query.workspace as string | undefined;
@ -479,6 +484,7 @@ export class MainServer extends Server {
), ),
PRODUCT_CONFIGURATION: product, PRODUCT_CONFIGURATION: product,
CONNECTION_AUTH_TOKEN: "", CONNECTION_AUTH_TOKEN: "",
NLS_CONFIGURATION: await getNlsConfiguration(locale, environment.userDataPath),
}; };
Object.keys(options).forEach((key) => { Object.keys(options).forEach((key) => {
@ -528,7 +534,10 @@ export class MainServer extends Server {
} else { } else {
const buffer = protocol.readEntireBuffer(); const buffer = protocol.readEntireBuffer();
connection = new ExtensionHostConnection( connection = new ExtensionHostConnection(
protocol, buffer, this.services.get(ILogService) as ILogService, message.args ? message.args.language : "en",
protocol, buffer,
this.services.get(ILogService) as ILogService,
this.services.get(IEnvironmentService) as IEnvironmentService,
); );
} }
connections.set(token, connection); connections.set(token, connection);
@ -576,7 +585,9 @@ export class MainServer extends Server {
await new Promise((resolve) => { await new Promise((resolve) => {
const instantiationService = new InstantiationService(this.services); const instantiationService = new InstantiationService(this.services);
this.services.set(ILocalizationsService, instantiationService.createInstance(LocalizationsService)); const localizationService = instantiationService.createInstance(LocalizationsService);
this.services.set(ILocalizationsService, localizationService);
this.ipc.registerChannel("localizations", new LocalizationsChannel(localizationService));
instantiationService.invokeFunction(() => { instantiationService.invokeFunction(() => {
instantiationService.createInstance(LogsDataCleaner); instantiationService.createInstance(LogsDataCleaner);
this.ipc.registerChannel(REMOTE_FILE_SYSTEM_CHANNEL_NAME, new FileProviderChannel(environmentService, logService)); this.ipc.registerChannel(REMOTE_FILE_SYSTEM_CHANNEL_NAME, new FileProviderChannel(environmentService, logService));