chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
#!/bin/bash
|
||||
set -e # Exit on error
|
||||
set -x # Print commands as they are executed
|
||||
|
||||
# Configuration
|
||||
APP_NAME="void"
|
||||
APP_VERSION="1.0.0"
|
||||
ARCH="x86_64"
|
||||
|
||||
export ARCH
|
||||
|
||||
# Check if void binary exists in current directory
|
||||
if [ ! -f "./void" ]; then
|
||||
echo "Error: void binary not found in current directory"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if icon exists
|
||||
if [ ! -f "./void.png" ]; then
|
||||
echo "Error: void.png icon not found in current directory"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Create temporary directory
|
||||
TEMP_DIR="$(mktemp -d)"
|
||||
echo "Created temporary directory: $TEMP_DIR"
|
||||
APP_DIR="$TEMP_DIR/$APP_NAME.AppDir"
|
||||
|
||||
# Create basic AppDir structure
|
||||
mkdir -pv "$APP_DIR/usr/bin"
|
||||
mkdir -pv "$APP_DIR/usr/lib"
|
||||
mkdir -pv "$APP_DIR/usr/share/applications"
|
||||
mkdir -pv "$APP_DIR/usr/share/icons/hicolor/256x256/apps"
|
||||
|
||||
# Exclude create-appimage.sh and appimagetool-x86_64.AppImage from being copied
|
||||
echo "Copying files excluding create-appimage.sh and appimagetool-x86_64.AppImage..."
|
||||
|
||||
cp -v ./void "$APP_DIR/usr/bin/"
|
||||
|
||||
# Copy the icon to required locations
|
||||
cp -v ./void.png "$APP_DIR/void.png"
|
||||
cp -v ./void.png "$APP_DIR/usr/share/icons/hicolor/256x256/apps/void.png"
|
||||
|
||||
# Copy dependencies with error checking
|
||||
echo "Copying dependencies..."
|
||||
for lib in $(ldd ./void | grep "=> /" | awk '{print $3}'); do
|
||||
if [ -f "$lib" ]; then
|
||||
cp -v "$lib" "$APP_DIR/usr/lib/" || echo "Failed to copy $lib"
|
||||
else
|
||||
echo "Warning: Library $lib not found"
|
||||
fi
|
||||
done
|
||||
|
||||
# Create desktop file with error checking
|
||||
echo "Creating desktop file..."
|
||||
if ! cat > "$APP_DIR/$APP_NAME.desktop" <<EOF
|
||||
[Desktop Entry]
|
||||
Name=$APP_NAME
|
||||
Exec=void
|
||||
Icon=void
|
||||
Type=Application
|
||||
Categories=Utility;
|
||||
Comment=Void Linux Application
|
||||
EOF
|
||||
then
|
||||
echo "Error creating desktop file"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Make desktop file executable
|
||||
chmod +x "$APP_DIR/$APP_NAME.desktop"
|
||||
|
||||
# Copy the desktop file to the applications directory
|
||||
cp -v "$APP_DIR/$APP_NAME.desktop" "$APP_DIR/usr/share/applications/"
|
||||
|
||||
# Create AppRun with error checking
|
||||
echo "Creating AppRun..."
|
||||
if ! cat > "$APP_DIR/AppRun" <<EOF
|
||||
#!/bin/bash
|
||||
cd "\$(dirname "\$0")/usr/bin"
|
||||
export LD_LIBRARY_PATH="\$APPDIR/usr/lib:\$LD_LIBRARY_PATH"
|
||||
exec ./void "\$@"
|
||||
EOF
|
||||
then
|
||||
echo "Error creating AppRun"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Make AppRun executable
|
||||
chmod +x "$APP_DIR/AppRun"
|
||||
|
||||
# Download appimagetool if not present in the current directory
|
||||
if [ ! -f "./appimagetool-x86_64.AppImage" ]; then
|
||||
echo "Downloading appimagetool-x86_64.AppImage..."
|
||||
wget "https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage"
|
||||
chmod +x appimagetool-x86_64.AppImage
|
||||
else
|
||||
echo "appimagetool-x86_64.AppImage is already present."
|
||||
fi
|
||||
|
||||
# Create the AppImage
|
||||
echo "Creating AppImage..."
|
||||
ARCH=x86_64 ./appimagetool-x86_64.AppImage "$APP_DIR" "${APP_NAME}-${APP_VERSION}-${ARCH}.AppImage"
|
||||
|
||||
# Cleanup
|
||||
echo "Cleaning up..."
|
||||
rm -rf "$TEMP_DIR"
|
||||
|
||||
echo "AppImage creation complete!"
|
||||
Executable
+168
@@ -0,0 +1,168 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Exit on error
|
||||
set -e
|
||||
|
||||
# Check platform
|
||||
platform=$(uname)
|
||||
|
||||
if [[ "$platform" == "Darwin" ]]; then
|
||||
echo "Running on macOS. Note that the AppImage created will only work on Linux systems."
|
||||
if ! command -v docker &> /dev/null; then
|
||||
echo "Docker Desktop for Mac is not installed. Please install it from https://www.docker.com/products/docker-desktop"
|
||||
exit 1
|
||||
fi
|
||||
elif [[ "$platform" == "Linux" ]]; then
|
||||
echo "Running on Linux. Proceeding with AppImage creation..."
|
||||
else
|
||||
echo "This script is intended to run on macOS or Linux. Current platform: $platform"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Enable BuildKit
|
||||
export DOCKER_BUILDKIT=1
|
||||
|
||||
BUILD_IMAGE_NAME="void-appimage-builder"
|
||||
|
||||
# Check if Docker is running
|
||||
if ! docker info >/dev/null 2>&1; then
|
||||
echo "Docker is not running. Please start Docker first."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check and install Buildx if needed
|
||||
if ! docker buildx version >/dev/null 2>&1; then
|
||||
echo "Installing Docker Buildx..."
|
||||
mkdir -p ~/.docker/cli-plugins/
|
||||
curl -SL https://github.com/docker/buildx/releases/download/v0.13.1/buildx-v0.13.1.linux-amd64 -o ~/.docker/cli-plugins/docker-buildx
|
||||
chmod +x ~/.docker/cli-plugins/docker-buildx
|
||||
fi
|
||||
|
||||
# Download appimagetool if not present
|
||||
if [ ! -f "appimagetool" ]; then
|
||||
echo "Downloading appimagetool..."
|
||||
wget -O appimagetool "https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage"
|
||||
chmod +x appimagetool
|
||||
fi
|
||||
|
||||
# Delete any existing AppImage to avoid bloating the build
|
||||
rm -f Void-x86_64.AppImage
|
||||
|
||||
# Create build Dockerfile
|
||||
echo "Creating build Dockerfile..."
|
||||
cat > Dockerfile.build << 'EOF'
|
||||
# syntax=docker/dockerfile:1
|
||||
FROM ubuntu:20.04
|
||||
|
||||
# Install required dependencies
|
||||
RUN apt-get update && apt-get install -y \
|
||||
libfuse2 \
|
||||
libglib2.0-0 \
|
||||
libgtk-3-0 \
|
||||
libx11-xcb1 \
|
||||
libxss1 \
|
||||
libxtst6 \
|
||||
libnss3 \
|
||||
libasound2 \
|
||||
libdrm2 \
|
||||
libgbm1 \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
WORKDIR /app
|
||||
EOF
|
||||
|
||||
# Create .dockerignore file
|
||||
echo "Creating .dockerignore file..."
|
||||
cat > .dockerignore << EOF
|
||||
Dockerfile.build
|
||||
.dockerignore
|
||||
.git
|
||||
.gitignore
|
||||
.DS_Store
|
||||
*~
|
||||
*.swp
|
||||
*.swo
|
||||
*.tmp
|
||||
*.bak
|
||||
*.log
|
||||
*.err
|
||||
node_modules/
|
||||
venv/
|
||||
*.egg-info/
|
||||
*.tox/
|
||||
dist/
|
||||
EOF
|
||||
|
||||
# Build Docker image without cache
|
||||
echo "Building Docker image (no cache)..."
|
||||
docker build --no-cache -t "$BUILD_IMAGE_NAME" -f Dockerfile.build .
|
||||
|
||||
# Create AppImage using local appimagetool
|
||||
echo "Creating AppImage..."
|
||||
docker run --rm --privileged -v "$(pwd):/app" "$BUILD_IMAGE_NAME" bash -c '
|
||||
cd /app && \
|
||||
rm -rf VoidApp.AppDir && \
|
||||
mkdir -p VoidApp.AppDir/usr/bin VoidApp.AppDir/usr/lib VoidApp.AppDir/usr/share/applications && \
|
||||
find . -maxdepth 1 ! -name VoidApp.AppDir ! -name "." ! -name ".." -exec cp -r {} VoidApp.AppDir/usr/bin/ \; && \
|
||||
cp void.png VoidApp.AppDir/ && \
|
||||
echo "[Desktop Entry]" > VoidApp.AppDir/void.desktop && \
|
||||
echo "Name=Void" >> VoidApp.AppDir/void.desktop && \
|
||||
echo "Comment=Open source AI code editor." >> VoidApp.AppDir/void.desktop && \
|
||||
echo "GenericName=Text Editor" >> VoidApp.AppDir/void.desktop && \
|
||||
echo "Exec=void %F" >> VoidApp.AppDir/void.desktop && \
|
||||
echo "Icon=void" >> VoidApp.AppDir/void.desktop && \
|
||||
echo "Type=Application" >> VoidApp.AppDir/void.desktop && \
|
||||
echo "StartupNotify=false" >> VoidApp.AppDir/void.desktop && \
|
||||
echo "StartupWMClass=Void" >> VoidApp.AppDir/void.desktop && \
|
||||
echo "Categories=TextEditor;Development;IDE;" >> VoidApp.AppDir/void.desktop && \
|
||||
echo "MimeType=application/x-void-workspace;" >> VoidApp.AppDir/void.desktop && \
|
||||
echo "Keywords=void;" >> VoidApp.AppDir/void.desktop && \
|
||||
echo "Actions=new-empty-window;" >> VoidApp.AppDir/void.desktop && \
|
||||
echo "[Desktop Action new-empty-window]" >> VoidApp.AppDir/void.desktop && \
|
||||
echo "Name=New Empty Window" >> VoidApp.AppDir/void.desktop && \
|
||||
echo "Name[de]=Neues leeres Fenster" >> VoidApp.AppDir/void.desktop && \
|
||||
echo "Name[es]=Nueva ventana vacía" >> VoidApp.AppDir/void.desktop && \
|
||||
echo "Name[fr]=Nouvelle fenêtre vide" >> VoidApp.AppDir/void.desktop && \
|
||||
echo "Name[it]=Nuova finestra vuota" >> VoidApp.AppDir/void.desktop && \
|
||||
echo "Name[ja]=新しい空のウィンドウ" >> VoidApp.AppDir/void.desktop && \
|
||||
echo "Name[ko]=새 빈 창" >> VoidApp.AppDir/void.desktop && \
|
||||
echo "Name[ru]=Новое пустое окно" >> VoidApp.AppDir/void.desktop && \
|
||||
echo "Name[zh_CN]=新建空窗口" >> VoidApp.AppDir/void.desktop && \
|
||||
echo "Name[zh_TW]=開新空視窗" >> VoidApp.AppDir/void.desktop && \
|
||||
echo "Exec=void --new-window %F" >> VoidApp.AppDir/void.desktop && \
|
||||
echo "Icon=void" >> VoidApp.AppDir/void.desktop && \
|
||||
chmod +x VoidApp.AppDir/void.desktop && \
|
||||
cp VoidApp.AppDir/void.desktop VoidApp.AppDir/usr/share/applications/ && \
|
||||
echo "[Desktop Entry]" > VoidApp.AppDir/void-url-handler.desktop && \
|
||||
echo "Name=Void - URL Handler" > VoidApp.AppDir/void-url-handler.desktop && \
|
||||
echo "Comment=Open source AI code editor." > VoidApp.AppDir/void-url-handler.desktop && \
|
||||
echo "GenericName=Text Editor" > VoidApp.AppDir/void-url-handler.desktop && \
|
||||
echo "Exec=void --open-url %U" > VoidApp.AppDir/void-url-handler.desktop && \
|
||||
echo "Icon=void" > VoidApp.AppDir/void-url-handler.desktop && \
|
||||
echo "Type=Application" > VoidApp.AppDir/void-url-handler.desktop && \
|
||||
echo "NoDisplay=true" > VoidApp.AppDir/void-url-handler.desktop && \
|
||||
echo "StartupNotify=true" > VoidApp.AppDir/void-url-handler.desktop && \
|
||||
echo "Categories=Utility;TextEditor;Development;IDE;" > VoidApp.AppDir/void-url-handler.desktop && \
|
||||
echo "MimeType=x-scheme-handler/void;" > VoidApp.AppDir/void-url-handler.desktop && \
|
||||
echo "Keywords=void;" > VoidApp.AppDir/void-url-handler.desktop && \
|
||||
chmod +x VoidApp.AppDir/void-url-handler.desktop && \
|
||||
cp VoidApp.AppDir/void-url-handler.desktop VoidApp.AppDir/usr/share/applications/ && \
|
||||
echo "#!/bin/bash" > VoidApp.AppDir/AppRun && \
|
||||
echo "HERE=\$(dirname \"\$(readlink -f \"\${0}\")\")" >> VoidApp.AppDir/AppRun && \
|
||||
echo "export PATH=\${HERE}/usr/bin:\${PATH}" >> VoidApp.AppDir/AppRun && \
|
||||
echo "export LD_LIBRARY_PATH=\${HERE}/usr/lib:\${LD_LIBRARY_PATH}" >> VoidApp.AppDir/AppRun && \
|
||||
echo "exec \${HERE}/usr/bin/void --no-sandbox \"\$@\"" >> VoidApp.AppDir/AppRun && \
|
||||
chmod +x VoidApp.AppDir/AppRun && \
|
||||
chmod -R 755 VoidApp.AppDir && \
|
||||
|
||||
# Strip unneeded symbols from the binary to reduce size
|
||||
strip --strip-unneeded VoidApp.AppDir/usr/bin/void
|
||||
|
||||
ls -la VoidApp.AppDir/ && \
|
||||
ARCH=x86_64 ./appimagetool -n VoidApp.AppDir Void-x86_64.AppImage
|
||||
'
|
||||
|
||||
# Clean up
|
||||
rm -rf VoidApp.AppDir .dockerignore appimagetool
|
||||
|
||||
echo "AppImage creation complete! Your AppImage is: Void-x86_64.AppImage"
|
||||
@@ -0,0 +1,127 @@
|
||||
|
||||
|
||||
# README
|
||||
|
||||
This is a community-made AppImage creation script.
|
||||
|
||||
There are some reported bugs with it.
|
||||
|
||||
To generate an AppImage yourself, feel free to look at
|
||||
stable-linux.yml in the separate `void-builder/` repo,
|
||||
which runs a GitHub Action that builds the AppImage you see on our website.
|
||||
|
||||
|
||||
# Void AppImage Creation Script
|
||||
|
||||
This script automates the process of creating an AppImage for the Void Editor using Docker. It works on macOS and Linux platforms.
|
||||
## Requirements
|
||||
|
||||
* **Docker:** The script relies on Docker to build the AppImage inside a container.
|
||||
* **macOS or Linux:** The script is designed for these platforms. On macOS, it generates a Linux-compatible AppImage.
|
||||
* **Internet Connection:** Required for downloading necessary tools (like `docker-buildx` and `appimagetool` inside the Docker container).
|
||||
|
||||
## Prerequisites
|
||||
|
||||
1. **Install Docker:**
|
||||
|
||||
* **macOS:** Download and install Docker Desktop from [docker.com](docker.com).
|
||||
* **Ubuntu:**
|
||||
```bash
|
||||
sudo apt install docker.io
|
||||
```
|
||||
* **Arch Linux:**
|
||||
```bash
|
||||
sudo pacman -S docker
|
||||
```
|
||||
* **Fedora:**
|
||||
```bash
|
||||
sudo dnf install docker
|
||||
```
|
||||
|
||||
2. **Set Docker User Group:**
|
||||
|
||||
Docker requires users to be part of the `docker` group to run Docker commands without `sudo`.
|
||||
|
||||
```bash
|
||||
sudo usermod -aG docker $USER
|
||||
```
|
||||
|
||||
After running this command, log out and log back in for the group changes to take effect.
|
||||
|
||||
3. **Enable and Start Docker:**
|
||||
|
||||
```bash
|
||||
sudo systemctl enable docker
|
||||
sudo systemctl start docker
|
||||
```
|
||||
|
||||
## Ubuntu Dependencies (Installed via Docker)
|
||||
|
||||
These dependencies are installed within the Docker container (Ubuntu 20.04 base). You generally don't need to install them manually:
|
||||
|
||||
* `libfuse2`
|
||||
* `libglib2.0-0`
|
||||
* `libgtk-3-0`
|
||||
* `libx11-xcb1`
|
||||
* `libxss1`
|
||||
* `libxtst6`
|
||||
* `libnss3`
|
||||
* `libasound2`
|
||||
* `libdrm2`
|
||||
* `libgbm1`
|
||||
|
||||
## Usage Instructions
|
||||
|
||||
1. **Clone or Download the Script:**
|
||||
|
||||
Save the script to your system as `create_appimage.sh`.
|
||||
|
||||
2. **Make the Script Executable:**
|
||||
|
||||
```bash
|
||||
chmod +x create_appimage.sh
|
||||
```
|
||||
|
||||
3. **Copy Required Files:**
|
||||
|
||||
Copy the following files to the directory where the app binary is being bundled (created during the build process):
|
||||
|
||||
* `create_appimage.sh`
|
||||
* `void.desktop`
|
||||
* `void.png`
|
||||
|
||||
4. **Run the Script:**
|
||||
|
||||
```bash
|
||||
./create_appimage.sh
|
||||
```
|
||||
|
||||
5. **Result:**
|
||||
|
||||
After the script completes, it will generate an AppImage named `Void-x86_64.AppImage` (or similar, depending on your architecture) in the current directory.
|
||||
|
||||
## Script Overview
|
||||
|
||||
* **Platform Check:** Checks for macOS or Linux. Exits if unsupported.
|
||||
* **Docker Checks:** Ensures Docker is installed and running.
|
||||
* **Buildx Installation:** Installs `docker buildx` if missing.
|
||||
* **`appimagetool` Download:** Downloads `appimagetool` inside the Docker container.
|
||||
* **Dockerfile Creation:** Creates a temporary `Dockerfile.build` for the Ubuntu-based environment.
|
||||
* **Docker Image Build:** Builds a Docker image and runs the build process.
|
||||
* **AppImage Creation:**
|
||||
* Creates the `VoidApp.AppDir` structure.
|
||||
* Copies binaries, resources, and the `.desktop` entry.
|
||||
* Copies `void.desktop` and `void.png`.
|
||||
* Strips unnecessary symbols from the binary.
|
||||
* Runs `appimagetool` to generate the AppImage.
|
||||
* **Cleanup:** Removes the temporary `Dockerfile.build`.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
* **Docker Not Running:** Ensure Docker is installed and running.
|
||||
* **Permission Issues:** Try running the script with `sudo` or check Docker permissions.
|
||||
* **Outdated Dependencies:** Ensure you have the minimum required versions.
|
||||
|
||||
## License
|
||||
|
||||
This script is provided "as is". It is free to use, modify, and distribute, but comes with no warranty.
|
||||
@@ -0,0 +1,12 @@
|
||||
[Desktop Entry]
|
||||
Name=Void - URL Handler
|
||||
Comment=Open source AI code editor.
|
||||
GenericName=Text Editor
|
||||
Exec=void --open-url %U
|
||||
Icon=void
|
||||
Type=Application
|
||||
NoDisplay=true
|
||||
StartupNotify=true
|
||||
Categories=Utility;TextEditor;Development;IDE;
|
||||
MimeType=x-scheme-handler/void;
|
||||
Keywords=void;
|
||||
Executable
+27
@@ -0,0 +1,27 @@
|
||||
[Desktop Entry]
|
||||
Name=Void
|
||||
Comment=Open source AI code editor.
|
||||
GenericName=Text Editor
|
||||
Exec=void %F
|
||||
Icon=void
|
||||
Type=Application
|
||||
StartupNotify=false
|
||||
StartupWMClass=Void
|
||||
Categories=TextEditor;Development;IDE;
|
||||
MimeType=application/x-void-workspace;
|
||||
Keywords=void;
|
||||
Actions=new-empty-window;
|
||||
|
||||
[Desktop Action new-empty-window]
|
||||
Name=New Empty Window
|
||||
Name[de]=Neues leeres Fenster
|
||||
Name[es]=Nueva ventana vacía
|
||||
Name[fr]=Nouvelle fenêtre vide
|
||||
Name[it]=Nuova finestra vuota
|
||||
Name[ja]=新しい空のウィンドウ
|
||||
Name[ko]=새 빈 창
|
||||
Name[ru]=Новое пустое окно
|
||||
Name[zh_CN]=新建空窗口
|
||||
Name[zh_TW]=開新空視窗
|
||||
Exec=void --new-window %F
|
||||
Icon=void
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 795 KiB |
@@ -0,0 +1,37 @@
|
||||
@echo off
|
||||
setlocal
|
||||
|
||||
title VSCode Dev
|
||||
|
||||
pushd %~dp0..
|
||||
|
||||
:: Get electron, compile, built-in extensions
|
||||
if "%VSCODE_SKIP_PRELAUNCH%"=="" node build/lib/preLaunch.js
|
||||
|
||||
for /f "tokens=2 delims=:," %%a in ('findstr /R /C:"\"nameShort\":.*" product.json') do set NAMESHORT=%%~a
|
||||
set NAMESHORT=%NAMESHORT: "=%
|
||||
set NAMESHORT=%NAMESHORT:"=%.exe
|
||||
set CODE=".build\electron\%NAMESHORT%"
|
||||
|
||||
:: Manage built-in extensions
|
||||
if "%~1"=="--builtin" goto builtin
|
||||
|
||||
:: Configuration
|
||||
set ELECTRON_RUN_AS_NODE=1
|
||||
set NODE_ENV=development
|
||||
set VSCODE_DEV=1
|
||||
set ELECTRON_ENABLE_LOGGING=1
|
||||
set ELECTRON_ENABLE_STACK_DUMPING=1
|
||||
|
||||
:: Launch Code
|
||||
%CODE% --inspect=5874 out\cli.js %~dp0.. %*
|
||||
goto end
|
||||
|
||||
:builtin
|
||||
%CODE% build/builtin
|
||||
|
||||
:end
|
||||
|
||||
popd
|
||||
|
||||
endlocal
|
||||
Executable
+40
@@ -0,0 +1,40 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
realpath() { [[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}"; }
|
||||
ROOT=$(dirname $(dirname $(realpath "$0")))
|
||||
else
|
||||
ROOT=$(dirname $(dirname $(readlink -f $0)))
|
||||
fi
|
||||
|
||||
function code() {
|
||||
cd $ROOT
|
||||
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
NAME=`node -p "require('./product.json').nameLong"`
|
||||
CODE="./.build/electron/$NAME.app/Contents/MacOS/Electron"
|
||||
else
|
||||
NAME=`node -p "require('./product.json').applicationName"`
|
||||
CODE=".build/electron/$NAME"
|
||||
fi
|
||||
|
||||
# Get electron, compile, built-in extensions
|
||||
if [[ -z "${VSCODE_SKIP_PRELAUNCH}" ]]; then
|
||||
node build/lib/preLaunch.js
|
||||
fi
|
||||
|
||||
# Manage built-in extensions
|
||||
if [[ "$1" == "--builtin" ]]; then
|
||||
exec "$CODE" build/builtin
|
||||
return
|
||||
fi
|
||||
|
||||
ELECTRON_RUN_AS_NODE=1 \
|
||||
NODE_ENV=development \
|
||||
VSCODE_DEV=1 \
|
||||
ELECTRON_ENABLE_LOGGING=1 \
|
||||
ELECTRON_ENABLE_STACK_DUMPING=1 \
|
||||
"$CODE" --inspect=5874 "$ROOT/out/cli.js" . "$@"
|
||||
}
|
||||
|
||||
code "$@"
|
||||
@@ -0,0 +1,91 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
// @ts-check
|
||||
|
||||
const path = require('path');
|
||||
const perf = require('@vscode/vscode-perf');
|
||||
|
||||
const VSCODE_FOLDER = path.join(__dirname, '..');
|
||||
|
||||
async function main() {
|
||||
|
||||
const args = process.argv;
|
||||
/** @type {string | undefined} */
|
||||
let build = undefined;
|
||||
|
||||
if (args.indexOf('--help') === -1 && args.indexOf('-h') === -1) {
|
||||
// get build arg from args
|
||||
let buildArgIndex = args.indexOf('--build');
|
||||
buildArgIndex = buildArgIndex === -1 ? args.indexOf('-b') : buildArgIndex;
|
||||
if (buildArgIndex === -1) {
|
||||
let runtimeArgIndex = args.indexOf('--runtime');
|
||||
runtimeArgIndex = runtimeArgIndex === -1 ? args.indexOf('-r') : runtimeArgIndex;
|
||||
if (runtimeArgIndex !== -1 && args[runtimeArgIndex + 1] !== 'desktop') {
|
||||
console.error('Please provide the --build argument. It is an executable file for desktop or a URL for web');
|
||||
process.exit(1);
|
||||
}
|
||||
build = getLocalCLIPath();
|
||||
} else {
|
||||
build = args[buildArgIndex + 1];
|
||||
if (build !== 'insider' && build !== 'stable' && build !== 'exploration') {
|
||||
build = getExePath(args[buildArgIndex + 1]);
|
||||
}
|
||||
args.splice(buildArgIndex + 1, 1);
|
||||
}
|
||||
|
||||
args.push('--folder');
|
||||
args.push(VSCODE_FOLDER);
|
||||
args.push('--file');
|
||||
args.push(path.join(VSCODE_FOLDER, 'package.json'));
|
||||
}
|
||||
|
||||
if (build) {
|
||||
args.push('--build');
|
||||
args.push(build);
|
||||
}
|
||||
|
||||
await perf.run();
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} buildPath
|
||||
* @returns {string}
|
||||
*/
|
||||
function getExePath(buildPath) {
|
||||
buildPath = path.normalize(path.resolve(buildPath));
|
||||
if (buildPath === path.normalize(getLocalCLIPath())) {
|
||||
return buildPath;
|
||||
}
|
||||
let relativeExePath;
|
||||
switch (process.platform) {
|
||||
case 'darwin':
|
||||
relativeExePath = path.join('Contents', 'MacOS', 'Electron');
|
||||
break;
|
||||
case 'linux': {
|
||||
const product = require(path.join(buildPath, 'resources', 'app', 'product.json'));
|
||||
relativeExePath = product.applicationName;
|
||||
break;
|
||||
}
|
||||
case 'win32': {
|
||||
const product = require(path.join(buildPath, 'resources', 'app', 'product.json'));
|
||||
relativeExePath = `${product.nameShort}.exe`;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new Error('Unsupported platform.');
|
||||
}
|
||||
return buildPath.endsWith(relativeExePath) ? buildPath : path.join(buildPath, relativeExePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {string}
|
||||
*/
|
||||
function getLocalCLIPath() {
|
||||
return process.platform === 'win32' ? path.join(VSCODE_FOLDER, 'scripts', 'code.bat') : path.join(VSCODE_FOLDER, 'scripts', 'code.sh');
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -0,0 +1,31 @@
|
||||
@echo off
|
||||
setlocal
|
||||
|
||||
title VSCode Server
|
||||
|
||||
set ROOT_DIR=%~dp0..
|
||||
|
||||
pushd %ROOT_DIR%
|
||||
|
||||
:: Configuration
|
||||
set NODE_ENV=development
|
||||
set VSCODE_DEV=1
|
||||
|
||||
:: Get electron, compile, built-in extensions
|
||||
if "%VSCODE_SKIP_PRELAUNCH%"=="" node build/lib/preLaunch.js
|
||||
|
||||
:: Node executable
|
||||
FOR /F "tokens=*" %%g IN ('node build/lib/node.js') do (SET NODE=%%g)
|
||||
|
||||
if not exist "%NODE%" (
|
||||
:: Download nodejs executable for remote
|
||||
call npm run gulp node
|
||||
)
|
||||
|
||||
popd
|
||||
|
||||
:: Launch Server
|
||||
call "%NODE%" %ROOT_DIR%\scripts\code-server.js %*
|
||||
|
||||
|
||||
endlocal
|
||||
@@ -0,0 +1,71 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
// @ts-check
|
||||
|
||||
const cp = require('child_process');
|
||||
const path = require('path');
|
||||
const open = require('open');
|
||||
const minimist = require('minimist');
|
||||
|
||||
async function main() {
|
||||
|
||||
const args = minimist(process.argv.slice(2), {
|
||||
boolean: [
|
||||
'help',
|
||||
'launch'
|
||||
]
|
||||
});
|
||||
|
||||
if (args.help) {
|
||||
console.log(
|
||||
'./scripts/code-server.sh|bat [options]\n' +
|
||||
' --launch Opens a browser'
|
||||
);
|
||||
startServer(['--help']);
|
||||
return;
|
||||
}
|
||||
|
||||
process.env['VSCODE_SERVER_PORT'] = '9888';
|
||||
|
||||
const serverArgs = process.argv.slice(2).filter(v => v !== '--launch');
|
||||
const addr = await startServer(serverArgs);
|
||||
if (args['launch']) {
|
||||
open(addr);
|
||||
}
|
||||
}
|
||||
|
||||
function startServer(programArgs) {
|
||||
return new Promise((s, e) => {
|
||||
const env = { ...process.env };
|
||||
const entryPoint = path.join(__dirname, '..', 'out', 'server-main.js');
|
||||
|
||||
console.log(`Starting server: ${entryPoint} ${programArgs.join(' ')}`);
|
||||
const proc = cp.spawn(process.execPath, [entryPoint, ...programArgs], { env, stdio: [process.stdin, null, process.stderr] });
|
||||
proc.stdout.on('data', e => {
|
||||
const data = e.toString();
|
||||
process.stdout.write(data);
|
||||
const m = data.match(/Web UI available at (.*)/);
|
||||
if (m) {
|
||||
s(m[1]);
|
||||
}
|
||||
});
|
||||
|
||||
proc.on('exit', (code) => process.exit(code));
|
||||
|
||||
process.on('exit', () => proc.kill());
|
||||
process.on('SIGINT', () => {
|
||||
proc.kill();
|
||||
process.exit(128 + 2); // https://nodejs.org/docs/v14.16.0/api/process.html#process_signal_events
|
||||
});
|
||||
process.on('SIGTERM', () => {
|
||||
proc.kill();
|
||||
process.exit(128 + 15); // https://nodejs.org/docs/v14.16.0/api/process.html#process_signal_events
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
main();
|
||||
Executable
+31
@@ -0,0 +1,31 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
realpath() { [[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}"; }
|
||||
ROOT=$(dirname $(dirname $(realpath "$0")))
|
||||
else
|
||||
ROOT=$(dirname $(dirname $(readlink -f $0)))
|
||||
fi
|
||||
|
||||
function code() {
|
||||
pushd $ROOT
|
||||
|
||||
# Get electron, compile, built-in extensions
|
||||
if [[ -z "${VSCODE_SKIP_PRELAUNCH}" ]]; then
|
||||
node build/lib/preLaunch.js
|
||||
fi
|
||||
|
||||
NODE=$(node build/lib/node.js)
|
||||
if [ ! -e $NODE ];then
|
||||
# Load remote node
|
||||
npm run gulp node
|
||||
fi
|
||||
|
||||
popd
|
||||
|
||||
NODE_ENV=development \
|
||||
VSCODE_DEV=1 \
|
||||
$NODE $ROOT/scripts/code-server.js "$@"
|
||||
}
|
||||
|
||||
code "$@"
|
||||
@@ -0,0 +1,24 @@
|
||||
@echo off
|
||||
setlocal
|
||||
|
||||
title VSCode Web Serverless
|
||||
|
||||
pushd %~dp0\..
|
||||
|
||||
:: Sync built-in extensions
|
||||
call npm run download-builtin-extensions
|
||||
|
||||
:: Node executable
|
||||
FOR /F "tokens=*" %%g IN ('node build/lib/node.js') do (SET NODE=%%g)
|
||||
|
||||
if not exist "%NODE%" (
|
||||
:: Download nodejs executable for remote
|
||||
call npm run gulp node
|
||||
)
|
||||
|
||||
:: Launch Server
|
||||
call "%NODE%" scripts\code-web.js %*
|
||||
|
||||
popd
|
||||
|
||||
endlocal
|
||||
@@ -0,0 +1,167 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
// @ts-check
|
||||
|
||||
const testWebLocation = require.resolve('@vscode/test-web');
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const cp = require('child_process');
|
||||
|
||||
const minimist = require('minimist');
|
||||
const fancyLog = require('fancy-log');
|
||||
const ansiColors = require('ansi-colors');
|
||||
const open = require('open');
|
||||
const https = require('https');
|
||||
|
||||
const APP_ROOT = path.join(__dirname, '..');
|
||||
const WEB_DEV_EXTENSIONS_ROOT = path.join(APP_ROOT, '.build', 'builtInWebDevExtensions');
|
||||
|
||||
const WEB_PLAYGROUND_VERSION = '0.0.13';
|
||||
|
||||
async function main() {
|
||||
|
||||
const args = minimist(process.argv.slice(2), {
|
||||
boolean: [
|
||||
'help',
|
||||
'playground'
|
||||
],
|
||||
string: [
|
||||
'host',
|
||||
'port',
|
||||
'extensionPath',
|
||||
'browser',
|
||||
'browserType'
|
||||
],
|
||||
});
|
||||
|
||||
if (args.help) {
|
||||
console.log(
|
||||
'./scripts/code-web.sh|bat[, folderMountPath[, options]]\n' +
|
||||
' Start with an empty workspace and no folder opened in explorer\n' +
|
||||
' folderMountPath Open local folder (eg: use `.` to open current directory)\n' +
|
||||
' --playground Include the vscode-web-playground extension\n'
|
||||
);
|
||||
startServer(['--help']);
|
||||
return;
|
||||
}
|
||||
|
||||
const serverArgs = [];
|
||||
|
||||
const HOST = args['host'] ?? 'localhost';
|
||||
const PORT = args['port'] ?? '8080';
|
||||
|
||||
if (args['host'] === undefined) {
|
||||
serverArgs.push('--host', HOST);
|
||||
}
|
||||
if (args['port'] === undefined) {
|
||||
serverArgs.push('--port', PORT);
|
||||
}
|
||||
|
||||
// only use `./scripts/code-web.sh --playground` to add vscode-web-playground extension by default.
|
||||
if (args['playground'] === true) {
|
||||
serverArgs.push('--extensionPath', WEB_DEV_EXTENSIONS_ROOT);
|
||||
serverArgs.push('--folder-uri', 'memfs:///sample-folder');
|
||||
await ensureWebDevExtensions(args['verbose']);
|
||||
}
|
||||
|
||||
let openSystemBrowser = false;
|
||||
if (!args['browser'] && !args['browserType']) {
|
||||
serverArgs.push('--browserType', 'none');
|
||||
openSystemBrowser = true;
|
||||
}
|
||||
|
||||
serverArgs.push('--sourcesPath', APP_ROOT);
|
||||
|
||||
serverArgs.push(...process.argv.slice(2).filter(v => !v.startsWith('--playground') && v !== '--no-playground'));
|
||||
|
||||
startServer(serverArgs);
|
||||
if (openSystemBrowser) {
|
||||
open(`http://${HOST}:${PORT}/`);
|
||||
}
|
||||
}
|
||||
|
||||
function startServer(runnerArguments) {
|
||||
const env = { ...process.env };
|
||||
|
||||
console.log(`Starting @vscode/test-web: ${testWebLocation} ${runnerArguments.join(' ')}`);
|
||||
const proc = cp.spawn(process.execPath, [testWebLocation, ...runnerArguments], { env, stdio: 'inherit' });
|
||||
|
||||
proc.on('exit', (code) => process.exit(code));
|
||||
|
||||
process.on('exit', () => proc.kill());
|
||||
process.on('SIGINT', () => {
|
||||
proc.kill();
|
||||
process.exit(128 + 2); // https://nodejs.org/docs/v14.16.0/api/process.html#process_signal_events
|
||||
});
|
||||
process.on('SIGTERM', () => {
|
||||
proc.kill();
|
||||
process.exit(128 + 15); // https://nodejs.org/docs/v14.16.0/api/process.html#process_signal_events
|
||||
});
|
||||
}
|
||||
|
||||
async function directoryExists(path) {
|
||||
try {
|
||||
return (await fs.promises.stat(path)).isDirectory();
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/** @return {Promise<void>} */
|
||||
async function downloadPlaygroundFile(fileName, httpsLocation, destinationRoot) {
|
||||
const destination = path.join(destinationRoot, fileName);
|
||||
await fs.promises.mkdir(path.dirname(destination), { recursive: true });
|
||||
const fileStream = fs.createWriteStream(destination);
|
||||
return (new Promise((resolve, reject) => {
|
||||
const request = https.get(path.posix.join(httpsLocation, fileName), response => {
|
||||
response.pipe(fileStream);
|
||||
fileStream.on('finish', () => {
|
||||
fileStream.close();
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
request.on('error', reject);
|
||||
}));
|
||||
}
|
||||
|
||||
async function ensureWebDevExtensions(verbose) {
|
||||
|
||||
// Playground (https://github.com/microsoft/vscode-web-playground)
|
||||
const webDevPlaygroundRoot = path.join(WEB_DEV_EXTENSIONS_ROOT, 'vscode-web-playground');
|
||||
const webDevPlaygroundExists = await directoryExists(webDevPlaygroundRoot);
|
||||
|
||||
let downloadPlayground = false;
|
||||
if (webDevPlaygroundExists) {
|
||||
try {
|
||||
const webDevPlaygroundPackageJson = JSON.parse(((await fs.promises.readFile(path.join(webDevPlaygroundRoot, 'package.json'))).toString()));
|
||||
if (webDevPlaygroundPackageJson.version !== WEB_PLAYGROUND_VERSION) {
|
||||
downloadPlayground = true;
|
||||
}
|
||||
} catch (error) {
|
||||
downloadPlayground = true;
|
||||
}
|
||||
} else {
|
||||
downloadPlayground = true;
|
||||
}
|
||||
|
||||
if (downloadPlayground) {
|
||||
if (verbose) {
|
||||
fancyLog(`${ansiColors.magenta('Web Development extensions')}: Downloading vscode-web-playground to ${webDevPlaygroundRoot}`);
|
||||
}
|
||||
const playgroundRepo = `https://raw.githubusercontent.com/microsoft/vscode-web-playground/main/`;
|
||||
await Promise.all(['package.json', 'dist/extension.js', 'dist/extension.js.map'].map(
|
||||
fileName => downloadPlaygroundFile(fileName, playgroundRepo, webDevPlaygroundRoot)
|
||||
));
|
||||
|
||||
} else {
|
||||
if (verbose) {
|
||||
fancyLog(`${ansiColors.magenta('Web Development extensions')}: Using existing vscode-web-playground in ${webDevPlaygroundRoot}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
Executable
+27
@@ -0,0 +1,27 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
realpath() { [[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}"; }
|
||||
ROOT=$(dirname $(dirname $(realpath "$0")))
|
||||
else
|
||||
ROOT=$(dirname $(dirname $(readlink -f $0)))
|
||||
fi
|
||||
|
||||
function code() {
|
||||
cd $ROOT
|
||||
|
||||
# Sync built-in extensions
|
||||
npm run download-builtin-extensions
|
||||
|
||||
NODE=$(node build/lib/node.js)
|
||||
if [ ! -e $NODE ];then
|
||||
# Load remote node
|
||||
npm run gulp node
|
||||
fi
|
||||
|
||||
NODE=$(node build/lib/node.js)
|
||||
|
||||
$NODE ./scripts/code-web.js "$@"
|
||||
}
|
||||
|
||||
code "$@"
|
||||
@@ -0,0 +1,45 @@
|
||||
@echo off
|
||||
setlocal
|
||||
|
||||
title VSCode Dev
|
||||
|
||||
pushd %~dp0\..
|
||||
|
||||
:: Get electron, compile, built-in extensions
|
||||
if "%VSCODE_SKIP_PRELAUNCH%"=="" node build/lib/preLaunch.js
|
||||
|
||||
for /f "tokens=2 delims=:," %%a in ('findstr /R /C:"\"nameShort\":.*" product.json') do set NAMESHORT=%%~a
|
||||
set NAMESHORT=%NAMESHORT: "=%
|
||||
set NAMESHORT=%NAMESHORT:"=%.exe
|
||||
set CODE=".build\electron\%NAMESHORT%"
|
||||
|
||||
:: Manage built-in extensions
|
||||
if "%~1"=="--builtin" goto builtin
|
||||
|
||||
:: Configuration
|
||||
set NODE_ENV=development
|
||||
set VSCODE_DEV=1
|
||||
set VSCODE_CLI=1
|
||||
set ELECTRON_ENABLE_LOGGING=1
|
||||
set ELECTRON_ENABLE_STACK_DUMPING=1
|
||||
|
||||
set DISABLE_TEST_EXTENSION="--disable-extension=vscode.vscode-api-tests"
|
||||
for %%A in (%*) do (
|
||||
if "%%~A"=="--extensionTestsPath" (
|
||||
set DISABLE_TEST_EXTENSION=""
|
||||
)
|
||||
)
|
||||
|
||||
:: Launch Code
|
||||
|
||||
%CODE% . %DISABLE_TEST_EXTENSION% %*
|
||||
goto end
|
||||
|
||||
:builtin
|
||||
%CODE% build/builtin
|
||||
|
||||
:end
|
||||
|
||||
popd
|
||||
|
||||
endlocal
|
||||
Executable
+93
@@ -0,0 +1,93 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
realpath() { [[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}"; }
|
||||
ROOT=$(dirname "$(dirname "$(realpath "$0")")")
|
||||
else
|
||||
ROOT=$(dirname "$(dirname "$(readlink -f $0)")")
|
||||
# If the script is running in Docker using the WSL2 engine, powershell.exe won't exist
|
||||
if grep -qi Microsoft /proc/version && type powershell.exe > /dev/null 2>&1; then
|
||||
IN_WSL=true
|
||||
fi
|
||||
fi
|
||||
|
||||
function code() {
|
||||
cd "$ROOT"
|
||||
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
NAME=`node -p "require('./product.json').nameLong"`
|
||||
CODE="./.build/electron/$NAME.app/Contents/MacOS/Electron"
|
||||
else
|
||||
NAME=`node -p "require('./product.json').applicationName"`
|
||||
CODE=".build/electron/$NAME"
|
||||
fi
|
||||
|
||||
# Get electron, compile, built-in extensions
|
||||
if [[ -z "${VSCODE_SKIP_PRELAUNCH}" ]]; then
|
||||
node build/lib/preLaunch.js
|
||||
fi
|
||||
|
||||
# Manage built-in extensions
|
||||
if [[ "$1" == "--builtin" ]]; then
|
||||
exec "$CODE" build/builtin
|
||||
return
|
||||
fi
|
||||
|
||||
# Configuration
|
||||
export NODE_ENV=development
|
||||
export VSCODE_DEV=1
|
||||
export VSCODE_CLI=1
|
||||
export ELECTRON_ENABLE_STACK_DUMPING=1
|
||||
export ELECTRON_ENABLE_LOGGING=1
|
||||
|
||||
DISABLE_TEST_EXTENSION="--disable-extension=vscode.vscode-api-tests"
|
||||
if [[ "$@" == *"--extensionTestsPath"* ]]; then
|
||||
DISABLE_TEST_EXTENSION=""
|
||||
fi
|
||||
|
||||
# Launch Code
|
||||
exec "$CODE" . $DISABLE_TEST_EXTENSION "$@"
|
||||
}
|
||||
|
||||
function code-wsl()
|
||||
{
|
||||
HOST_IP=$(echo "" | powershell.exe -noprofile -Command "& {(Get-NetIPAddress | Where-Object {\$_.InterfaceAlias -like '*WSL*' -and \$_.AddressFamily -eq 'IPv4'}).IPAddress | Write-Host -NoNewline}")
|
||||
export DISPLAY="$HOST_IP:0"
|
||||
|
||||
# in a wsl shell
|
||||
ELECTRON="$ROOT/.build/electron/Code - OSS.exe"
|
||||
if [ -f "$ELECTRON" ]; then
|
||||
local CWD=$(pwd)
|
||||
cd $ROOT
|
||||
export WSLENV=ELECTRON_RUN_AS_NODE/w:VSCODE_DEV/w:$WSLENV
|
||||
local WSL_EXT_ID="ms-vscode-remote.remote-wsl"
|
||||
local WSL_EXT_WLOC=$(echo "" | VSCODE_DEV=1 ELECTRON_RUN_AS_NODE=1 "$ROOT/.build/electron/Code - OSS.exe" "out/cli.js" --locate-extension $WSL_EXT_ID)
|
||||
cd $CWD
|
||||
if [ -n "$WSL_EXT_WLOC" ]; then
|
||||
# replace \r\n with \n in WSL_EXT_WLOC
|
||||
local WSL_CODE=$(wslpath -u "${WSL_EXT_WLOC%%[[:cntrl:]]}")/scripts/wslCode-dev.sh
|
||||
$WSL_CODE "$ROOT" "$@"
|
||||
exit $?
|
||||
else
|
||||
echo "Remote WSL not installed, trying to run VSCode in WSL."
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
if [ "$IN_WSL" == "true" ] && [ -z "$DISPLAY" ]; then
|
||||
code-wsl "$@"
|
||||
elif [ -f /mnt/wslg/versions.txt ]; then
|
||||
code --disable-gpu "$@"
|
||||
elif [ -f /.dockerenv ]; then
|
||||
# Workaround for https://bugs.chromium.org/p/chromium/issues/detail?id=1263267
|
||||
# Chromium does not release shared memory when streaming scripts
|
||||
# which might exhaust the available resources in the container environment
|
||||
# leading to failed script loading.
|
||||
code --disable-dev-shm-usage "$@"
|
||||
else
|
||||
code "$@"
|
||||
fi
|
||||
|
||||
exit $?
|
||||
Executable
+31
@@ -0,0 +1,31 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
if [ $# -eq 0 ]; then
|
||||
echo "Pass in a version like ./scripts/generate-vscode-dts.sh 1.30."
|
||||
echo "Failed to generate index.d.ts."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
header="// Type definitions for Visual Studio Code ${1}
|
||||
// Project: https://github.com/microsoft/vscode
|
||||
// Definitions by: Visual Studio Code Team, Microsoft <https://github.com/microsoft>
|
||||
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
|
||||
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
* See https://github.com/microsoft/vscode/blob/main/LICENSE.txt for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Type Definition for Visual Studio Code ${1} Extension API
|
||||
* See https://code.visualstudio.com/api for more information
|
||||
*/"
|
||||
|
||||
if [ -f ./src/vscode-dts/vscode.d.ts ]; then
|
||||
echo "$header" > index.d.ts
|
||||
sed "1,4d" ./src/vscode-dts/vscode.d.ts >> index.d.ts
|
||||
echo "Generated index.d.ts for version ${1}."
|
||||
else
|
||||
echo "Can't find ./src/vscode-dts/vscode.d.ts. Run this script at vscode root."
|
||||
fi
|
||||
@@ -0,0 +1,18 @@
|
||||
@echo off
|
||||
setlocal
|
||||
|
||||
set ELECTRON_RUN_AS_NODE=1
|
||||
|
||||
pushd %~dp0\..
|
||||
|
||||
for /f "tokens=2 delims=:," %%a in ('findstr /R /C:"\"nameShort\":.*" product.json') do set NAMESHORT=%%~a
|
||||
set NAMESHORT=%NAMESHORT: "=%
|
||||
set NAMESHORT=%NAMESHORT:"=%.exe
|
||||
set CODE=".build\electron\%NAMESHORT%"
|
||||
|
||||
%CODE% %*
|
||||
|
||||
popd
|
||||
|
||||
endlocal
|
||||
exit /b %errorlevel%
|
||||
Executable
+34
@@ -0,0 +1,34 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
realpath() { [[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}"; }
|
||||
ROOT=$(dirname $(dirname $(realpath "$0")))
|
||||
else
|
||||
ROOT=$(dirname $(dirname $(readlink -f $0)))
|
||||
fi
|
||||
|
||||
pushd $ROOT
|
||||
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
NAME=`node -p "require('./product.json').nameLong"`
|
||||
CODE="$ROOT/.build/electron/$NAME.app/Contents/MacOS/Electron"
|
||||
else
|
||||
NAME=`node -p "require('./product.json').applicationName"`
|
||||
CODE="$ROOT/.build/electron/$NAME"
|
||||
fi
|
||||
|
||||
# Get electron
|
||||
npm run electron
|
||||
|
||||
popd
|
||||
|
||||
export VSCODE_DEV=1
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
ulimit -n 4096 ; ELECTRON_RUN_AS_NODE=1 \
|
||||
"$CODE" \
|
||||
"$@"
|
||||
else
|
||||
ELECTRON_RUN_AS_NODE=1 \
|
||||
"$CODE" \
|
||||
"$@"
|
||||
fi
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"type": "commonjs"
|
||||
}
|
||||
@@ -0,0 +1,896 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as fsPromise from 'fs/promises';
|
||||
import path from 'path';
|
||||
import * as http from 'http';
|
||||
import * as parcelWatcher from '@parcel/watcher';
|
||||
|
||||
/**
|
||||
* Launches the server for the monaco editor playground
|
||||
*/
|
||||
function main() {
|
||||
const server = new HttpServer({ host: 'localhost', port: 5001, cors: true });
|
||||
server.use('/', redirectToMonacoEditorPlayground());
|
||||
|
||||
const rootDir = path.join(__dirname, '..');
|
||||
const fileServer = new FileServer(rootDir);
|
||||
server.use(fileServer.handleRequest);
|
||||
|
||||
const moduleIdMapper = new SimpleModuleIdPathMapper(path.join(rootDir, 'out'));
|
||||
const editorMainBundle = new CachedBundle('vs/editor/editor.main', moduleIdMapper);
|
||||
fileServer.overrideFileContent(editorMainBundle.entryModulePath, () => editorMainBundle.bundle());
|
||||
|
||||
const loaderPath = path.join(rootDir, 'out/vs/loader.js');
|
||||
fileServer.overrideFileContent(loaderPath, async () =>
|
||||
Buffer.from(new TextEncoder().encode(makeLoaderJsHotReloadable(await fsPromise.readFile(loaderPath, 'utf8'), new URL('/file-changes', server.url))))
|
||||
);
|
||||
|
||||
const watcher = DirWatcher.watchRecursively(moduleIdMapper.rootDir);
|
||||
watcher.onDidChange((path, newContent) => {
|
||||
editorMainBundle.setModuleContent(path, newContent);
|
||||
editorMainBundle.bundle();
|
||||
console.log(`${new Date().toLocaleTimeString()}, file change: ${path}`);
|
||||
});
|
||||
server.use('/file-changes', handleGetFileChangesRequest(watcher, fileServer, moduleIdMapper));
|
||||
|
||||
console.log(`Server listening on ${server.url}`);
|
||||
}
|
||||
setTimeout(main, 0);
|
||||
|
||||
// #region Http/File Server
|
||||
|
||||
type RequestHandler = (req: http.IncomingMessage, res: http.ServerResponse) => Promise<void>;
|
||||
type ChainableRequestHandler = (req: http.IncomingMessage, res: http.ServerResponse, next: RequestHandler) => Promise<void>;
|
||||
|
||||
class HttpServer {
|
||||
private readonly server: http.Server;
|
||||
public readonly url: URL;
|
||||
|
||||
private handler: ChainableRequestHandler[] = [];
|
||||
|
||||
constructor(options: { host: string; port: number; cors: boolean }) {
|
||||
this.server = http.createServer(async (req, res) => {
|
||||
if (options.cors) {
|
||||
res.setHeader('Access-Control-Allow-Origin', '*');
|
||||
}
|
||||
|
||||
let i = 0;
|
||||
const next = async (req: http.IncomingMessage, res: http.ServerResponse) => {
|
||||
if (i >= this.handler.length) {
|
||||
res.writeHead(404, { 'Content-Type': 'text/plain' });
|
||||
res.end('404 Not Found');
|
||||
return;
|
||||
}
|
||||
const handler = this.handler[i];
|
||||
i++;
|
||||
await handler(req, res, next);
|
||||
};
|
||||
await next(req, res);
|
||||
});
|
||||
this.server.listen(options.port, options.host);
|
||||
this.url = new URL(`http://${options.host}:${options.port}`);
|
||||
}
|
||||
|
||||
use(handler: ChainableRequestHandler);
|
||||
use(path: string, handler: ChainableRequestHandler);
|
||||
use(...args: [path: string, handler: ChainableRequestHandler] | [handler: ChainableRequestHandler]) {
|
||||
const handler = args.length === 1 ? args[0] : (req, res, next) => {
|
||||
const path = args[0];
|
||||
const requestedUrl = new URL(req.url, this.url);
|
||||
if (requestedUrl.pathname === path) {
|
||||
return args[1](req, res, next);
|
||||
} else {
|
||||
return next(req, res);
|
||||
}
|
||||
};
|
||||
|
||||
this.handler.push(handler);
|
||||
}
|
||||
}
|
||||
|
||||
function redirectToMonacoEditorPlayground(): ChainableRequestHandler {
|
||||
return async (req, res) => {
|
||||
const url = new URL('https://microsoft.github.io/monaco-editor/playground.html');
|
||||
url.searchParams.append('source', `http://${req.headers.host}/out/vs`);
|
||||
res.writeHead(302, { Location: url.toString() });
|
||||
res.end();
|
||||
};
|
||||
}
|
||||
|
||||
class FileServer {
|
||||
private readonly overrides = new Map<string, () => Promise<Buffer>>();
|
||||
|
||||
constructor(public readonly publicDir: string) { }
|
||||
|
||||
public readonly handleRequest: ChainableRequestHandler = async (req, res, next) => {
|
||||
const requestedUrl = new URL(req.url!, `http://${req.headers.host}`);
|
||||
|
||||
const pathName = requestedUrl.pathname;
|
||||
|
||||
const filePath = path.join(this.publicDir, pathName);
|
||||
if (!filePath.startsWith(this.publicDir)) {
|
||||
res.writeHead(403, { 'Content-Type': 'text/plain' });
|
||||
res.end('403 Forbidden');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const override = this.overrides.get(filePath);
|
||||
let content: Buffer;
|
||||
if (override) {
|
||||
content = await override();
|
||||
} else {
|
||||
content = await fsPromise.readFile(filePath);
|
||||
}
|
||||
|
||||
const contentType = getContentType(filePath);
|
||||
res.writeHead(200, { 'Content-Type': contentType });
|
||||
res.end(content);
|
||||
} catch (err) {
|
||||
if (err.code === 'ENOENT') {
|
||||
next(req, res);
|
||||
} else {
|
||||
res.writeHead(500, { 'Content-Type': 'text/plain' });
|
||||
res.end('500 Internal Server Error');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public filePathToUrlPath(filePath: string): string | undefined {
|
||||
const relative = path.relative(this.publicDir, filePath);
|
||||
const isSubPath = !!relative && !relative.startsWith('..') && !path.isAbsolute(relative);
|
||||
|
||||
if (!isSubPath) {
|
||||
return undefined;
|
||||
}
|
||||
const relativePath = relative.replace(/\\/g, '/');
|
||||
return `/${relativePath}`;
|
||||
}
|
||||
|
||||
public overrideFileContent(filePath: string, content: () => Promise<Buffer>): void {
|
||||
this.overrides.set(filePath, content);
|
||||
}
|
||||
}
|
||||
|
||||
function getContentType(filePath: string): string {
|
||||
const extname = path.extname(filePath);
|
||||
switch (extname) {
|
||||
case '.js':
|
||||
return 'text/javascript';
|
||||
case '.css':
|
||||
return 'text/css';
|
||||
case '.json':
|
||||
return 'application/json';
|
||||
case '.png':
|
||||
return 'image/png';
|
||||
case '.jpg':
|
||||
return 'image/jpg';
|
||||
case '.svg':
|
||||
return 'image/svg+xml';
|
||||
case '.html':
|
||||
return 'text/html';
|
||||
case '.wasm':
|
||||
return 'application/wasm';
|
||||
default:
|
||||
return 'text/plain';
|
||||
}
|
||||
}
|
||||
|
||||
// #endregion
|
||||
|
||||
// #region File Watching
|
||||
|
||||
interface IDisposable {
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
class DirWatcher {
|
||||
public static watchRecursively(dir: string): DirWatcher {
|
||||
const listeners: ((path: string, newContent: string) => void)[] = [];
|
||||
const fileContents = new Map<string, string>();
|
||||
const event = (handler: (path: string, newContent: string) => void) => {
|
||||
listeners.push(handler);
|
||||
return {
|
||||
dispose: () => {
|
||||
const idx = listeners.indexOf(handler);
|
||||
if (idx >= 0) {
|
||||
listeners.splice(idx, 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
parcelWatcher.subscribe(dir, async (err, events) => {
|
||||
for (const e of events) {
|
||||
if (e.type === 'update') {
|
||||
const newContent = await fsPromise.readFile(e.path, 'utf8');
|
||||
if (fileContents.get(e.path) !== newContent) {
|
||||
fileContents.set(e.path, newContent);
|
||||
listeners.forEach(l => l(e.path, newContent));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return new DirWatcher(event);
|
||||
}
|
||||
|
||||
constructor(public readonly onDidChange: (handler: (path: string, newContent: string) => void) => IDisposable) {
|
||||
}
|
||||
}
|
||||
|
||||
function handleGetFileChangesRequest(watcher: DirWatcher, fileServer: FileServer, moduleIdMapper: SimpleModuleIdPathMapper): ChainableRequestHandler {
|
||||
return async (req, res) => {
|
||||
res.writeHead(200, { 'Content-Type': 'text/plain' });
|
||||
const d = watcher.onDidChange((fsPath, newContent) => {
|
||||
const path = fileServer.filePathToUrlPath(fsPath);
|
||||
if (path) {
|
||||
res.write(JSON.stringify({ changedPath: path, moduleId: moduleIdMapper.getModuleId(fsPath), newContent }) + '\n');
|
||||
}
|
||||
});
|
||||
res.on('close', () => d.dispose());
|
||||
};
|
||||
}
|
||||
function makeLoaderJsHotReloadable(loaderJsCode: string, fileChangesUrl: URL): string {
|
||||
loaderJsCode = loaderJsCode.replace(
|
||||
/constructor\(env, scriptLoader, defineFunc, requireFunc, loaderAvailableTimestamp = 0\) {/,
|
||||
'$&globalThis.___globalModuleManager = this; globalThis.vscode = { process: { env: { VSCODE_DEV: true } } }'
|
||||
);
|
||||
|
||||
const ___globalModuleManager: any = undefined;
|
||||
|
||||
// This code will be appended to loader.js
|
||||
function $watchChanges(fileChangesUrl: string) {
|
||||
interface HotReloadConfig { }
|
||||
|
||||
let reloadFn;
|
||||
if (globalThis.$sendMessageToParent) {
|
||||
reloadFn = () => globalThis.$sendMessageToParent({ kind: 'reload' });
|
||||
} else if (typeof window !== 'undefined') {
|
||||
reloadFn = () => window.location.reload();
|
||||
} else {
|
||||
reloadFn = () => { };
|
||||
}
|
||||
|
||||
console.log('Connecting to server to watch for changes...');
|
||||
(fetch as any)(fileChangesUrl)
|
||||
.then(async request => {
|
||||
const reader = request.body.getReader();
|
||||
let buffer = '';
|
||||
while (true) {
|
||||
const { done, value } = await reader.read();
|
||||
if (done) { break; }
|
||||
buffer += new TextDecoder().decode(value);
|
||||
const lines = buffer.split('\n');
|
||||
buffer = lines.pop()!;
|
||||
|
||||
const changes: { relativePath: string; config: HotReloadConfig | undefined; path: string; newContent: string }[] = [];
|
||||
|
||||
for (const line of lines) {
|
||||
const data = JSON.parse(line);
|
||||
const relativePath = data.changedPath.replace(/\\/g, '/').split('/out/')[1];
|
||||
changes.push({ config: {}, path: data.changedPath, relativePath, newContent: data.newContent });
|
||||
}
|
||||
|
||||
const result = handleChanges(changes, 'playground-server');
|
||||
if (result.reloadFailedJsFiles.length > 0) {
|
||||
reloadFn();
|
||||
}
|
||||
}
|
||||
}).catch(err => {
|
||||
console.error(err);
|
||||
setTimeout(() => $watchChanges(fileChangesUrl), 1000);
|
||||
});
|
||||
|
||||
|
||||
function handleChanges(changes: {
|
||||
relativePath: string;
|
||||
config: HotReloadConfig | undefined;
|
||||
path: string;
|
||||
newContent: string;
|
||||
}[], debugSessionName: string) {
|
||||
// This function is stringified and injected into the debuggee.
|
||||
|
||||
const hotReloadData: { count: number; originalWindowTitle: any; timeout: any; shouldReload: boolean } = globalThis.$hotReloadData || (globalThis.$hotReloadData = { count: 0, messageHideTimeout: undefined, shouldReload: false });
|
||||
|
||||
const reloadFailedJsFiles: { relativePath: string; path: string }[] = [];
|
||||
|
||||
for (const change of changes) {
|
||||
handleChange(change.relativePath, change.path, change.newContent, change.config);
|
||||
}
|
||||
|
||||
return { reloadFailedJsFiles };
|
||||
|
||||
function handleChange(relativePath: string, path: string, newSrc: string, config: any) {
|
||||
if (relativePath.endsWith('.css')) {
|
||||
handleCssChange(relativePath);
|
||||
} else if (relativePath.endsWith('.js')) {
|
||||
handleJsChange(relativePath, path, newSrc, config);
|
||||
}
|
||||
}
|
||||
|
||||
function handleCssChange(relativePath: string) {
|
||||
if (typeof document === 'undefined') {
|
||||
return;
|
||||
}
|
||||
|
||||
const styleSheet = (([...document.querySelectorAll(`link[rel='stylesheet']`)] as HTMLLinkElement[]))
|
||||
.find(l => new URL(l.href, document.location.href).pathname.endsWith(relativePath));
|
||||
if (styleSheet) {
|
||||
setMessage(`reload ${formatPath(relativePath)} - ${new Date().toLocaleTimeString()}`);
|
||||
console.log(debugSessionName, 'css reloaded', relativePath);
|
||||
styleSheet.href = styleSheet.href.replace(/\?.*/, '') + '?' + Date.now();
|
||||
} else {
|
||||
setMessage(`could not reload ${formatPath(relativePath)} - ${new Date().toLocaleTimeString()}`);
|
||||
console.log(debugSessionName, 'ignoring css change, as stylesheet is not loaded', relativePath);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function handleJsChange(relativePath: string, path: string, newSrc: string, config: any) {
|
||||
const moduleIdStr = trimEnd(relativePath, '.js');
|
||||
|
||||
const requireFn: any = globalThis.require;
|
||||
const moduleManager = (requireFn as any).moduleManager;
|
||||
if (!moduleManager) {
|
||||
console.log(debugSessionName, 'ignoring js change, as moduleManager is not available', relativePath);
|
||||
return;
|
||||
}
|
||||
|
||||
const moduleId = moduleManager._moduleIdProvider.getModuleId(moduleIdStr);
|
||||
const oldModule = moduleManager._modules2[moduleId];
|
||||
|
||||
if (!oldModule) {
|
||||
console.log(debugSessionName, 'ignoring js change, as module is not loaded', relativePath);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if we can reload
|
||||
const g = globalThis as any;
|
||||
|
||||
// A frozen copy of the previous exports
|
||||
const oldExports = Object.freeze({ ...oldModule.exports });
|
||||
const reloadFn = g.$hotReload_applyNewExports?.({ oldExports, newSrc, config });
|
||||
|
||||
if (!reloadFn) {
|
||||
console.log(debugSessionName, 'ignoring js change, as module does not support hot-reload', relativePath);
|
||||
hotReloadData.shouldReload = true;
|
||||
|
||||
reloadFailedJsFiles.push({ relativePath, path });
|
||||
|
||||
setMessage(`hot reload not supported for ${formatPath(relativePath)} - ${new Date().toLocaleTimeString()}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Eval maintains source maps
|
||||
function newScript(/* this parameter is used by newSrc */ define) {
|
||||
// eslint-disable-next-line no-eval
|
||||
eval(newSrc); // CodeQL [SM01632] This code is only executed during development. It is required for the hot-reload functionality.
|
||||
}
|
||||
|
||||
newScript(/* define */ function (deps, callback) {
|
||||
// Evaluating the new code was successful.
|
||||
|
||||
// Redefine the module
|
||||
delete moduleManager._modules2[moduleId];
|
||||
moduleManager.defineModule(moduleIdStr, deps, callback);
|
||||
const newModule = moduleManager._modules2[moduleId];
|
||||
|
||||
|
||||
// Patch the exports of the old module, so that modules using the old module get the new exports
|
||||
Object.assign(oldModule.exports, newModule.exports);
|
||||
// We override the exports so that future reloads still patch the initial exports.
|
||||
newModule.exports = oldModule.exports;
|
||||
|
||||
const successful = reloadFn(newModule.exports);
|
||||
if (!successful) {
|
||||
hotReloadData.shouldReload = true;
|
||||
setMessage(`hot reload failed ${formatPath(relativePath)} - ${new Date().toLocaleTimeString()}`);
|
||||
console.log(debugSessionName, 'hot reload was not successful', relativePath);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(debugSessionName, 'hot reloaded', moduleIdStr);
|
||||
setMessage(`successfully reloaded ${formatPath(relativePath)} - ${new Date().toLocaleTimeString()}`);
|
||||
});
|
||||
}
|
||||
|
||||
function setMessage(message: string) {
|
||||
const domElem = (document.querySelector('.titlebar-center .window-title')) as HTMLDivElement | undefined;
|
||||
if (!domElem) { return; }
|
||||
if (!hotReloadData.timeout) {
|
||||
hotReloadData.originalWindowTitle = domElem.innerText;
|
||||
} else {
|
||||
clearTimeout(hotReloadData.timeout);
|
||||
}
|
||||
if (hotReloadData.shouldReload) {
|
||||
message += ' (manual reload required)';
|
||||
}
|
||||
|
||||
domElem.innerText = message;
|
||||
hotReloadData.timeout = setTimeout(() => {
|
||||
hotReloadData.timeout = undefined;
|
||||
// If wanted, we can restore the previous title message
|
||||
// domElem.replaceChildren(hotReloadData.originalWindowTitle);
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
function formatPath(path: string): string {
|
||||
const parts = path.split('/');
|
||||
parts.reverse();
|
||||
let result = parts[0];
|
||||
parts.shift();
|
||||
for (const p of parts) {
|
||||
if (result.length + p.length > 40) {
|
||||
break;
|
||||
}
|
||||
result = p + '/' + result;
|
||||
if (result.length > 20) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function trimEnd(str, suffix) {
|
||||
if (str.endsWith(suffix)) {
|
||||
return str.substring(0, str.length - suffix.length);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const additionalJsCode = `
|
||||
(${(function () {
|
||||
globalThis.$hotReload_deprecateExports = new Set<(oldExports: any, newExports: any) => void>();
|
||||
}).toString()})();
|
||||
${$watchChanges.toString()}
|
||||
$watchChanges(${JSON.stringify(fileChangesUrl)});
|
||||
`;
|
||||
|
||||
return `${loaderJsCode}\n${additionalJsCode}`;
|
||||
}
|
||||
|
||||
// #endregion
|
||||
|
||||
// #region Bundling
|
||||
|
||||
class CachedBundle {
|
||||
public readonly entryModulePath = this.mapper.resolveRequestToPath(this.moduleId)!;
|
||||
|
||||
constructor(
|
||||
private readonly moduleId: string,
|
||||
private readonly mapper: SimpleModuleIdPathMapper,
|
||||
) {
|
||||
}
|
||||
|
||||
private loader: ModuleLoader | undefined = undefined;
|
||||
|
||||
private bundlePromise: Promise<Buffer> | undefined = undefined;
|
||||
public async bundle(): Promise<Buffer> {
|
||||
if (!this.bundlePromise) {
|
||||
this.bundlePromise = (async () => {
|
||||
if (!this.loader) {
|
||||
this.loader = new ModuleLoader(this.mapper);
|
||||
await this.loader.addModuleAndDependencies(this.entryModulePath);
|
||||
}
|
||||
const editorEntryPoint = await this.loader.getModule(this.entryModulePath);
|
||||
const content = bundleWithDependencies(editorEntryPoint!);
|
||||
return content;
|
||||
})();
|
||||
}
|
||||
return this.bundlePromise;
|
||||
}
|
||||
|
||||
public async setModuleContent(path: string, newContent: string): Promise<void> {
|
||||
if (!this.loader) {
|
||||
return;
|
||||
}
|
||||
const module = await this.loader!.getModule(path);
|
||||
if (module) {
|
||||
if (!this.loader.updateContent(module, newContent)) {
|
||||
this.loader = undefined;
|
||||
}
|
||||
}
|
||||
this.bundlePromise = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
function bundleWithDependencies(module: IModule): Buffer {
|
||||
const visited = new Set<IModule>();
|
||||
const builder = new SourceMapBuilder();
|
||||
|
||||
function visit(module: IModule) {
|
||||
if (visited.has(module)) {
|
||||
return;
|
||||
}
|
||||
visited.add(module);
|
||||
for (const dep of module.dependencies) {
|
||||
visit(dep);
|
||||
}
|
||||
builder.addSource(module.source);
|
||||
}
|
||||
|
||||
visit(module);
|
||||
|
||||
const sourceMap = builder.toSourceMap();
|
||||
sourceMap.sourceRoot = module.source.sourceMap.sourceRoot;
|
||||
const sourceMapBase64Str = Buffer.from(JSON.stringify(sourceMap)).toString('base64');
|
||||
|
||||
builder.addLine(`//# sourceMappingURL=data:application/json;base64,${sourceMapBase64Str}`);
|
||||
|
||||
return builder.toContent();
|
||||
}
|
||||
|
||||
class ModuleLoader {
|
||||
private readonly modules = new Map<string, Promise<IModule | undefined>>();
|
||||
|
||||
constructor(private readonly mapper: SimpleModuleIdPathMapper) { }
|
||||
|
||||
public getModule(path: string): Promise<IModule | undefined> {
|
||||
return Promise.resolve(this.modules.get(path));
|
||||
}
|
||||
|
||||
public updateContent(module: IModule, newContent: string): boolean {
|
||||
const parsedModule = parseModule(newContent, module.path, this.mapper);
|
||||
if (!parsedModule) {
|
||||
return false;
|
||||
}
|
||||
if (!arrayEquals(parsedModule.dependencyRequests, module.dependencyRequests)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
module.dependencyRequests = parsedModule.dependencyRequests;
|
||||
module.source = parsedModule.source;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
async addModuleAndDependencies(path: string): Promise<IModule | undefined> {
|
||||
if (this.modules.has(path)) {
|
||||
return this.modules.get(path)!;
|
||||
}
|
||||
|
||||
const promise = (async () => {
|
||||
const content = await fsPromise.readFile(path, { encoding: 'utf-8' });
|
||||
|
||||
const parsedModule = parseModule(content, path, this.mapper);
|
||||
if (!parsedModule) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const dependencies = (await Promise.all(parsedModule.dependencyRequests.map(async r => {
|
||||
if (r === 'require' || r === 'exports' || r === 'module') {
|
||||
return null;
|
||||
}
|
||||
|
||||
const depPath = this.mapper.resolveRequestToPath(r, path);
|
||||
if (!depPath) {
|
||||
return null;
|
||||
}
|
||||
return await this.addModuleAndDependencies(depPath);
|
||||
}))).filter((d): d is IModule => !!d);
|
||||
|
||||
const module: IModule = {
|
||||
id: this.mapper.getModuleId(path)!,
|
||||
dependencyRequests: parsedModule.dependencyRequests,
|
||||
dependencies,
|
||||
path,
|
||||
source: parsedModule.source,
|
||||
};
|
||||
return module;
|
||||
})();
|
||||
|
||||
this.modules.set(path, promise);
|
||||
return promise;
|
||||
}
|
||||
}
|
||||
|
||||
function arrayEquals<T>(a: T[], b: T[]): boolean {
|
||||
if (a.length !== b.length) {
|
||||
return false;
|
||||
}
|
||||
for (let i = 0; i < a.length; i++) {
|
||||
if (a[i] !== b[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const encoder = new TextEncoder();
|
||||
|
||||
function parseModule(content: string, path: string, mapper: SimpleModuleIdPathMapper): { source: Source; dependencyRequests: string[] } | undefined {
|
||||
const m = content.match(/define\((\[.*?\])/);
|
||||
if (!m) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const dependencyRequests = JSON.parse(m[1].replace(/'/g, '"')) as string[];
|
||||
|
||||
const sourceMapHeader = '//# sourceMappingURL=data:application/json;base64,';
|
||||
const idx = content.indexOf(sourceMapHeader);
|
||||
|
||||
let sourceMap: any = null;
|
||||
if (idx !== -1) {
|
||||
const sourceMapJsonStr = Buffer.from(content.substring(idx + sourceMapHeader.length), 'base64').toString('utf-8');
|
||||
sourceMap = JSON.parse(sourceMapJsonStr);
|
||||
content = content.substring(0, idx);
|
||||
}
|
||||
|
||||
content = content.replace('define([', `define("${mapper.getModuleId(path)}", [`);
|
||||
|
||||
const contentBuffer = Buffer.from(encoder.encode(content));
|
||||
const source = new Source(contentBuffer, sourceMap);
|
||||
|
||||
return { dependencyRequests, source };
|
||||
}
|
||||
|
||||
class SimpleModuleIdPathMapper {
|
||||
constructor(public readonly rootDir: string) { }
|
||||
|
||||
public getModuleId(path: string): string | null {
|
||||
if (!path.startsWith(this.rootDir) || !path.endsWith('.js')) {
|
||||
return null;
|
||||
}
|
||||
const moduleId = path.substring(this.rootDir.length + 1);
|
||||
|
||||
|
||||
return moduleId.replace(/\\/g, '/').substring(0, moduleId.length - 3);
|
||||
}
|
||||
|
||||
public resolveRequestToPath(request: string, requestingModulePath?: string): string | null {
|
||||
if (request.indexOf('css!') !== -1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (request.startsWith('.')) {
|
||||
return path.join(path.dirname(requestingModulePath!), request + '.js');
|
||||
} else {
|
||||
return path.join(this.rootDir, request + '.js');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface IModule {
|
||||
id: string;
|
||||
dependencyRequests: string[];
|
||||
dependencies: IModule[];
|
||||
path: string;
|
||||
source: Source;
|
||||
}
|
||||
|
||||
// #endregion
|
||||
|
||||
// #region SourceMapBuilder
|
||||
|
||||
// From https://stackoverflow.com/questions/29905373/how-to-create-sourcemaps-for-concatenated-files with modifications
|
||||
|
||||
class Source {
|
||||
// Ends with \n
|
||||
public readonly content: Buffer;
|
||||
public readonly sourceMap: SourceMap;
|
||||
public readonly sourceLines: number;
|
||||
|
||||
public readonly sourceMapMappings: Buffer;
|
||||
|
||||
|
||||
constructor(content: Buffer, sourceMap: SourceMap | undefined) {
|
||||
if (!sourceMap) {
|
||||
sourceMap = SourceMapBuilder.emptySourceMap;
|
||||
}
|
||||
|
||||
let sourceLines = countNL(content);
|
||||
if (content.length > 0 && content[content.length - 1] !== 10) {
|
||||
sourceLines++;
|
||||
content = Buffer.concat([content, Buffer.from([10])]);
|
||||
}
|
||||
|
||||
this.content = content;
|
||||
this.sourceMap = sourceMap;
|
||||
this.sourceLines = sourceLines;
|
||||
this.sourceMapMappings = typeof this.sourceMap.mappings === 'string'
|
||||
? Buffer.from(encoder.encode(sourceMap.mappings as string))
|
||||
: this.sourceMap.mappings;
|
||||
}
|
||||
}
|
||||
|
||||
class SourceMapBuilder {
|
||||
public static emptySourceMap: SourceMap = { version: 3, sources: [], mappings: Buffer.alloc(0) };
|
||||
|
||||
private readonly outputBuffer = new DynamicBuffer();
|
||||
private readonly sources: string[] = [];
|
||||
private readonly mappings = new DynamicBuffer();
|
||||
private lastSourceIndex = 0;
|
||||
private lastSourceLine = 0;
|
||||
private lastSourceCol = 0;
|
||||
|
||||
addLine(text: string) {
|
||||
this.outputBuffer.addString(text);
|
||||
this.outputBuffer.addByte(10);
|
||||
this.mappings.addByte(59); // ;
|
||||
}
|
||||
|
||||
addSource(source: Source) {
|
||||
const sourceMap = source.sourceMap;
|
||||
this.outputBuffer.addBuffer(source.content);
|
||||
|
||||
const sourceRemap: number[] = [];
|
||||
for (const v of sourceMap.sources) {
|
||||
let pos = this.sources.indexOf(v);
|
||||
if (pos < 0) {
|
||||
pos = this.sources.length;
|
||||
this.sources.push(v);
|
||||
}
|
||||
sourceRemap.push(pos);
|
||||
}
|
||||
let lastOutputCol = 0;
|
||||
|
||||
const inputMappings = source.sourceMapMappings;
|
||||
let outputLine = 0;
|
||||
let ip = 0;
|
||||
let inOutputCol = 0;
|
||||
let inSourceIndex = 0;
|
||||
let inSourceLine = 0;
|
||||
let inSourceCol = 0;
|
||||
let shift = 0;
|
||||
let value = 0;
|
||||
let valpos = 0;
|
||||
const commit = () => {
|
||||
if (valpos === 0) { return; }
|
||||
this.mappings.addVLQ(inOutputCol - lastOutputCol);
|
||||
lastOutputCol = inOutputCol;
|
||||
if (valpos === 1) {
|
||||
valpos = 0;
|
||||
return;
|
||||
}
|
||||
const outSourceIndex = sourceRemap[inSourceIndex];
|
||||
this.mappings.addVLQ(outSourceIndex - this.lastSourceIndex);
|
||||
this.lastSourceIndex = outSourceIndex;
|
||||
this.mappings.addVLQ(inSourceLine - this.lastSourceLine);
|
||||
this.lastSourceLine = inSourceLine;
|
||||
this.mappings.addVLQ(inSourceCol - this.lastSourceCol);
|
||||
this.lastSourceCol = inSourceCol;
|
||||
valpos = 0;
|
||||
};
|
||||
while (ip < inputMappings.length) {
|
||||
let b = inputMappings[ip++];
|
||||
if (b === 59) { // ;
|
||||
commit();
|
||||
this.mappings.addByte(59);
|
||||
inOutputCol = 0;
|
||||
lastOutputCol = 0;
|
||||
outputLine++;
|
||||
} else if (b === 44) { // ,
|
||||
commit();
|
||||
this.mappings.addByte(44);
|
||||
} else {
|
||||
b = charToInteger[b];
|
||||
if (b === 255) { throw new Error('Invalid sourceMap'); }
|
||||
value += (b & 31) << shift;
|
||||
if (b & 32) {
|
||||
shift += 5;
|
||||
} else {
|
||||
const shouldNegate = value & 1;
|
||||
value >>= 1;
|
||||
if (shouldNegate) { value = -value; }
|
||||
switch (valpos) {
|
||||
case 0: inOutputCol += value; break;
|
||||
case 1: inSourceIndex += value; break;
|
||||
case 2: inSourceLine += value; break;
|
||||
case 3: inSourceCol += value; break;
|
||||
}
|
||||
valpos++;
|
||||
value = shift = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
commit();
|
||||
while (outputLine < source.sourceLines) {
|
||||
this.mappings.addByte(59);
|
||||
outputLine++;
|
||||
}
|
||||
}
|
||||
|
||||
toContent(): Buffer {
|
||||
return this.outputBuffer.toBuffer();
|
||||
}
|
||||
|
||||
toSourceMap(sourceRoot?: string): SourceMap {
|
||||
return { version: 3, sourceRoot, sources: this.sources, mappings: this.mappings.toBuffer().toString() };
|
||||
}
|
||||
}
|
||||
|
||||
export interface SourceMap {
|
||||
version: number; // always 3
|
||||
file?: string;
|
||||
sourceRoot?: string;
|
||||
sources: string[];
|
||||
sourcesContent?: string[];
|
||||
names?: string[];
|
||||
mappings: string | Buffer;
|
||||
}
|
||||
|
||||
const charToInteger = Buffer.alloc(256);
|
||||
const integerToChar = Buffer.alloc(64);
|
||||
|
||||
charToInteger.fill(255);
|
||||
|
||||
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='.split('').forEach((char, i) => {
|
||||
charToInteger[char.charCodeAt(0)] = i;
|
||||
integerToChar[i] = char.charCodeAt(0);
|
||||
});
|
||||
|
||||
class DynamicBuffer {
|
||||
private buffer: Buffer;
|
||||
private size: number;
|
||||
|
||||
constructor() {
|
||||
this.buffer = Buffer.alloc(512);
|
||||
this.size = 0;
|
||||
}
|
||||
|
||||
ensureCapacity(capacity: number) {
|
||||
if (this.buffer.length >= capacity) {
|
||||
return;
|
||||
}
|
||||
const oldBuffer = this.buffer;
|
||||
this.buffer = Buffer.alloc(Math.max(oldBuffer.length * 2, capacity));
|
||||
oldBuffer.copy(this.buffer);
|
||||
}
|
||||
|
||||
addByte(b: number) {
|
||||
this.ensureCapacity(this.size + 1);
|
||||
this.buffer[this.size++] = b;
|
||||
}
|
||||
|
||||
addVLQ(num: number) {
|
||||
let clamped: number;
|
||||
|
||||
if (num < 0) {
|
||||
num = (-num << 1) | 1;
|
||||
} else {
|
||||
num <<= 1;
|
||||
}
|
||||
|
||||
do {
|
||||
clamped = num & 31;
|
||||
num >>= 5;
|
||||
|
||||
if (num > 0) {
|
||||
clamped |= 32;
|
||||
}
|
||||
|
||||
this.addByte(integerToChar[clamped]);
|
||||
} while (num > 0);
|
||||
}
|
||||
|
||||
addString(s: string) {
|
||||
const l = Buffer.byteLength(s);
|
||||
this.ensureCapacity(this.size + l);
|
||||
this.buffer.write(s, this.size);
|
||||
this.size += l;
|
||||
}
|
||||
|
||||
addBuffer(b: Buffer) {
|
||||
this.ensureCapacity(this.size + b.length);
|
||||
b.copy(this.buffer, this.size);
|
||||
this.size += b.length;
|
||||
}
|
||||
|
||||
toBuffer(): Buffer {
|
||||
return this.buffer.slice(0, this.size);
|
||||
}
|
||||
}
|
||||
|
||||
function countNL(b: Buffer): number {
|
||||
let res = 0;
|
||||
for (let i = 0; i < b.length; i++) {
|
||||
if (b[i] === 10) { res++; }
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// #endregion
|
||||
@@ -0,0 +1,17 @@
|
||||
@echo off
|
||||
setlocal
|
||||
|
||||
echo Runs tests against the current documentation in https://github.com/microsoft/vscode-docs/tree/vnext
|
||||
|
||||
pushd %~dp0\..
|
||||
|
||||
:: Endgame tests
|
||||
call .\scripts\test.bat --runGlob **\*.releaseTest.js %*
|
||||
if %errorlevel% neq 0 exit /b %errorlevel%
|
||||
|
||||
|
||||
rmdir /s /q %VSCODEUSERDATADIR%
|
||||
|
||||
popd
|
||||
|
||||
endlocal
|
||||
Executable
+21
@@ -0,0 +1,21 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
realpath() { [[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}"; }
|
||||
ROOT=$(dirname $(dirname $(realpath "$0")))
|
||||
VSCODEUSERDATADIR=`mktemp -d -t 'myuserdatadir'`
|
||||
else
|
||||
ROOT=$(dirname $(dirname $(readlink -f $0)))
|
||||
VSCODEUSERDATADIR=`mktemp -d 2>/dev/null`
|
||||
fi
|
||||
|
||||
cd $ROOT
|
||||
|
||||
echo "Runs tests against the current documentation in https://github.com/microsoft/vscode-docs/tree/vnext"
|
||||
|
||||
# Tests
|
||||
./scripts/test.sh --runGlob **/*.releaseTest.js "$@"
|
||||
|
||||
|
||||
rm -r $VSCODEUSERDATADIR
|
||||
@@ -0,0 +1,124 @@
|
||||
@echo off
|
||||
setlocal
|
||||
|
||||
pushd %~dp0\..
|
||||
|
||||
set VSCODEUSERDATADIR=%TEMP%\vscodeuserfolder-%RANDOM%-%TIME:~6,2%
|
||||
set VSCODECRASHDIR=%~dp0\..\.build\crashes
|
||||
set VSCODELOGSDIR=%~dp0\..\.build\logs\integration-tests
|
||||
|
||||
:: Figure out which Electron to use for running tests
|
||||
if "%INTEGRATION_TEST_ELECTRON_PATH%"=="" (
|
||||
chcp 65001
|
||||
set INTEGRATION_TEST_ELECTRON_PATH=.\scripts\code.bat
|
||||
set VSCODE_BUILD_BUILTIN_EXTENSIONS_SILENCE_PLEASE=1
|
||||
|
||||
echo Running integration tests out of sources.
|
||||
) else (
|
||||
set VSCODE_CLI=1
|
||||
set ELECTRON_ENABLE_LOGGING=1
|
||||
|
||||
echo Running integration tests with '%INTEGRATION_TEST_ELECTRON_PATH%' as build.
|
||||
)
|
||||
|
||||
echo Storing crash reports into '%VSCODECRASHDIR%'.
|
||||
echo Storing log files into '%VSCODELOGSDIR%'.
|
||||
|
||||
|
||||
:: Unit tests
|
||||
|
||||
echo.
|
||||
echo ### node.js integration tests
|
||||
call .\scripts\test.bat --runGlob **\*.integrationTest.js %*
|
||||
if %errorlevel% neq 0 exit /b %errorlevel%
|
||||
|
||||
|
||||
:: Tests in the extension host
|
||||
|
||||
set API_TESTS_EXTRA_ARGS=--disable-telemetry --skip-welcome --skip-release-notes --crash-reporter-directory=%VSCODECRASHDIR% --logsPath=%VSCODELOGSDIR% --no-cached-data --disable-updates --use-inmemory-secretstorage --disable-extensions --disable-workspace-trust --user-data-dir=%VSCODEUSERDATADIR%
|
||||
|
||||
echo.
|
||||
echo ### API tests (folder)
|
||||
call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\vscode-api-tests\testWorkspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=%~dp0\..\extensions\vscode-api-tests --extensionTestsPath=%~dp0\..\extensions\vscode-api-tests\out\singlefolder-tests %API_TESTS_EXTRA_ARGS%
|
||||
if %errorlevel% neq 0 exit /b %errorlevel%
|
||||
|
||||
echo.
|
||||
echo ### API tests (workspace)
|
||||
call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\vscode-api-tests\testworkspace.code-workspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=%~dp0\..\extensions\vscode-api-tests --extensionTestsPath=%~dp0\..\extensions\vscode-api-tests\out\workspace-tests %API_TESTS_EXTRA_ARGS%
|
||||
if %errorlevel% neq 0 exit /b %errorlevel%
|
||||
|
||||
echo.
|
||||
echo ### Colorize tests
|
||||
call npm run test-extension -- -l vscode-colorize-tests
|
||||
if %errorlevel% neq 0 exit /b %errorlevel%
|
||||
|
||||
echo.
|
||||
echo ### Terminal Suggest tests
|
||||
call npm run test-extension -- -l terminal-suggest --enable-proposed-api=vscode.vscode-api-tests
|
||||
if %errorlevel% neq 0 exit /b %errorlevel%
|
||||
|
||||
echo.
|
||||
echo ### TypeScript tests
|
||||
call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\typescript-language-features\test-workspace --extensionDevelopmentPath=%~dp0\..\extensions\typescript-language-features --extensionTestsPath=%~dp0\..\extensions\typescript-language-features\out\test\unit %API_TESTS_EXTRA_ARGS%
|
||||
if %errorlevel% neq 0 exit /b %errorlevel%
|
||||
|
||||
echo.
|
||||
echo ### Markdown tests
|
||||
call npm run test-extension -- -l markdown-language-features
|
||||
if %errorlevel% neq 0 exit /b %errorlevel%
|
||||
|
||||
echo.
|
||||
echo ### Emmet tests
|
||||
call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\emmet\test-workspace --extensionDevelopmentPath=%~dp0\..\extensions\emmet --extensionTestsPath=%~dp0\..\extensions\emmet\out\test %API_TESTS_EXTRA_ARGS%
|
||||
if %errorlevel% neq 0 exit /b %errorlevel%
|
||||
|
||||
echo.
|
||||
echo ### Git tests
|
||||
for /f "delims=" %%i in ('node -p "require('fs').realpathSync.native(require('os').tmpdir())"') do set TEMPDIR=%%i
|
||||
set GITWORKSPACE=%TEMPDIR%\git-%RANDOM%
|
||||
mkdir %GITWORKSPACE%
|
||||
call "%INTEGRATION_TEST_ELECTRON_PATH%" %GITWORKSPACE% --extensionDevelopmentPath=%~dp0\..\extensions\git --extensionTestsPath=%~dp0\..\extensions\git\out\test %API_TESTS_EXTRA_ARGS%
|
||||
if %errorlevel% neq 0 exit /b %errorlevel%
|
||||
|
||||
echo.
|
||||
echo ### Ipynb tests
|
||||
call npm run test-extension -- -l ipynb
|
||||
if %errorlevel% neq 0 exit /b %errorlevel%
|
||||
|
||||
echo.
|
||||
echo ### Notebook Output tests
|
||||
call npm run test-extension -- -l notebook-renderers
|
||||
if %errorlevel% neq 0 exit /b %errorlevel%
|
||||
|
||||
echo.
|
||||
echo ### Configuration editing tests
|
||||
set CFWORKSPACE=%TEMPDIR%\cf-%RANDOM%
|
||||
mkdir %CFWORKSPACE%
|
||||
call npm run test-extension -- -l configuration-editing
|
||||
if %errorlevel% neq 0 exit /b %errorlevel%
|
||||
|
||||
echo.
|
||||
echo ### GitHub Authentication tests
|
||||
call npm run test-extension -- -l github-authentication
|
||||
if %errorlevel% neq 0 exit /b %errorlevel%
|
||||
|
||||
:: Tests standalone (CommonJS)
|
||||
|
||||
echo.
|
||||
echo ### CSS tests
|
||||
call %~dp0\node-electron.bat %~dp0\..\extensions\css-language-features/server/test/index.js
|
||||
if %errorlevel% neq 0 exit /b %errorlevel%
|
||||
|
||||
echo.
|
||||
echo ### HTML tests
|
||||
call %~dp0\node-electron.bat %~dp0\..\extensions\html-language-features/server/test/index.js
|
||||
if %errorlevel% neq 0 exit /b %errorlevel%
|
||||
|
||||
|
||||
:: Cleanup
|
||||
|
||||
rmdir /s /q %VSCODEUSERDATADIR%
|
||||
|
||||
popd
|
||||
|
||||
endlocal
|
||||
Executable
+142
@@ -0,0 +1,142 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
realpath() { [[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}"; }
|
||||
ROOT=$(dirname $(dirname $(realpath "$0")))
|
||||
else
|
||||
ROOT=$(dirname $(dirname $(readlink -f $0)))
|
||||
# --disable-dev-shm-usage: when run on docker containers where size of /dev/shm
|
||||
# partition < 64MB which causes OOM failure for chromium compositor that uses the partition for shared memory
|
||||
LINUX_EXTRA_ARGS="--disable-dev-shm-usage"
|
||||
fi
|
||||
|
||||
VSCODEUSERDATADIR=`mktemp -d 2>/dev/null`
|
||||
VSCODECRASHDIR=$ROOT/.build/crashes
|
||||
VSCODELOGSDIR=$ROOT/.build/logs/integration-tests
|
||||
|
||||
cd $ROOT
|
||||
|
||||
# Figure out which Electron to use for running tests
|
||||
if [ -z "$INTEGRATION_TEST_ELECTRON_PATH" ]
|
||||
then
|
||||
INTEGRATION_TEST_ELECTRON_PATH="./scripts/code.sh"
|
||||
|
||||
echo "Running integration tests out of sources."
|
||||
else
|
||||
export VSCODE_CLI=1
|
||||
export ELECTRON_ENABLE_LOGGING=1
|
||||
|
||||
echo "Running integration tests with '$INTEGRATION_TEST_ELECTRON_PATH' as build."
|
||||
fi
|
||||
|
||||
echo "Storing crash reports into '$VSCODECRASHDIR'."
|
||||
echo "Storing log files into '$VSCODELOGSDIR'."
|
||||
|
||||
|
||||
# Unit tests
|
||||
|
||||
echo
|
||||
echo "### node.js integration tests"
|
||||
echo
|
||||
./scripts/test.sh --runGlob **/*.integrationTest.js "$@"
|
||||
|
||||
|
||||
# Tests in the extension host
|
||||
|
||||
API_TESTS_EXTRA_ARGS="--disable-telemetry --skip-welcome --skip-release-notes --crash-reporter-directory=$VSCODECRASHDIR --logsPath=$VSCODELOGSDIR --no-cached-data --disable-updates --use-inmemory-secretstorage --disable-extensions --disable-workspace-trust --user-data-dir=$VSCODEUSERDATADIR"
|
||||
|
||||
if [ -z "$INTEGRATION_TEST_APP_NAME" ]; then
|
||||
kill_app() { true; }
|
||||
else
|
||||
kill_app() { killall $INTEGRATION_TEST_APP_NAME || true; }
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "### API tests (folder)"
|
||||
echo
|
||||
"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_EXTRA_ARGS $ROOT/extensions/vscode-api-tests/testWorkspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out/singlefolder-tests $API_TESTS_EXTRA_ARGS
|
||||
kill_app
|
||||
|
||||
echo
|
||||
echo "### API tests (workspace)"
|
||||
echo
|
||||
"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_EXTRA_ARGS $ROOT/extensions/vscode-api-tests/testworkspace.code-workspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out/workspace-tests $API_TESTS_EXTRA_ARGS
|
||||
kill_app
|
||||
|
||||
echo
|
||||
echo "### Colorize tests"
|
||||
echo
|
||||
npm run test-extension -- -l vscode-colorize-tests
|
||||
kill_app
|
||||
|
||||
echo
|
||||
echo "### Terminal Suggest tests"
|
||||
echo
|
||||
npm run test-extension -- -l terminal-suggest --enable-proposed-api=vscode.vscode-api-tests
|
||||
kill_app
|
||||
|
||||
echo
|
||||
echo "### TypeScript tests"
|
||||
echo
|
||||
"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_EXTRA_ARGS $ROOT/extensions/typescript-language-features/test-workspace --extensionDevelopmentPath=$ROOT/extensions/typescript-language-features --extensionTestsPath=$ROOT/extensions/typescript-language-features/out/test/unit $API_TESTS_EXTRA_ARGS
|
||||
kill_app
|
||||
|
||||
echo
|
||||
echo "### Markdown tests"
|
||||
echo
|
||||
npm run test-extension -- -l markdown-language-features
|
||||
kill_app
|
||||
|
||||
echo
|
||||
echo "### Emmet tests"
|
||||
echo
|
||||
"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_EXTRA_ARGS $ROOT/extensions/emmet/test-workspace --extensionDevelopmentPath=$ROOT/extensions/emmet --extensionTestsPath=$ROOT/extensions/emmet/out/test $API_TESTS_EXTRA_ARGS
|
||||
kill_app
|
||||
|
||||
echo
|
||||
echo "### Git tests"
|
||||
echo
|
||||
"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_EXTRA_ARGS $(mktemp -d 2>/dev/null) --extensionDevelopmentPath=$ROOT/extensions/git --extensionTestsPath=$ROOT/extensions/git/out/test $API_TESTS_EXTRA_ARGS
|
||||
kill_app
|
||||
|
||||
echo
|
||||
echo "### Ipynb tests"
|
||||
echo
|
||||
npm run test-extension -- -l ipynb
|
||||
kill_app
|
||||
|
||||
echo
|
||||
echo "### Notebook Output tests"
|
||||
echo
|
||||
npm run test-extension -- -l notebook-renderers
|
||||
kill_app
|
||||
|
||||
echo
|
||||
echo "### Configuration editing tests"
|
||||
echo
|
||||
npm run test-extension -- -l configuration-editing
|
||||
kill_app
|
||||
|
||||
echo
|
||||
echo "### GitHub Authentication tests"
|
||||
echo
|
||||
npm run test-extension -- -l github-authentication
|
||||
kill_app
|
||||
|
||||
# Tests standalone (CommonJS)
|
||||
|
||||
echo
|
||||
echo "### CSS tests"
|
||||
echo
|
||||
cd $ROOT/extensions/css-language-features/server && $ROOT/scripts/node-electron.sh test/index.js
|
||||
|
||||
echo
|
||||
echo "### HTML tests"
|
||||
echo
|
||||
cd $ROOT/extensions/html-language-features/server && $ROOT/scripts/node-electron.sh test/index.js
|
||||
|
||||
|
||||
# Cleanup
|
||||
|
||||
rm -rf $VSCODEUSERDATADIR
|
||||
@@ -0,0 +1,117 @@
|
||||
@echo off
|
||||
setlocal
|
||||
|
||||
pushd %~dp0\..
|
||||
|
||||
IF "%~1" == "" (
|
||||
set AUTHORITY=vscode-remote://test+test/
|
||||
:: backward to forward slashed
|
||||
set EXT_PATH=%CD:\=/%/extensions
|
||||
|
||||
:: Download nodejs executable for remote
|
||||
call npm run gulp node
|
||||
) else (
|
||||
set AUTHORITY=%1
|
||||
set EXT_PATH=%2
|
||||
set VSCODEUSERDATADIR=%3
|
||||
)
|
||||
IF "%VSCODEUSERDATADIR%" == "" (
|
||||
set VSCODEUSERDATADIR=%TMP%\vscodeuserfolder-%RANDOM%-%TIME:~6,5%
|
||||
)
|
||||
|
||||
set REMOTE_EXT_PATH=%AUTHORITY%%EXT_PATH%
|
||||
set VSCODECRASHDIR=%~dp0\..\.build\crashes
|
||||
set VSCODELOGSDIR=%~dp0\..\.build\logs\integration-tests-remote
|
||||
set TESTRESOLVER_DATA_FOLDER=%TMP%\testresolverdatafolder-%RANDOM%-%TIME:~6,5%
|
||||
set TESTRESOLVER_LOGS_FOLDER=%VSCODELOGSDIR%\server
|
||||
|
||||
if "%VSCODE_REMOTE_SERVER_PATH%"=="" (
|
||||
echo Using remote server out of sources for integration tests
|
||||
) else (
|
||||
set TESTRESOLVER_INSTALL_BUILTIN_EXTENSION=ms-vscode.vscode-smoketest-check
|
||||
echo Using '%VSCODE_REMOTE_SERVER_PATH%' as server path
|
||||
)
|
||||
|
||||
:: Figure out which Electron to use for running tests
|
||||
if "%INTEGRATION_TEST_ELECTRON_PATH%"=="" (
|
||||
chcp 65001
|
||||
set INTEGRATION_TEST_ELECTRON_PATH=.\scripts\code.bat
|
||||
set API_TESTS_EXTRA_ARGS_BUILT=
|
||||
|
||||
echo Running integration tests out of sources.
|
||||
) else (
|
||||
set VSCODE_CLI=1
|
||||
set ELECTRON_ENABLE_LOGGING=1
|
||||
|
||||
:: Extra arguments only when running against a built version
|
||||
set API_TESTS_EXTRA_ARGS_BUILT=--extensions-dir=%EXT_PATH% --enable-proposed-api=vscode.vscode-test-resolver --enable-proposed-api=vscode.vscode-api-tests
|
||||
|
||||
echo Using %INTEGRATION_TEST_ELECTRON_PATH% as Electron path
|
||||
)
|
||||
|
||||
echo Storing crash reports into '%VSCODECRASHDIR%'
|
||||
echo Storing log files into '%VSCODELOGSDIR%'
|
||||
|
||||
|
||||
:: Tests in the extension host
|
||||
|
||||
set API_TESTS_EXTRA_ARGS=--disable-telemetry --skip-welcome --skip-release-notes --crash-reporter-directory=%VSCODECRASHDIR% --logsPath=%VSCODELOGSDIR% --no-cached-data --disable-updates --use-inmemory-secretstorage --disable-inspect --disable-workspace-trust --user-data-dir=%VSCODEUSERDATADIR%
|
||||
|
||||
echo.
|
||||
echo ### API tests (folder)
|
||||
call "%INTEGRATION_TEST_ELECTRON_PATH%" --folder-uri=%REMOTE_EXT_PATH%/vscode-api-tests/testWorkspace --extensionDevelopmentPath=%REMOTE_EXT_PATH%/vscode-api-tests --extensionTestsPath=%REMOTE_EXT_PATH%/vscode-api-tests/out/singlefolder-tests %API_TESTS_EXTRA_ARGS% %API_TESTS_EXTRA_ARGS_BUILT%
|
||||
if %errorlevel% neq 0 exit /b %errorlevel%
|
||||
|
||||
echo.
|
||||
echo ### API tests (workspace)
|
||||
call "%INTEGRATION_TEST_ELECTRON_PATH%" --file-uri=%REMOTE_EXT_PATH%/vscode-api-tests/testworkspace.code-workspace --extensionDevelopmentPath=%REMOTE_EXT_PATH%/vscode-api-tests --extensionTestsPath=%REMOTE_EXT_PATH%/vscode-api-tests/out/workspace-tests %API_TESTS_EXTRA_ARGS% %API_TESTS_EXTRA_ARGS_BUILT%
|
||||
if %errorlevel% neq 0 exit /b %errorlevel%
|
||||
|
||||
echo.
|
||||
echo ### TypeScript tests
|
||||
call "%INTEGRATION_TEST_ELECTRON_PATH%" --folder-uri=%REMOTE_EXT_PATH%/typescript-language-features/test-workspace --extensionDevelopmentPath=%REMOTE_EXT_PATH%/typescript-language-features --extensionTestsPath=%REMOTE_EXT_PATH%/typescript-language-features\out\test\unit %API_TESTS_EXTRA_ARGS% %API_TESTS_EXTRA_ARGS_BUILT%
|
||||
if %errorlevel% neq 0 exit /b %errorlevel%
|
||||
|
||||
echo.
|
||||
echo ### Markdown tests
|
||||
call "%INTEGRATION_TEST_ELECTRON_PATH%" --folder-uri=%REMOTE_EXT_PATH%/markdown-language-features/test-workspace --extensionDevelopmentPath=%REMOTE_EXT_PATH%/markdown-language-features --extensionTestsPath=%REMOTE_EXT_PATH%/markdown-language-features/out/test %API_TESTS_EXTRA_ARGS% %API_TESTS_EXTRA_ARGS_BUILT%
|
||||
if %errorlevel% neq 0 exit /b %errorlevel%
|
||||
|
||||
echo.
|
||||
echo ### Emmet tests
|
||||
call "%INTEGRATION_TEST_ELECTRON_PATH%" --folder-uri=%REMOTE_EXT_PATH%/emmet/test-workspace --extensionDevelopmentPath=%REMOTE_EXT_PATH%/emmet --extensionTestsPath=%REMOTE_EXT_PATH%/emmet/out/test %API_TESTS_EXTRA_ARGS% %API_TESTS_EXTRA_ARGS_BUILT%
|
||||
if %errorlevel% neq 0 exit /b %errorlevel%
|
||||
|
||||
echo.
|
||||
echo ### Git tests
|
||||
for /f "delims=" %%i in ('node -p "require('fs').realpathSync.native(require('os').tmpdir())"') do set TEMPDIR=%%i
|
||||
set GITWORKSPACE=%TEMPDIR%\git-%RANDOM%
|
||||
mkdir %GITWORKSPACE%
|
||||
call "%INTEGRATION_TEST_ELECTRON_PATH%" --folder-uri=%AUTHORITY%%GITWORKSPACE% --extensionDevelopmentPath=%REMOTE_EXT_PATH%/git --extensionTestsPath=%REMOTE_EXT_PATH%/git/out/test %API_TESTS_EXTRA_ARGS% %API_TESTS_EXTRA_ARGS_BUILT%
|
||||
if %errorlevel% neq 0 exit /b %errorlevel%
|
||||
|
||||
echo.
|
||||
echo ### Ipynb tests
|
||||
set IPYNBWORKSPACE=%TEMPDIR%\ipynb-%RANDOM%
|
||||
mkdir %IPYNBWORKSPACE%
|
||||
call "%INTEGRATION_TEST_ELECTRON_PATH%" --folder-uri=%AUTHORITY%%IPYNBWORKSPACE% --extensionDevelopmentPath=%REMOTE_EXT_PATH%/ipynb --extensionTestsPath=%REMOTE_EXT_PATH%/ipynb/out/test %API_TESTS_EXTRA_ARGS% %API_TESTS_EXTRA_ARGS_BUILT%
|
||||
if %errorlevel% neq 0 exit /b %errorlevel%
|
||||
|
||||
echo.
|
||||
echo ### Configuration editing tests
|
||||
set CFWORKSPACE=%TEMPDIR%\cf-%RANDOM%
|
||||
mkdir %CFWORKSPACE%
|
||||
call "%INTEGRATION_TEST_ELECTRON_PATH%" --folder-uri=%AUTHORITY%/%CFWORKSPACE% --extensionDevelopmentPath=%REMOTE_EXT_PATH%/configuration-editing --extensionTestsPath=%REMOTE_EXT_PATH%/configuration-editing/out/test %API_TESTS_EXTRA_ARGS% %API_TESTS_EXTRA_ARGS_BUILT%
|
||||
if %errorlevel% neq 0 exit /b %errorlevel%
|
||||
|
||||
:: Cleanup
|
||||
|
||||
IF "%3" == "" (
|
||||
rmdir /s /q %VSCODEUSERDATADIR%
|
||||
)
|
||||
|
||||
rmdir /s /q %TESTRESOLVER_DATA_FOLDER%
|
||||
|
||||
popd
|
||||
|
||||
endlocal
|
||||
Executable
+133
@@ -0,0 +1,133 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
realpath() { [[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}"; }
|
||||
ROOT=$(dirname $(dirname $(realpath "$0")))
|
||||
else
|
||||
ROOT=$(dirname $(dirname $(readlink -f $0)))
|
||||
# --disable-dev-shm-usage: when run on docker containers where size of /dev/shm
|
||||
# partition < 64MB which causes OOM failure for chromium compositor that uses the partition for shared memory
|
||||
LINUX_EXTRA_ARGS="--disable-dev-shm-usage"
|
||||
fi
|
||||
|
||||
VSCODEUSERDATADIR=`mktemp -d 2>/dev/null`
|
||||
VSCODECRASHDIR=$ROOT/.build/crashes
|
||||
VSCODELOGSDIR=$ROOT/.build/logs/integration-tests-remote
|
||||
TESTRESOLVER_DATA_FOLDER=`mktemp -d 2>/dev/null`
|
||||
|
||||
cd $ROOT
|
||||
|
||||
if [[ "$1" == "" ]]; then
|
||||
AUTHORITY=vscode-remote://test+test
|
||||
EXT_PATH=$ROOT/extensions
|
||||
# Load remote node
|
||||
npm run gulp node
|
||||
else
|
||||
AUTHORITY=$1
|
||||
EXT_PATH=$2
|
||||
VSCODEUSERDATADIR=${3:-$VSCODEUSERDATADIR}
|
||||
fi
|
||||
|
||||
export REMOTE_VSCODE=$AUTHORITY$EXT_PATH
|
||||
|
||||
# Figure out which Electron to use for running tests
|
||||
if [ -z "$INTEGRATION_TEST_ELECTRON_PATH" ]
|
||||
then
|
||||
INTEGRATION_TEST_ELECTRON_PATH="./scripts/code.sh"
|
||||
|
||||
# No extra arguments when running out of sources
|
||||
EXTRA_INTEGRATION_TEST_ARGUMENTS=""
|
||||
|
||||
echo "Running remote integration tests out of sources."
|
||||
else
|
||||
export VSCODE_CLI=1
|
||||
export ELECTRON_ENABLE_LOGGING=1
|
||||
|
||||
# Running from a build, we need to enable the vscode-test-resolver extension
|
||||
EXTRA_INTEGRATION_TEST_ARGUMENTS="--extensions-dir=$EXT_PATH --enable-proposed-api=vscode.vscode-test-resolver --enable-proposed-api=vscode.vscode-api-tests"
|
||||
|
||||
echo "Running remote integration tests with $INTEGRATION_TEST_ELECTRON_PATH as build."
|
||||
fi
|
||||
|
||||
export TESTRESOLVER_DATA_FOLDER=$TESTRESOLVER_DATA_FOLDER
|
||||
export TESTRESOLVER_LOGS_FOLDER=$VSCODELOGSDIR/server
|
||||
|
||||
# Figure out which remote server to use for running tests
|
||||
if [ -z "$VSCODE_REMOTE_SERVER_PATH" ]
|
||||
then
|
||||
echo "Using remote server out of sources for integration tests"
|
||||
else
|
||||
echo "Using $VSCODE_REMOTE_SERVER_PATH as server path for integration tests"
|
||||
export TESTRESOLVER_INSTALL_BUILTIN_EXTENSION='ms-vscode.vscode-smoketest-check'
|
||||
fi
|
||||
|
||||
if [ -z "$INTEGRATION_TEST_APP_NAME" ]; then
|
||||
kill_app() { true; }
|
||||
else
|
||||
kill_app() { killall $INTEGRATION_TEST_APP_NAME || true; }
|
||||
fi
|
||||
|
||||
API_TESTS_EXTRA_ARGS="--disable-telemetry --skip-welcome --skip-release-notes --crash-reporter-directory=$VSCODECRASHDIR --logsPath=$VSCODELOGSDIR --no-cached-data --disable-updates --use-inmemory-secretstorage --disable-workspace-trust --user-data-dir=$VSCODEUSERDATADIR"
|
||||
|
||||
echo "Storing crash reports into '$VSCODECRASHDIR'."
|
||||
echo "Storing log files into '$VSCODELOGSDIR'."
|
||||
|
||||
|
||||
# Tests in the extension host
|
||||
|
||||
echo
|
||||
echo "### API tests (folder)"
|
||||
echo
|
||||
"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_EXTRA_ARGS --folder-uri=$REMOTE_VSCODE/vscode-api-tests/testWorkspace --extensionDevelopmentPath=$REMOTE_VSCODE/vscode-api-tests --extensionTestsPath=$REMOTE_VSCODE/vscode-api-tests/out/singlefolder-tests $API_TESTS_EXTRA_ARGS $EXTRA_INTEGRATION_TEST_ARGUMENTS
|
||||
kill_app
|
||||
|
||||
echo
|
||||
echo "### API tests (workspace)"
|
||||
echo
|
||||
"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_EXTRA_ARGS --file-uri=$REMOTE_VSCODE/vscode-api-tests/testworkspace.code-workspace --extensionDevelopmentPath=$REMOTE_VSCODE/vscode-api-tests --extensionTestsPath=$REMOTE_VSCODE/vscode-api-tests/out/workspace-tests $API_TESTS_EXTRA_ARGS $EXTRA_INTEGRATION_TEST_ARGUMENTS
|
||||
kill_app
|
||||
|
||||
echo
|
||||
echo "### TypeScript tests"
|
||||
echo
|
||||
"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_EXTRA_ARGS --folder-uri=$REMOTE_VSCODE/typescript-language-features/test-workspace --extensionDevelopmentPath=$REMOTE_VSCODE/typescript-language-features --extensionTestsPath=$REMOTE_VSCODE/typescript-language-features/out/test/unit $API_TESTS_EXTRA_ARGS $EXTRA_INTEGRATION_TEST_ARGUMENTS
|
||||
kill_app
|
||||
|
||||
echo
|
||||
echo "### Markdown tests"
|
||||
echo
|
||||
"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_EXTRA_ARGS --folder-uri=$REMOTE_VSCODE/markdown-language-features/test-workspace --extensionDevelopmentPath=$REMOTE_VSCODE/markdown-language-features --extensionTestsPath=$REMOTE_VSCODE/markdown-language-features/out/test $API_TESTS_EXTRA_ARGS $EXTRA_INTEGRATION_TEST_ARGUMENTS
|
||||
kill_app
|
||||
|
||||
echo
|
||||
echo "### Emmet tests"
|
||||
echo
|
||||
"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_EXTRA_ARGS --folder-uri=$REMOTE_VSCODE/emmet/test-workspace --extensionDevelopmentPath=$REMOTE_VSCODE/emmet --extensionTestsPath=$REMOTE_VSCODE/emmet/out/test $API_TESTS_EXTRA_ARGS $EXTRA_INTEGRATION_TEST_ARGUMENTS
|
||||
kill_app
|
||||
|
||||
echo
|
||||
echo "### Git tests"
|
||||
echo
|
||||
"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_EXTRA_ARGS --folder-uri=$AUTHORITY$(mktemp -d 2>/dev/null) --extensionDevelopmentPath=$REMOTE_VSCODE/git --extensionTestsPath=$REMOTE_VSCODE/git/out/test $API_TESTS_EXTRA_ARGS $EXTRA_INTEGRATION_TEST_ARGUMENTS
|
||||
kill_app
|
||||
|
||||
echo
|
||||
echo "### Ipynb tests"
|
||||
echo
|
||||
"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_EXTRA_ARGS --folder-uri=$AUTHORITY$(mktemp -d 2>/dev/null) --extensionDevelopmentPath=$REMOTE_VSCODE/ipynb --extensionTestsPath=$REMOTE_VSCODE/ipynb/out/test $API_TESTS_EXTRA_ARGS $EXTRA_INTEGRATION_TEST_ARGUMENTS
|
||||
kill_app
|
||||
|
||||
echo
|
||||
echo "### Configuration editing tests"
|
||||
echo
|
||||
"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_EXTRA_ARGS --folder-uri=$AUTHORITY$(mktemp -d 2>/dev/null) --extensionDevelopmentPath=$REMOTE_VSCODE/configuration-editing --extensionTestsPath=$REMOTE_VSCODE/configuration-editing/out/test $API_TESTS_EXTRA_ARGS $EXTRA_INTEGRATION_TEST_ARGUMENTS
|
||||
kill_app
|
||||
|
||||
# Cleanup
|
||||
|
||||
if [[ "$3" == "" ]]; then
|
||||
rm -rf $VSCODEUSERDATADIR
|
||||
fi
|
||||
|
||||
rm -rf $TESTRESOLVER_DATA_FOLDER
|
||||
@@ -0,0 +1,87 @@
|
||||
@echo off
|
||||
setlocal
|
||||
|
||||
pushd %~dp0\..
|
||||
|
||||
IF "%~1" == "" (
|
||||
set AUTHORITY=vscode-remote://test+test/
|
||||
:: backward to forward slashed
|
||||
set EXT_PATH=%CD:\=/%/extensions
|
||||
|
||||
:: Download nodejs executable for remote
|
||||
call npm run gulp node
|
||||
) else (
|
||||
set AUTHORITY=%1
|
||||
set EXT_PATH=%2
|
||||
)
|
||||
|
||||
set REMOTE_VSCODE=%AUTHORITY%%EXT_PATH%
|
||||
|
||||
if "%VSCODE_REMOTE_SERVER_PATH%"=="" (
|
||||
chcp 65001
|
||||
|
||||
echo Using remote server out of sources for integration web tests
|
||||
) else (
|
||||
echo Using '%VSCODE_REMOTE_SERVER_PATH%' as server path for web integration tests
|
||||
)
|
||||
|
||||
if not exist ".\test\integration\browser\out\index.js" (
|
||||
pushd test\integration\browser
|
||||
call npm run compile
|
||||
popd
|
||||
call npm run playwright-install
|
||||
)
|
||||
|
||||
|
||||
:: Tests in the extension host
|
||||
|
||||
echo.
|
||||
echo ### API tests (folder)
|
||||
call node .\test\integration\browser\out\index.js --workspacePath=.\extensions\vscode-api-tests\testWorkspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=.\extensions\vscode-api-tests --extensionTestsPath=.\extensions\vscode-api-tests\out\singlefolder-tests %*
|
||||
if %errorlevel% neq 0 exit /b %errorlevel%
|
||||
|
||||
echo.
|
||||
echo ### API tests (workspace)
|
||||
call node .\test\integration\browser\out\index.js --workspacePath=.\extensions\vscode-api-tests\testworkspace.code-workspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=.\extensions\vscode-api-tests --extensionTestsPath=.\extensions\vscode-api-tests\out\workspace-tests %*
|
||||
if %errorlevel% neq 0 exit /b %errorlevel%
|
||||
|
||||
echo.
|
||||
echo ### TypeScript tests
|
||||
call node .\test\integration\browser\out\index.js --workspacePath=.\extensions\typescript-language-features\test-workspace --extensionDevelopmentPath=.\extensions\typescript-language-features --extensionTestsPath=.\extensions\typescript-language-features\out\test\unit %*
|
||||
if %errorlevel% neq 0 exit /b %errorlevel%
|
||||
|
||||
echo.
|
||||
echo ### Markdown tests
|
||||
call node .\test\integration\browser\out\index.js --workspacePath=.\extensions\markdown-language-features\test-workspace --extensionDevelopmentPath=.\extensions\markdown-language-features --extensionTestsPath=.\extensions\markdown-language-features\out\test %*
|
||||
if %errorlevel% neq 0 exit /b %errorlevel%
|
||||
|
||||
echo.
|
||||
echo ### Emmet tests
|
||||
call node .\test\integration\browser\out\index.js --workspacePath=.\extensions\emmet\test-workspace --extensionDevelopmentPath=.\extensions\emmet --extensionTestsPath=.\extensions\emmet\out\test %*
|
||||
if %errorlevel% neq 0 exit /b %errorlevel%
|
||||
|
||||
echo.
|
||||
echo ### Git tests
|
||||
for /f "delims=" %%i in ('node -p "require('fs').realpathSync.native(require('os').tmpdir())"') do set TEMPDIR=%%i
|
||||
set GITWORKSPACE=%TEMPDIR%\git-%RANDOM%
|
||||
mkdir %GITWORKSPACE%
|
||||
call node .\test\integration\browser\out\index.js --workspacePath=%GITWORKSPACE% --extensionDevelopmentPath=.\extensions\git --extensionTestsPath=.\extensions\git\out\test %*
|
||||
if %errorlevel% neq 0 exit /b %errorlevel%
|
||||
|
||||
echo.
|
||||
echo ### Ipynb tests
|
||||
set IPYNBWORKSPACE=%TEMPDIR%\ipynb-%RANDOM%
|
||||
mkdir %IPYNBWORKSPACE%
|
||||
call node .\test\integration\browser\out\index.js --workspacePath=%IPYNBWORKSPACE% --extensionDevelopmentPath=.\extensions\ipynb --extensionTestsPath=.\extensions\ipynb\out\test %*
|
||||
if %errorlevel% neq 0 exit /b %errorlevel%
|
||||
|
||||
echo.
|
||||
echo ### Configuration editing tests
|
||||
set CFWORKSPACE=%TEMPDIR%\git-%RANDOM%
|
||||
mkdir %CFWORKSPACE%
|
||||
call node .\test\integration\browser\out\index.js --workspacePath=%CFWORKSPACE% --extensionDevelopmentPath=.\extensions\configuration-editing --extensionTestsPath=.\extensions\configuration-editing\out\test %*
|
||||
if %errorlevel% neq 0 exit /b %errorlevel%
|
||||
|
||||
popd
|
||||
|
||||
endlocal
|
||||
Executable
+67
@@ -0,0 +1,67 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
realpath() { [[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}"; }
|
||||
ROOT=$(dirname $(dirname $(realpath "$0")))
|
||||
else
|
||||
ROOT=$(dirname $(dirname $(readlink -f $0)))
|
||||
fi
|
||||
|
||||
cd $ROOT
|
||||
|
||||
if [ -z "$VSCODE_REMOTE_SERVER_PATH" ]
|
||||
then
|
||||
echo "Using remote server out of sources for integration web tests"
|
||||
else
|
||||
echo "Using $VSCODE_REMOTE_SERVER_PATH as server path for web integration tests"
|
||||
fi
|
||||
|
||||
if [ ! -e 'test/integration/browser/out/index.js' ];then
|
||||
(cd test/integration/browser && npm run compile)
|
||||
npm run playwright-install
|
||||
fi
|
||||
|
||||
|
||||
# Tests in the extension host
|
||||
|
||||
echo
|
||||
echo "### API tests (folder)"
|
||||
echo
|
||||
node test/integration/browser/out/index.js --workspacePath $ROOT/extensions/vscode-api-tests/testWorkspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out/singlefolder-tests "$@"
|
||||
|
||||
echo
|
||||
echo "### API tests (workspace)"
|
||||
echo
|
||||
node test/integration/browser/out/index.js --workspacePath $ROOT/extensions/vscode-api-tests/testworkspace.code-workspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out/workspace-tests "$@"
|
||||
|
||||
echo
|
||||
echo "### TypeScript tests"
|
||||
echo
|
||||
node test/integration/browser/out/index.js --workspacePath $ROOT/extensions/typescript-language-features/test-workspace --extensionDevelopmentPath=$ROOT/extensions/typescript-language-features --extensionTestsPath=$ROOT/extensions/typescript-language-features/out/test/unit "$@"
|
||||
|
||||
echo
|
||||
echo "### Markdown tests"
|
||||
echo
|
||||
node test/integration/browser/out/index.js --workspacePath $ROOT/extensions/markdown-language-features/test-workspace --extensionDevelopmentPath=$ROOT/extensions/markdown-language-features --extensionTestsPath=$ROOT/extensions/markdown-language-features/out/test "$@"
|
||||
|
||||
echo
|
||||
echo "### Emmet tests"
|
||||
echo
|
||||
node test/integration/browser/out/index.js --workspacePath $ROOT/extensions/emmet/test-workspace --extensionDevelopmentPath=$ROOT/extensions/emmet --extensionTestsPath=$ROOT/extensions/emmet/out/test "$@"
|
||||
|
||||
echo
|
||||
echo "### Git tests"
|
||||
echo
|
||||
node test/integration/browser/out/index.js --workspacePath $(mktemp -d 2>/dev/null) --extensionDevelopmentPath=$ROOT/extensions/git --extensionTestsPath=$ROOT/extensions/git/out/test "$@"
|
||||
|
||||
echo
|
||||
echo "### Ipynb tests"
|
||||
echo
|
||||
node test/integration/browser/out/index.js --workspacePath $(mktemp -d 2>/dev/null) --extensionDevelopmentPath=$ROOT/extensions/ipynb --extensionTestsPath=$ROOT/extensions/ipynb/out/test "$@"
|
||||
|
||||
echo
|
||||
echo "### Configuration editing tests"
|
||||
echo
|
||||
node test/integration/browser/out/index.js --workspacePath $(mktemp -d 2>/dev/null) --extensionDevelopmentPath=$ROOT/extensions/configuration-editing --extensionTestsPath=$ROOT/extensions/configuration-editing/out/test "$@"
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
@echo off
|
||||
setlocal
|
||||
|
||||
set ELECTRON_RUN_AS_NODE=
|
||||
|
||||
pushd %~dp0\..
|
||||
|
||||
:: Get Code.exe location
|
||||
for /f "tokens=2 delims=:," %%a in ('findstr /R /C:"\"nameShort\":.*" product.json') do set NAMESHORT=%%~a
|
||||
set NAMESHORT=%NAMESHORT: "=%
|
||||
set NAMESHORT=%NAMESHORT:"=%.exe
|
||||
set CODE=".build\electron\%NAMESHORT%"
|
||||
|
||||
:: Download Electron if needed
|
||||
call node build\lib\electron.js
|
||||
if %errorlevel% neq 0 node .\node_modules\gulp\bin\gulp.js electron
|
||||
|
||||
:: Run tests
|
||||
set ELECTRON_ENABLE_LOGGING=1
|
||||
%CODE% .\test\unit\electron\index.js --crash-reporter-directory=%~dp0\..\.build\crashes %*
|
||||
|
||||
popd
|
||||
|
||||
endlocal
|
||||
|
||||
:: app.exit(0) is exiting with code 255 in Electron 1.7.4.
|
||||
:: See https://github.com/microsoft/vscode/issues/28582
|
||||
echo errorlevel: %errorlevel%
|
||||
if %errorlevel% == 255 set errorlevel=0
|
||||
|
||||
exit /b %errorlevel%
|
||||
Executable
+43
@@ -0,0 +1,43 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
realpath() { [[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}"; }
|
||||
ROOT=$(dirname $(dirname $(realpath "$0")))
|
||||
else
|
||||
ROOT=$(dirname $(dirname $(readlink -f $0)))
|
||||
# --disable-dev-shm-usage: when run on docker containers where size of /dev/shm
|
||||
# partition < 64MB which causes OOM failure for chromium compositor that uses the partition for shared memory
|
||||
LINUX_EXTRA_ARGS="--disable-dev-shm-usage"
|
||||
fi
|
||||
|
||||
cd $ROOT
|
||||
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
NAME=`node -p "require('./product.json').nameLong"`
|
||||
CODE="./.build/electron/$NAME.app/Contents/MacOS/Electron"
|
||||
else
|
||||
NAME=`node -p "require('./product.json').applicationName"`
|
||||
CODE=".build/electron/$NAME"
|
||||
fi
|
||||
|
||||
VSCODECRASHDIR=$ROOT/.build/crashes
|
||||
|
||||
# Node modules
|
||||
test -d node_modules || npm i
|
||||
|
||||
# Get electron
|
||||
npm run electron
|
||||
|
||||
# Unit Tests
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
cd $ROOT ; ulimit -n 4096 ; \
|
||||
ELECTRON_ENABLE_LOGGING=1 \
|
||||
"$CODE" \
|
||||
test/unit/electron/index.js --crash-reporter-directory=$VSCODECRASHDIR "$@"
|
||||
else
|
||||
cd $ROOT ; \
|
||||
ELECTRON_ENABLE_LOGGING=1 \
|
||||
"$CODE" \
|
||||
test/unit/electron/index.js --crash-reporter-directory=$VSCODECRASHDIR $LINUX_EXTRA_ARGS "$@"
|
||||
fi
|
||||
@@ -0,0 +1,34 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Symlinks ./node_modules/xterm to provided $XtermFolder.
|
||||
#>
|
||||
|
||||
Param(
|
||||
[Parameter(Mandatory=$True)]
|
||||
$XtermFolder
|
||||
)
|
||||
|
||||
$TargetFolder = "./node_modules/@xterm/xterm"
|
||||
|
||||
if (Test-Path $TargetFolder -PathType Container)
|
||||
{
|
||||
Write-Host -ForegroundColor Green ":: Deleting $TargetFolder`n"
|
||||
Remove-Item -Path $TargetFolder
|
||||
}
|
||||
|
||||
if (Test-Path $XtermFolder -PathType Container)
|
||||
{
|
||||
Write-Host -ForegroundColor Green "`n:: Creating symlink $TargetFolder -> $XtermFolder`n"
|
||||
New-Item -Path $TargetFolder -ItemType SymbolicLink -Value $XtermFolder
|
||||
|
||||
Write-Host -ForegroundColor Green "`n:: Packaging xterm.js`n"
|
||||
Set-Location $TargetFolder
|
||||
yarn package -- --mode development
|
||||
Set-Location -
|
||||
|
||||
Write-Host -ForegroundColor Green "`n:: Finished! To watch changes, open the VS Code terminal in the xterm.js repo and run:`n`n yarn package -- --mode development --watch"
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Error -ForegroundColor Red "`n:: $XtermFolder is not a valid folder"
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
const cp = require('child_process');
|
||||
const path = require('path');
|
||||
|
||||
const moduleNames = [
|
||||
'@xterm/xterm',
|
||||
'@xterm/addon-clipboard',
|
||||
'@xterm/addon-image',
|
||||
'@xterm/addon-ligatures',
|
||||
'@xterm/addon-progress',
|
||||
'@xterm/addon-search',
|
||||
'@xterm/addon-serialize',
|
||||
'@xterm/addon-unicode11',
|
||||
'@xterm/addon-webgl',
|
||||
];
|
||||
|
||||
const backendOnlyModuleNames = [
|
||||
'@xterm/headless'
|
||||
];
|
||||
|
||||
const vscodeDir = process.argv.length >= 3 ? process.argv[2] : process.cwd();
|
||||
if (path.basename(vscodeDir) !== 'vscode') {
|
||||
console.error('The cwd is not named "vscode"');
|
||||
return;
|
||||
}
|
||||
|
||||
function getLatestModuleVersion(moduleName) {
|
||||
return new Promise((resolve, reject) => {
|
||||
cp.exec(`npm view ${moduleName} versions --json`, { cwd: vscodeDir }, (err, stdout, stderr) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
}
|
||||
let versions = JSON.parse(stdout);
|
||||
// Fix format if there is only a single version published
|
||||
if (typeof versions === 'string') {
|
||||
versions = [versions];
|
||||
}
|
||||
resolve(versions[versions.length - 1]);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function update() {
|
||||
console.log('Fetching latest versions');
|
||||
const allModules = moduleNames.concat(backendOnlyModuleNames);
|
||||
const versionPromises = [];
|
||||
for (const m of allModules) {
|
||||
versionPromises.push(getLatestModuleVersion(m));
|
||||
}
|
||||
const latestVersionsArray = await Promise.all(versionPromises);
|
||||
const latestVersions = {};
|
||||
for (const [i, v] of latestVersionsArray.entries()) {
|
||||
latestVersions[allModules[i]] = v;
|
||||
}
|
||||
|
||||
console.log('Detected versions:');
|
||||
for (const m of moduleNames.concat(backendOnlyModuleNames)) {
|
||||
console.log(` ${m}@${latestVersions[m]}`);
|
||||
}
|
||||
|
||||
const pkg = require(path.join(vscodeDir, 'package.json'));
|
||||
|
||||
const modulesWithVersion = [];
|
||||
for (const m of moduleNames) {
|
||||
const moduleWithVersion = `${m}@${latestVersions[m]}`;
|
||||
if (pkg.dependencies[m] === latestVersions[m]) {
|
||||
console.log(`Skipping ${moduleWithVersion}, already up to date`);
|
||||
continue;
|
||||
}
|
||||
modulesWithVersion.push(moduleWithVersion);
|
||||
}
|
||||
|
||||
if (modulesWithVersion.length > 0) {
|
||||
for (const cwd of [vscodeDir, path.join(vscodeDir, 'remote'), path.join(vscodeDir, 'remote/web')]) {
|
||||
console.log(`${path.join(cwd, 'package.json')}: Updating\n ${modulesWithVersion.join('\n ')}`);
|
||||
cp.execSync(`npm install ${modulesWithVersion.join(' ')}`, { cwd });
|
||||
}
|
||||
}
|
||||
|
||||
const backendOnlyModulesWithVersion = [];
|
||||
for (const m of backendOnlyModuleNames) {
|
||||
const moduleWithVersion = `${m}@${latestVersions[m]}`;
|
||||
if (pkg.dependencies[m] === latestVersions[m]) {
|
||||
console.log(`Skipping ${moduleWithVersion}, already up to date`);
|
||||
continue;
|
||||
}
|
||||
backendOnlyModulesWithVersion.push(moduleWithVersion);
|
||||
}
|
||||
if (backendOnlyModulesWithVersion.length > 0) {
|
||||
for (const cwd of [vscodeDir, path.join(vscodeDir, 'remote')]) {
|
||||
console.log(`${path.join(cwd, 'package.json')}: Updating\n ${backendOnlyModulesWithVersion.join('\n ')}`);
|
||||
cp.execSync(`npm install ${backendOnlyModulesWithVersion.join(' ')}`, { cwd });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
update();
|
||||
@@ -0,0 +1,2 @@
|
||||
$scriptPath = Join-Path $PSScriptRoot "xterm-update.js"
|
||||
node $scriptPath (Get-Location)
|
||||
Reference in New Issue
Block a user