Compare commits
105 Commits
1.604-vsc1
...
1.1156-vsc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cf63bbd003 | ||
|
|
02f62882b8 | ||
|
|
362715bbeb | ||
|
|
ec70ea6994 | ||
|
|
04adf14146 | ||
|
|
406ec0ba71 | ||
|
|
a2ad3d4ff4 | ||
|
|
4a29cd1664 | ||
|
|
0462a93f11 | ||
|
|
db39eacfa1 | ||
|
|
c020cd2f2c | ||
|
|
81bbfa7fbe | ||
|
|
aa1474b675 | ||
|
|
8256252967 | ||
|
|
07342bbee7 | ||
|
|
72152f74ab | ||
|
|
420ca76f54 | ||
|
|
31503fc853 | ||
|
|
cf399ef6ac | ||
|
|
bb5836ec61 | ||
|
|
f36235e03f | ||
|
|
6ef1628acb | ||
|
|
ab8f8a0a22 | ||
|
|
cdb900aca8 | ||
|
|
1622fd4152 | ||
|
|
6c972e855f | ||
|
|
e332882a88 | ||
|
|
d0142e2536 | ||
|
|
e8c8fba91d | ||
|
|
01a63a7241 | ||
|
|
a2e0638c6a | ||
|
|
4e62f938a9 | ||
|
|
4c5bb83fc1 | ||
|
|
a3ac4567e3 | ||
|
|
58cf109a83 | ||
|
|
fab45dedcd | ||
|
|
446573809c | ||
|
|
5ad9398b01 | ||
|
|
bcdbd90197 | ||
|
|
0de7247868 | ||
|
|
c9f91e77cd | ||
|
|
30b8565e2d | ||
|
|
6b887dcc9c | ||
|
|
41c7d98b7b | ||
|
|
b055a26dc3 | ||
|
|
2bc6e1a457 | ||
|
|
e61ea796c6 | ||
|
|
d073622629 | ||
|
|
5f40ebb845 | ||
|
|
c56e2797cc | ||
|
|
166efcb17e | ||
|
|
206e107a9a | ||
|
|
12c8b5d337 | ||
|
|
4aa20fd864 | ||
|
|
0cd4e46055 | ||
|
|
f51823b51f | ||
|
|
55bfeab208 | ||
|
|
309d15cefd | ||
|
|
95006a435a | ||
|
|
4d576ab4d4 | ||
|
|
d5b03ef60e | ||
|
|
cdc5b55a9d | ||
|
|
c3a38e3fea | ||
|
|
cc8c7e2cee | ||
|
|
e0f1787ce6 | ||
|
|
50e6108012 | ||
|
|
630ccfcacc | ||
|
|
c4c26058ef | ||
|
|
8a4da542ae | ||
|
|
e907dbe7e6 | ||
|
|
22b485acd9 | ||
|
|
b8f222acf2 | ||
|
|
aabb2ecda7 | ||
|
|
dfabc070b9 | ||
|
|
da420cdda9 | ||
|
|
c6a46e4753 | ||
|
|
742dd6f597 | ||
|
|
6c3ff1d6f0 | ||
|
|
db57aa229f | ||
|
|
f7342ede69 | ||
|
|
b781ccde9c | ||
|
|
8f62b2bff2 | ||
|
|
7047be859c | ||
|
|
2785e2219a | ||
|
|
4b217fba00 | ||
|
|
3fae68bbab | ||
|
|
a2f20aa25c | ||
|
|
94b8b9a5cf | ||
|
|
bbd8b27fc7 | ||
|
|
6361635b55 | ||
|
|
d2da4cfc43 | ||
|
|
a1136b3a02 | ||
|
|
4dd74b31b9 | ||
|
|
bc0f6eb65d | ||
|
|
6737d3da18 | ||
|
|
eb0f773146 | ||
|
|
ebac84899e | ||
|
|
0b7a090a73 | ||
|
|
a95019f38d | ||
|
|
15948c1af6 | ||
|
|
e73eb74208 | ||
|
|
278c59b920 | ||
|
|
5a1eb858a9 | ||
|
|
3c1dfb1170 | ||
|
|
09a02eb9e9 |
@@ -7,3 +7,4 @@ doc/
|
||||
.travis.yml
|
||||
LICENSE
|
||||
README.md
|
||||
node_modules
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -4,4 +4,5 @@ dist
|
||||
out
|
||||
.DS_Store
|
||||
release
|
||||
.vscode
|
||||
.cache
|
||||
@@ -1 +1 @@
|
||||
8.15.0
|
||||
10.15.1
|
||||
|
||||
17
.travis.yml
17
.travis.yml
@@ -1,13 +1,21 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- 8.15.0
|
||||
env:
|
||||
- VSCODE_VERSION="1.32.0" MAJOR_VERSION="1" VERSION="$MAJOR_VERSION.$TRAVIS_BUILD_NUMBER-vsc$VSCODE_VERSION"
|
||||
- 10.15.1
|
||||
services:
|
||||
- docker
|
||||
matrix:
|
||||
include:
|
||||
- os: linux
|
||||
dist: trusty
|
||||
env:
|
||||
- VSCODE_VERSION="1.33.1" MAJOR_VERSION="1" VERSION="$MAJOR_VERSION.$TRAVIS_BUILD_NUMBER-vsc$VSCODE_VERSION" TARGET="centos"
|
||||
- os: linux
|
||||
dist: trusty
|
||||
env:
|
||||
- VSCODE_VERSION="1.33.1" MAJOR_VERSION="1" VERSION="$MAJOR_VERSION.$TRAVIS_BUILD_NUMBER-vsc$VSCODE_VERSION" TARGET="alpine"
|
||||
- os: osx
|
||||
env:
|
||||
- VSCODE_VERSION="1.33.1" MAJOR_VERSION="1" VERSION="$MAJOR_VERSION.$TRAVIS_BUILD_NUMBER-vsc$VSCODE_VERSION"
|
||||
before_install:
|
||||
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get install libxkbfile-dev
|
||||
libsecret-1-dev; fi
|
||||
@@ -19,7 +27,6 @@ before_deploy:
|
||||
- git config --local user.name "$USER_NAME"
|
||||
- git config --local user.email "$USER_EMAIL"
|
||||
- git tag "$VERSION" "$TRAVIS_COMMIT"
|
||||
- yarn task package "$VERSION"
|
||||
deploy:
|
||||
provider: releases
|
||||
file_glob: true
|
||||
@@ -34,7 +41,7 @@ deploy:
|
||||
- release/*.tar.gz
|
||||
- release/*.zip
|
||||
on:
|
||||
repo: codercom/code-server
|
||||
repo: cdr/code-server
|
||||
branch: master
|
||||
cache:
|
||||
yarn: true
|
||||
|
||||
37
Dockerfile
37
Dockerfile
@@ -1,4 +1,4 @@
|
||||
FROM node:8.15.0
|
||||
FROM node:10.15.1
|
||||
|
||||
# Install VS Code's deps. These are the only two it seems we need.
|
||||
RUN apt-get update && apt-get install -y \
|
||||
@@ -13,22 +13,41 @@ COPY . .
|
||||
|
||||
# In the future, we can use https://github.com/yarnpkg/rfcs/pull/53 to make yarn use the node_modules
|
||||
# directly which should be fast as it is slow because it populates its own cache every time.
|
||||
RUN yarn && yarn task build:server:binary
|
||||
RUN yarn && NODE_ENV=production yarn task build:server:binary
|
||||
|
||||
# We deploy with ubuntu so that devs have a familiar environment.
|
||||
FROM ubuntu:18.10
|
||||
WORKDIR /root/project
|
||||
COPY --from=0 /src/packages/server/cli-linux-x64 /usr/local/bin/code-server
|
||||
EXPOSE 8443
|
||||
FROM ubuntu:18.04
|
||||
|
||||
RUN apt-get update && apt-get install -y \
|
||||
openssl \
|
||||
net-tools \
|
||||
git \
|
||||
locales
|
||||
locales \
|
||||
sudo \
|
||||
dumb-init \
|
||||
vim \
|
||||
curl \
|
||||
wget
|
||||
|
||||
RUN locale-gen en_US.UTF-8
|
||||
# We unfortunately cannot use update-locale because docker will not use the env variables
|
||||
# configured in /etc/default/locale so we need to set it manually.
|
||||
ENV LANG=en_US.UTF-8
|
||||
ENV LC_ALL=en_US.UTF-8
|
||||
ENTRYPOINT ["code-server"]
|
||||
|
||||
RUN adduser --gecos '' --disabled-password coder && \
|
||||
echo "coder ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers.d/nopasswd
|
||||
|
||||
USER coder
|
||||
# We create first instead of just using WORKDIR as when WORKDIR creates, the user is root.
|
||||
RUN mkdir -p /home/coder/project
|
||||
|
||||
WORKDIR /home/coder/project
|
||||
|
||||
# This assures we have a volume mounted even if the user forgot to do bind mount.
|
||||
# So that they do not lose their data if they delete the container.
|
||||
VOLUME [ "/home/coder/project" ]
|
||||
|
||||
COPY --from=0 /src/packages/server/cli-linux-x64 /usr/local/bin/code-server
|
||||
EXPOSE 8443
|
||||
|
||||
ENTRYPOINT ["dumb-init", "code-server"]
|
||||
|
||||
20
README.md
20
README.md
@@ -1,15 +1,15 @@
|
||||
# code-server
|
||||
|
||||
[](https://github.com/codercom/code-server/issues)
|
||||
[](https://github.com/codercom/code-server/releases/latest)
|
||||
[](https://github.com/codercom/code-server/blob/master/LICENSE)
|
||||
[](https://github.com/cdr/code-server/issues)
|
||||
[](https://github.com/cdr/code-server/releases/latest)
|
||||
[](https://github.com/cdr/code-server/blob/master/LICENSE)
|
||||
[](https://discord.gg/zxSwN8Z)
|
||||
|
||||
`code-server` is [VS Code](https://github.com/Microsoft/vscode) running on a remote server, accessible through the browser.
|
||||
|
||||
Try it out:
|
||||
```bash
|
||||
docker run -t -p 127.0.0.1:8443:8443 -v "${PWD}:/root/project" codercom/code-server code-server --allow-http --no-auth
|
||||
docker run -it -p 127.0.0.1:8443:8443 -v "${PWD}:/home/coder/project" codercom/code-server --allow-http --no-auth
|
||||
```
|
||||
|
||||
- Code on your Chromebook, tablet, and laptop with a consistent dev environment.
|
||||
@@ -23,9 +23,9 @@ docker run -t -p 127.0.0.1:8443:8443 -v "${PWD}:/root/project" codercom/code-ser
|
||||
|
||||
## Getting Started
|
||||
|
||||
### Hosted
|
||||
### Run over SSH
|
||||
|
||||
[Try `code-server` now](https://coder.com/signup) for free at coder.com.
|
||||
Use [sshcode](https://github.com/codercom/sshcode) for a simple setup.
|
||||
|
||||
### Docker
|
||||
|
||||
@@ -33,7 +33,7 @@ See docker oneliner mentioned above. Dockerfile is at [/Dockerfile](/Dockerfile)
|
||||
|
||||
### Binaries
|
||||
|
||||
1. [Download a binary](https://github.com/codercom/code-server/releases) (Linux and OS X supported. Windows coming soon)
|
||||
1. [Download a binary](https://github.com/cdr/code-server/releases) (Linux and OS X supported. Windows coming soon)
|
||||
2. Start the binary with the project directory as the first argument
|
||||
|
||||
```
|
||||
@@ -67,6 +67,12 @@ How to [secure your setup](/doc/security/ssl.md).
|
||||
|
||||
At the moment we can't use the official VSCode Marketplace. We've created a custom extension marketplace focused around open-sourced extensions. However, if you have access to the `.vsix` file, you can manually install the extension.
|
||||
|
||||
## Telemetry
|
||||
|
||||
Use the `--disable-telemetry` flag or set `DISABLE_TELEMETRY=true` to disable tracking ENTIRELY.
|
||||
|
||||
We use data collected to improve code-server.
|
||||
|
||||
## Contributing
|
||||
|
||||
Development guides are coming soon.
|
||||
|
||||
42
build/platform.ts
Normal file
42
build/platform.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Script that detects platform name and arch.
|
||||
* Cannot use os.platform() as that won't detect libc version
|
||||
*/
|
||||
import * as cp from "child_process";
|
||||
import * as fs from "fs";
|
||||
import * as os from "os";
|
||||
|
||||
enum Lib {
|
||||
GLIBC,
|
||||
MUSL,
|
||||
}
|
||||
|
||||
const CLIB: Lib | undefined = ((): Lib | undefined => {
|
||||
if (os.platform() !== "linux") {
|
||||
return;
|
||||
}
|
||||
const glibc = cp.spawnSync("getconf", ["GNU_LIBC_VERSION"]);
|
||||
if (glibc.status === 0) {
|
||||
return Lib.GLIBC;
|
||||
}
|
||||
|
||||
const ldd = cp.spawnSync("ldd", ["--version"]);
|
||||
if (ldd.stdout && ldd.stdout.indexOf("musl") !== -1) {
|
||||
return Lib.MUSL;
|
||||
}
|
||||
|
||||
const muslFile = fs.readdirSync("/lib").find((value) => value.startsWith("libc.musl"));
|
||||
if (muslFile) {
|
||||
return Lib.MUSL;
|
||||
}
|
||||
|
||||
return Lib.GLIBC;
|
||||
})();
|
||||
|
||||
export const platform = (): NodeJS.Platform | "musl" => {
|
||||
if (CLIB === Lib.MUSL) {
|
||||
return "musl";
|
||||
}
|
||||
|
||||
return os.platform();
|
||||
};
|
||||
@@ -1,7 +1,9 @@
|
||||
import { register, run } from "@coder/runner";
|
||||
import { logger, field } from "@coder/logger";
|
||||
import * as fs from "fs";
|
||||
import * as fse from "fs-extra";
|
||||
import * as os from "os";
|
||||
import { platform } from "./platform";
|
||||
import * as path from "path";
|
||||
import * as zlib from "zlib";
|
||||
import * as https from "https";
|
||||
@@ -12,10 +14,17 @@ const libPath = path.join(__dirname, "../lib");
|
||||
const vscodePath = path.join(libPath, "vscode");
|
||||
const defaultExtensionsPath = path.join(libPath, "extensions");
|
||||
const pkgsPath = path.join(__dirname, "../packages");
|
||||
const vscodeVersion = process.env.VSCODE_VERSION || "1.32.0";
|
||||
const vscodeVersion = process.env.VSCODE_VERSION || "1.33.1";
|
||||
const vsSourceUrl = `https://codesrv-ci.cdr.sh/vstar-${vscodeVersion}.tar.gz`;
|
||||
|
||||
const buildServerBinary = register("build:server:binary", async (runner) => {
|
||||
logger.info("Building with environment", field("env", {
|
||||
NODE_ENV: process.env.NODE_ENV,
|
||||
VERSION: process.env.VERSION,
|
||||
OSTYPE: process.env.OSTYPE,
|
||||
TARGET: process.env.TARGET,
|
||||
}));
|
||||
|
||||
await ensureInstalled();
|
||||
await Promise.all([
|
||||
buildBootstrapFork(),
|
||||
@@ -48,19 +57,11 @@ const buildServerBinaryCopy = register("build:server:binary:copy", async (runner
|
||||
const bootstrapForkPath = path.join(pkgsPath, "vscode", "out", "bootstrap-fork.js");
|
||||
const webOutputPath = path.join(pkgsPath, "web", "out");
|
||||
const browserAppOutputPath = path.join(pkgsPath, "app", "browser", "out");
|
||||
const nodePtyModule = path.join(pkgsPath, "protocol", "node_modules", "node-pty-prebuilt", "build", "Release", "pty.node");
|
||||
const spdlogModule = path.join(pkgsPath, "protocol", "node_modules", "spdlog", "build", "Release", "spdlog.node");
|
||||
let ripgrepPath = path.join(pkgsPath, "..", "lib", "vscode", "node_modules", "vscode-ripgrep", "bin", "rg");
|
||||
if (isWin) {
|
||||
ripgrepPath += ".exe";
|
||||
}
|
||||
|
||||
if (!fs.existsSync(nodePtyModule)) {
|
||||
throw new Error("Could not find pty.node. Ensure all packages have been installed");
|
||||
}
|
||||
if (!fs.existsSync(spdlogModule)) {
|
||||
throw new Error("Could not find spdlog.node. Ensure all packages have been installed");
|
||||
}
|
||||
if (!fs.existsSync(webOutputPath)) {
|
||||
throw new Error("Web bundle must be built");
|
||||
}
|
||||
@@ -75,24 +76,22 @@ const buildServerBinaryCopy = register("build:server:binary:copy", async (runner
|
||||
}
|
||||
fse.copySync(defaultExtensionsPath, path.join(cliBuildPath, "extensions"));
|
||||
fs.writeFileSync(path.join(cliBuildPath, "bootstrap-fork.js.gz"), zlib.gzipSync(fs.readFileSync(bootstrapForkPath)));
|
||||
const cpDir = (dir: string, subdir: "auth" | "unauth", rootPath: string): void => {
|
||||
const cpDir = (dir: string, rootPath: string, subdir?: "login"): void => {
|
||||
const stat = fs.statSync(dir);
|
||||
if (stat.isDirectory()) {
|
||||
const paths = fs.readdirSync(dir);
|
||||
paths.forEach((p) => cpDir(path.join(dir, p), subdir, rootPath));
|
||||
paths.forEach((p) => cpDir(path.join(dir, p), rootPath, subdir));
|
||||
} else if (stat.isFile()) {
|
||||
const newPath = path.join(cliBuildPath, "web", subdir, path.relative(rootPath, dir));
|
||||
const newPath = path.join(cliBuildPath, "web", subdir || "", path.relative(rootPath, dir));
|
||||
fse.mkdirpSync(path.dirname(newPath));
|
||||
fs.writeFileSync(newPath + ".gz", zlib.gzipSync(fs.readFileSync(dir)));
|
||||
} else {
|
||||
// Nothing
|
||||
}
|
||||
};
|
||||
cpDir(webOutputPath, "auth", webOutputPath);
|
||||
cpDir(browserAppOutputPath, "unauth", browserAppOutputPath);
|
||||
cpDir(webOutputPath, webOutputPath);
|
||||
cpDir(browserAppOutputPath, browserAppOutputPath, "login");
|
||||
fse.mkdirpSync(path.join(cliBuildPath, "dependencies"));
|
||||
fse.copySync(nodePtyModule, path.join(cliBuildPath, "dependencies", "pty.node"));
|
||||
fse.copySync(spdlogModule, path.join(cliBuildPath, "dependencies", "spdlog.node"));
|
||||
fse.copySync(ripgrepPath, path.join(cliBuildPath, "dependencies", "rg"));
|
||||
});
|
||||
|
||||
@@ -190,12 +189,12 @@ register("package", async (runner, releaseTag) => {
|
||||
|
||||
const releasePath = path.resolve(__dirname, "../release");
|
||||
|
||||
const archiveName = `code-server${releaseTag}-${os.platform()}-${os.arch()}`;
|
||||
const archiveName = `code-server${releaseTag}-${platform()}-${os.arch()}`;
|
||||
const archiveDir = path.join(releasePath, archiveName);
|
||||
fse.removeSync(archiveDir);
|
||||
fse.mkdirpSync(archiveDir);
|
||||
|
||||
const binaryPath = path.join(__dirname, `../packages/server/cli-${os.platform()}-${os.arch()}`);
|
||||
const binaryPath = path.join(__dirname, `../packages/server/cli-${platform()}-${os.arch()}`);
|
||||
const binaryDestination = path.join(archiveDir, "code-server");
|
||||
fse.copySync(binaryPath, binaryDestination);
|
||||
fs.chmodSync(binaryDestination, "755");
|
||||
@@ -204,9 +203,9 @@ register("package", async (runner, releaseTag) => {
|
||||
});
|
||||
|
||||
runner.cwd = releasePath;
|
||||
await os.platform() === "linux"
|
||||
await (os.platform() === "linux"
|
||||
? runner.execute("tar", ["-cvzf", `${archiveName}.tar.gz`, `${archiveName}`])
|
||||
: runner.execute("zip", ["-r", `${archiveName}.zip`, `${archiveName}`]);
|
||||
: runner.execute("zip", ["-r", `${archiveName}.zip`, `${archiveName}`]));
|
||||
});
|
||||
|
||||
run();
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
This tutorial shows you how to deploy `code-server` on an EC2 AWS instance.
|
||||
|
||||
If you're just starting out, we recommend [installing code-server locally](../../self-hosted/index.md). It takes only a few minutes and lets you try out all of the features. You can also try out the IDE on a container hosted [by Coder](http://coder.com/signup)
|
||||
If you're just starting out, we recommend [installing code-server locally](../../self-hosted/index.md). It takes only a few minutes and lets you try out all of the features.
|
||||
|
||||
---
|
||||
|
||||
@@ -11,9 +11,9 @@ If you're just starting out, we recommend [installing code-server locally](../..
|
||||
### Use the AWS wizard
|
||||
|
||||
- Click **Launch Instance** from your [EC2 dashboard](https://console.aws.amazon.com/ec2/v2/home).
|
||||
- Select the Ubuntu Server 16.04 LTS (HVM), SSD Volume Type (`ami-0f9cf087c1f27d9b1)` at this time of writing)
|
||||
- Select the Ubuntu Server 18.04 LTS (HVM), SSD Volume Type
|
||||
- Select an appropriate instance size (we recommend t2.medium/large, depending on team size and number of repositories/languages enabled), then **Next: Configure Instance Details**
|
||||
- Select **Next: ...** until you get to the **Configure Security Group** page, then add the default **HTTP** rule (port range "80", source "0.0.0.0/0, ::/0")
|
||||
- Select **Next: ...** until you get to the **Configure Security Group** page, then add a **Custom TCP Rule** rule with port range set to `8443` and source set to "Anywhere"
|
||||
> Rules with source of 0.0.0.0/0 allow all IP addresses to access your instance. We recommend setting [security group rules](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-network-security.html?icmpid=docs_ec2_console) to allow access from known IP addresses only.
|
||||
- Click **Launch**
|
||||
- You will be prompted to create a key pair
|
||||
@@ -35,11 +35,11 @@ If you're just starting out, we recommend [installing code-server locally](../..
|
||||
- At this point it is time to download the `code-server` binary. We will of course want the linux version.
|
||||
- Find the latest Linux release from this URL:
|
||||
```
|
||||
https://github.com/codercom/code-server/releases/latest
|
||||
https://github.com/cdr/code-server/releases/latest
|
||||
```
|
||||
- Replace {version} in the following command with the version found on the releases page and run it (or just copy the download URL from the releases page):
|
||||
```
|
||||
wget https://github.com/codercom/code-server/releases/download/{version}/code-server-{version}-linux-x64.tar.gz
|
||||
wget https://github.com/cdr/code-server/releases/download/{version}/code-server-{version}-linux-x64.tar.gz
|
||||
```
|
||||
- Extract the downloaded tar.gz file with this command, for example:
|
||||
```
|
||||
@@ -56,14 +56,11 @@ If you're just starting out, we recommend [installing code-server locally](../..
|
||||
> To ensure the connection between you and your server is encrypted view our guide on [securing your setup](../../security/ssl.md)
|
||||
- Finally, run
|
||||
```
|
||||
sudo ./code-server -p 80
|
||||
./code-server
|
||||
```
|
||||
- When you visit the public IP for your AWS instance, you will be greeted with this page. Code-server is using a self-signed SSL certificate for easy setup. To proceed to the IDE, click **"Advanced"**<img src ="../../assets/chrome_warning.png">
|
||||
- Then click **"proceed anyway"**<img src="../../assets/chrome_confirm.png">
|
||||
- Open your browser and visit `https://$public_ip:8443/` (where `$public_ip` is your AWS instance's public IP address). You will be greeted with a page similar to the following screenshot. Code-server is using a self-signed SSL certificate for easy setup. In Chrome/Chromium, click **"Advanced"** then click **"proceed anyway"**. In Firefox, click **Advanced**, then **Add Exception**, then finally **Confirm Security Exception**.<img src ="../../assets/chrome_warning.png">
|
||||
|
||||
> For instructions on how to keep the server running after you end your SSH session please checkout [how to use systemd](https://www.linode.com/docs/quick-answers/linux/start-service-at-boot/) to start linux based services if they are killed
|
||||
|
||||
> The `-p 80` flag is necessary in order to make the IDE accessible from the public IP of your instance (also available from the description in the instances page.
|
||||
|
||||
---
|
||||
> NOTE: If you get stuck or need help, [file an issue](https://github.com/codercom/code-server/issues/new?&title=Improve+self-hosted+quickstart+guide), [tweet (@coderhq)](https://twitter.com/coderhq) or [email](mailto:support@coder.com?subject=Self-hosted%20quickstart%20guide).
|
||||
> NOTE: If you get stuck or need help, [file an issue](https://github.com/cdr/code-server/issues/new?&title=Improve+self-hosted+quickstart+guide), [tweet (@coderhq)](https://twitter.com/coderhq) or [email](mailto:support@coder.com?subject=Self-hosted%20quickstart%20guide).
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
This tutorial shows you how to deploy `code-server` to a single node running on DigitalOcean.
|
||||
|
||||
If you're just starting out, we recommend [installing code-server locally](../../self-hosted/index.md). It takes only a few minutes and lets you try out all of the features. You can also try out the IDE on a container hosted [by Coder](http://coder.com/signup)
|
||||
If you're just starting out, we recommend [installing code-server locally](../../self-hosted/index.md). It takes only a few minutes and lets you try out all of the features.
|
||||
|
||||
---
|
||||
|
||||
@@ -15,14 +15,14 @@ If you're just starting out, we recommend [installing code-server locally](../..
|
||||
- Launch your instance
|
||||
- Open a terminal on your computer and SSH into your instance
|
||||
> example: ssh root@203.0.113.0
|
||||
- Once in the SSH session, visit code-server [releases page](https://github.com/codercom/code-server/releases/) and copy the link to the download for the latest linux release
|
||||
- Once in the SSH session, visit code-server [releases page](https://github.com/cdr/code-server/releases/) and copy the link to the download for the latest linux release
|
||||
- Find the latest Linux release from this URL:
|
||||
```
|
||||
https://github.com/codercom/code-server/releases/latest
|
||||
https://github.com/cdr/code-server/releases/latest
|
||||
```
|
||||
- Replace {version} in the following command with the version found on the releases page and run it (or just copy the download URL from the releases page):
|
||||
```
|
||||
wget https://github.com/codercom/code-server/releases/download/{version}/code-server-{version}-linux-x64.tar.gz
|
||||
wget https://github.com/cdr/code-server/releases/download/{version}/code-server-{version}-linux-x64.tar.gz
|
||||
```
|
||||
- Extract the downloaded tar.gz file with this command, for example:
|
||||
```
|
||||
@@ -39,11 +39,10 @@ If you're just starting out, we recommend [installing code-server locally](../..
|
||||
> To ensure the connection between you and your server is encrypted view our guide on [securing your setup](../../security/ssl.md)
|
||||
- Finally start the code-server
|
||||
```
|
||||
sudo ./code-server-linux -p 80
|
||||
./code-server
|
||||
```
|
||||
> For instructions on how to keep the server running after you end your SSH session please checkout [how to use systemd](https://www.linode.com/docs/quick-answers/linux/start-service-at-boot/) to start linux based services if they are killed
|
||||
- When you visit the public IP for your Digital Ocean instance, you will be greeted with this page. Code-server is using a self-signed SSL certificate for easy setup. To proceed to the IDE, click **"Advanced"**<img src ="../../assets/chrome_warning.png">
|
||||
- Then click **"proceed anyway"**<img src="../../assets/chrome_confirm.png">
|
||||
- Open your browser and visit `https://$public_ip:8443/` (where `$public_ip` is your Digital Ocean instance's public IP address). You will be greeted with a page similar to the following screenshot. Code-server is using a self-signed SSL certificate for easy setup. In Chrome/Chromium, click **"Advanced"** then click **"proceed anyway"**. In Firefox, click **Advanced**, then **Add Exception**, then finally **Confirm Security Exception**.<img src ="../../assets/chrome_warning.png">
|
||||
|
||||
---
|
||||
> NOTE: If you get stuck or need help, [file an issue](https://github.com/codercom/code-server/issues/new?&title=Improve+self-hosted+quickstart+guide), [tweet (@coderhq)](https://twitter.com/coderhq) or [email](mailto:support@coder.com?subject=Self-hosted%20quickstart%20guide).
|
||||
> NOTE: If you get stuck or need help, [file an issue](https://github.com/cdr/code-server/issues/new?&title=Improve+self-hosted+quickstart+guide), [tweet (@coderhq)](https://twitter.com/coderhq) or [email](mailto:support@coder.com?subject=Self-hosted%20quickstart%20guide).
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
This tutorial shows you how to deploy `code-server` to a single node running on Google Cloud.
|
||||
|
||||
If you're just starting out, we recommend [installing code-server locally](../../self-hosted/index.md). It takes only a few minutes and lets you try out all of the features. You can also try out the IDE on a container hosted [by Coder](http://coder.com/signup)
|
||||
If you're just starting out, we recommend [installing code-server locally](../../self-hosted/index.md). It takes only a few minutes and lets you try out all of the features.
|
||||
|
||||
---
|
||||
|
||||
@@ -12,9 +12,10 @@ If you're just starting out, we recommend [installing code-server locally](../..
|
||||
- [Open your Google Cloud console](https://console.cloud.google.com/compute/instances) to create a new VM instance and click **Create Instance**
|
||||
- Choose an appropriate machine type (we recommend 2 vCPU and 7.5 GB RAM, more depending on team size and number of repositories/languages enabled)
|
||||
- Choose Ubuntu 16.04 LTS as your boot disk
|
||||
- Check the boxes for **Allow HTTP traffic** and **Allow HTTPS traffic** in the **Firewall** section
|
||||
- Expand the "Management, security, disks, networking, sole tenancy" section, go to the "Networking" tab, then under network tags add "code-server"
|
||||
- Create your VM, and **take note** of its public IP address.
|
||||
- Copy the link to download the latest Linux binary from our [releases page](https://github.com/codercom/code-server/releases)
|
||||
- Visit "VPC network" in the console and go to "Firewall rules". Create a new firewall rule called "http-8443". Under "Target tags" add "code-server", and under "Protocols and ports" tick "Specified protocols and ports" and "tcp". Beside "tcp", add "8443", then create the rule.
|
||||
- Copy the link to download the latest Linux binary from our [releases page](https://github.com/cdr/code-server/releases)
|
||||
|
||||
---
|
||||
|
||||
@@ -27,12 +28,12 @@ gcloud compute ssh --zone [region] [instance name]
|
||||
|
||||
- Find the latest Linux release from this URL:
|
||||
```
|
||||
https://github.com/codercom/code-server/releases/latest
|
||||
https://github.com/cdr/code-server/releases/latest
|
||||
```
|
||||
|
||||
- Replace {version} in the following command with the version found on the releases page and run it (or just copy the download URL from the releases page):
|
||||
```
|
||||
wget https://github.com/codercom/code-server/releases/download/{version}/code-server-{version}-linux-x64.tar.gz
|
||||
wget https://github.com/cdr/code-server/releases/download/{version}/code-server-{version}-linux-x64.tar.gz
|
||||
```
|
||||
|
||||
- Extract the downloaded tar.gz file with this command, for example:
|
||||
@@ -50,22 +51,16 @@ cd code-server-{version}-linux-x64
|
||||
chmod +x code-server
|
||||
```
|
||||
|
||||
> To ensure the connection between you and your server is encrypted view our guide on [securing your setup](../security/ssl.md)
|
||||
> To ensure the connection between you and your server is encrypted view our guide on [securing your setup](../../security/ssl.md)
|
||||
|
||||
- Start the code-server
|
||||
```
|
||||
sudo ./code-server -p 80
|
||||
./code-server
|
||||
```
|
||||
- Open your browser and visit `https://$public_ip:8443/` (where `$public_ip` is your Compute Engine instance's public IP address). You will be greeted with a page similar to the following screenshot. Code-server is using a self-signed SSL certificate for easy setup. In Chrome/Chromium, click **"Advanced"** then click **"proceed anyway"**. In Firefox, click **Advanced**, then **Add Exception**, then finally **Confirm Security Exception**.<img src ="../../assets/chrome_warning.png">
|
||||
|
||||
> For instructions on how to keep the server running after you end your SSH session please checkout [how to use systemd](https://www.linode.com/docs/quick-answers/linux/start-service-at-boot/) to start linux based services if they are killed
|
||||
|
||||
- Access code-server from the public IP of your Google Cloud instance we noted earlier in your browser.
|
||||
> example: 32.32.32.234
|
||||
|
||||
- You will be greeted with this page. Code-server is using a self-signed SSL certificate for easy setup. To proceed to the IDE, click **"Advanced"**<img src ="../../assets/chrome_warning.png">
|
||||
|
||||
- Then click **"proceed anyway"**<img src="../../assets/chrome_confirm.png">
|
||||
|
||||
---
|
||||
|
||||
> NOTE: If you get stuck or need help, [file an issue](https://github.com/codercom/code-server/issues/new?&title=Improve+self-hosted+quickstart+guide), [tweet (@coderhq)](https://twitter.com/coderhq) or [email](mailto:support@coder.com?subject=Self-hosted%20quickstart%20guide).
|
||||
> NOTE: If you get stuck or need help, [file an issue](https://github.com/cdr/code-server/issues/new?&title=Improve+self-hosted+quickstart+guide), [tweet (@coderhq)](https://twitter.com/coderhq) or [email](mailto:support@coder.com?subject=Self-hosted%20quickstart%20guide).
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 19 KiB |
@@ -4,7 +4,7 @@
|
||||
|
||||
## Quickstart Guide
|
||||
|
||||
> NOTE: If you get stuck or need help, [file an issue](https://github.com/codercom/code-server/issues/new?&title=Improve+self-hosted+quickstart+guide), [tweet (@coderhq)](https://twitter.com/coderhq) or [email](mailto:support@coder.com?subject=Self-hosted%20quickstart%20guide).
|
||||
> NOTE: If you get stuck or need help, [file an issue](https://github.com/cdr/code-server/issues/new?&title=Improve+self-hosted+quickstart+guide), [tweet (@coderhq)](https://twitter.com/coderhq) or [email](mailto:support@coder.com?subject=Self-hosted%20quickstart%20guide).
|
||||
|
||||
This document pertains to Coder specific implementations of VS Code. For documentation on how to use VS Code itself, please refer to the official [documentation for VS Code](https://code.visualstudio.com/docs)
|
||||
|
||||
@@ -17,7 +17,7 @@ It takes just a few minutes to get your own self-hosted server running. If you'v
|
||||
-->
|
||||
|
||||
|
||||
1. Visit [the releases](https://github.com/codercom/code-server/releases) page and download the latest cli for your operating system
|
||||
1. Visit [the releases](https://github.com/cdr/code-server/releases) page and download the latest cli for your operating system
|
||||
2. Double click the executable to run in the current directory
|
||||
3. Copy the password that appears in the cli<img src="../assets/cli.png">
|
||||
4. In your browser navigate to `localhost:8443`
|
||||
@@ -25,8 +25,7 @@ It takes just a few minutes to get your own self-hosted server running. If you'v
|
||||
> NOTE: Be careful with your password as sharing it will grant those users access to your server's file system
|
||||
|
||||
### Things To Know
|
||||
- When you visit the IP for your code-server, you will be greeted with this page. Code-server is using a self-signed SSL certificate for easy setup. To proceed to the IDE, click **"Advanced"**<img src ="../assets/chrome_warning.png">
|
||||
- Then click **"proceed anyway"**<img src="../assets/chrome_confirm.png">
|
||||
- When you visit the IP for your code-server instance, you will be greeted with a page similar to the following screenshot. Code-server is using a self-signed SSL certificate for easy setup. In Chrome/Chromium, click **"Advanced"** then click **"proceed anyway"**. In Firefox, click **Advanced**, then **Add Exception**, then finally **Confirm Security Exception**.<img src ="../../assets/chrome_warning.png">
|
||||
|
||||
## Usage
|
||||
<pre class="pre-wrap"><code>code-server<span class="virtual-br"></span> --help</code></pre>
|
||||
@@ -34,40 +33,44 @@ It takes just a few minutes to get your own self-hosted server running. If you'v
|
||||
code-server can be ran with a number of arguments to customize your working directory, host, port, and SSL certificate.
|
||||
|
||||
```
|
||||
USAGE
|
||||
$ code-server [WORKDIR]
|
||||
Usage: code-server [options]
|
||||
|
||||
ARGUMENTS
|
||||
WORKDIR [default: (directory to binary)] Specify working dir
|
||||
Run VS Code on a remote server.
|
||||
|
||||
OPTIONS
|
||||
-d, --data-dir=data-dir
|
||||
-h, --host=host [default: 0.0.0.0]
|
||||
-o, --open Open in browser on startup
|
||||
-p, --port=port [default: 8443] Port to bind on
|
||||
-v, --version show CLI version
|
||||
--allow-http
|
||||
--cert=cert
|
||||
--cert-key=cert-key
|
||||
--help show CLI help
|
||||
--no-auth
|
||||
--password=password
|
||||
Options:
|
||||
-V, --version output the version number
|
||||
--cert <value>
|
||||
--cert-key <value>
|
||||
-e, --extensions-dir <dir> Set the root path for extensions.
|
||||
-d --user-data-dir <dir> Specifies the directory that user data is kept in, useful when running as root.
|
||||
--data-dir <value> DEPRECATED: Use '--user-data-dir' instead. Customize where user-data is stored.
|
||||
-h, --host <value> Customize the hostname. (default: "0.0.0.0")
|
||||
-o, --open Open in the browser on startup.
|
||||
-p, --port <number> Port to bind on. (default: 8443)
|
||||
-N, --no-auth Start without requiring authentication.
|
||||
-H, --allow-http Allow http connections.
|
||||
-P, --password <value> Specify a password for authentication.
|
||||
--disable-telemetry Disables ALL telemetry.
|
||||
--help output usage information
|
||||
```
|
||||
|
||||
### Data Directory
|
||||
Use `code-server -d (path/to/directory)` or `code-server --data-dir=(path/to/directory)`, excluding the parentheses to specify the root folder that VS Code will start in
|
||||
Use `code-server -d (path/to/directory)` or `code-server --user-data-dir=(path/to/directory)`, excluding the parentheses to specify the root folder that VS Code will start in.
|
||||
|
||||
### Host
|
||||
By default, code-server will use `0.0.0.0` as its address. This can be changed by using `code-server -h` or `code-server --host=` followed by the address you want to use.
|
||||
> Example: `code-server -h 127.0.0.1`
|
||||
|
||||
### Open
|
||||
You can have the server automatically open the VS Code in your browser on startup by using the `code server -o` or `code-server --open` flags
|
||||
You can have the server automatically open the VS Code in your browser on startup by using the `code-server -o` or `code-server --open` flags
|
||||
|
||||
### Port
|
||||
By default, code-server will use `8443` as its port. This can be changed by using `code-server -p` or `code-server --port=` followed by the port you want to use.
|
||||
> Example: `code-server -p 9000`
|
||||
|
||||
### Telemetry
|
||||
Disable all telemetry with `code-server --disable-telemetry`.
|
||||
|
||||
### Cert and Cert Key
|
||||
To encrypt the traffic between the browser and server use `code-server --cert=` followed by the path to your `.cer` file. Additionally, you can use certificate keys with `code-server --cert-key` followed by the path to your `.key` file.
|
||||
> Example (certificate and key): `code-server --cert /etc/letsencrypt/live/example.com/fullchain.cer --cert-key /etc/letsencrypt/live/example.com/fullchain.key`
|
||||
@@ -116,4 +119,4 @@ OPTIONS
|
||||
*Important:* For more details about Apache reverse proxy configuration checkout the [documentation](https://httpd.apache.org/docs/current/mod/mod_proxy.html) - especially the [Securing your Server](https://httpd.apache.org/docs/current/mod/mod_proxy.html#access) section
|
||||
|
||||
### Help
|
||||
Use `code-server -h` or `code-server --help` to view the usage for the cli. This is also shown at the beginning of this section.
|
||||
Use `code-server --help` to view the usage for the CLI. This is also shown at the beginning of this section.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@coder/code-server",
|
||||
"repository": "https://github.com/codercom/code-server",
|
||||
"repository": "https://github.com/cdr/code-server",
|
||||
"author": "Coder",
|
||||
"license": "MIT",
|
||||
"description": "Run VS Code remotely.",
|
||||
@@ -54,10 +54,17 @@
|
||||
"webpack-dev-middleware": "^3.5.0",
|
||||
"webpack-dev-server": "^3.1.14",
|
||||
"webpack-hot-middleware": "^2.24.3",
|
||||
"webpack-pwa-manifest": "^4.0.0",
|
||||
"workbox-webpack-plugin": "^4.1.0",
|
||||
"write-file-webpack-plugin": "^4.5.0"
|
||||
},
|
||||
"resolutions": {
|
||||
"bindings": "1.3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"node-loader": "^0.6.0",
|
||||
"node-pty": "0.8.1",
|
||||
"spdlog": "0.8.1",
|
||||
"webpack-merge": "^4.2.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,9 +7,10 @@
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<form id="login-form">
|
||||
<div class="login">
|
||||
<div class="back"> <- Back </div>
|
||||
<h4 class="title">code-server</h4>
|
||||
<div class="back">
|
||||
<- Back </div> <h4 class="title">code-server</h4>
|
||||
<h2 class="subtitle">
|
||||
Enter server password
|
||||
</h2>
|
||||
@@ -23,6 +24,7 @@
|
||||
</button>
|
||||
<div id="error-display"></div>
|
||||
</div>
|
||||
</form>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -20,12 +20,17 @@ window.addEventListener("message", (event) => {
|
||||
});
|
||||
|
||||
const password = document.getElementById("password") as HTMLInputElement;
|
||||
const submit = document.getElementById("submit") as HTMLButtonElement;
|
||||
if (!submit) {
|
||||
throw new Error("No submit button found");
|
||||
const form = document.getElementById("login-form") as HTMLFormElement;
|
||||
|
||||
if (!form) {
|
||||
throw new Error("No password form found");
|
||||
}
|
||||
submit.addEventListener("click", () => {
|
||||
document.cookie = `password=${password.value}`;
|
||||
|
||||
form.addEventListener("submit", (e) => {
|
||||
e.preventDefault();
|
||||
document.cookie = `password=${password.value}; `
|
||||
+ `path=${location.pathname.replace(/\/login\/?$/, "/")}; `
|
||||
+ `domain=${location.hostname}`;
|
||||
location.reload();
|
||||
});
|
||||
|
||||
|
||||
@@ -7,11 +7,10 @@ const root = path.resolve(__dirname, "../../..");
|
||||
|
||||
module.exports = merge(
|
||||
require(path.join(root, "scripts/webpack.client.config.js"))({
|
||||
entry: path.join(root, "packages/app/browser/src/app.ts"),
|
||||
template: path.join(root, "packages/app/browser/src/app.html"),
|
||||
dirname: __dirname,
|
||||
entry: path.join(__dirname, "src/app.ts"),
|
||||
name: "login",
|
||||
template: path.join(__dirname, "src/app.html"),
|
||||
}), {
|
||||
output: {
|
||||
path: path.join(__dirname, "out"),
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
@@ -5,15 +5,12 @@ const root = path.resolve(__dirname, "../..");
|
||||
|
||||
module.exports = merge(
|
||||
require(path.join(root, "scripts/webpack.node.config.js"))({
|
||||
// Options.
|
||||
dirname: __dirname,
|
||||
name: "dns",
|
||||
}), {
|
||||
externals: {
|
||||
"node-named": "commonjs node-named",
|
||||
},
|
||||
output: {
|
||||
path: path.join(__dirname, "out"),
|
||||
filename: "main.js",
|
||||
},
|
||||
entry: [
|
||||
"./packages/dns/src/dns.ts"
|
||||
],
|
||||
|
||||
14
packages/ide-api/api.d.ts
vendored
14
packages/ide-api/api.d.ts
vendored
@@ -1,5 +1,10 @@
|
||||
// tslint:disable no-any
|
||||
|
||||
import { ITerminalService } from "vs/workbench/contrib/terminal/common/terminal";
|
||||
import { IWorkbenchActionRegistry } from 'vs/workbench/common/actions';
|
||||
import { Action } from 'vs/base/common/actions';
|
||||
import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
|
||||
|
||||
export interface EvalHelper { }
|
||||
interface ActiveEvalEmitter {
|
||||
removeAllListeners(event?: string): void;
|
||||
@@ -136,14 +141,23 @@ interface ICommandRegistry {
|
||||
registerCommand(command: ICommand): IDisposable;
|
||||
}
|
||||
|
||||
interface IStorageService {
|
||||
save(): Promise<void>;
|
||||
}
|
||||
|
||||
declare namespace ide {
|
||||
export const client: {};
|
||||
|
||||
export const workbench: {
|
||||
readonly action: Action,
|
||||
readonly syncActionDescriptor: SyncActionDescriptor,
|
||||
readonly statusbarService: IStatusbarService;
|
||||
readonly actionsRegistry: IWorkbenchActionRegistry;
|
||||
readonly notificationService: INotificationService;
|
||||
readonly storageService: IStorageService;
|
||||
readonly menuRegistry: IMenuRegistry;
|
||||
readonly commandRegistry: ICommandRegistry;
|
||||
readonly terminalService: ITerminalService;
|
||||
|
||||
onFileCreate(cb: (path: string) => void): void;
|
||||
onFileMove(cb: (path: string, target: string) => void): void;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@coder/ide-api",
|
||||
"version": "1.0.3",
|
||||
"version": "1.0.4",
|
||||
"typings": "api.d.ts",
|
||||
"author": "Coder",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -34,6 +34,12 @@ export abstract class IdeClient {
|
||||
this.loadTime = time(2500);
|
||||
|
||||
let appWindow: Window | undefined;
|
||||
|
||||
window.addEventListener("beforeunload", (e) => {
|
||||
e.preventDefault(); // FireFox
|
||||
e.returnValue = ""; // Chrome
|
||||
});
|
||||
|
||||
window.addEventListener("message", (event) => {
|
||||
if (event.data === "app") {
|
||||
appWindow = event.source as Window;
|
||||
@@ -41,7 +47,16 @@ export abstract class IdeClient {
|
||||
});
|
||||
|
||||
this.sharedProcessData = new Promise((resolve): void => {
|
||||
client.onSharedProcessActive(resolve);
|
||||
let d = client.onSharedProcessActive((data) => {
|
||||
d.dispose();
|
||||
d = client.onSharedProcessActive(() => {
|
||||
d.dispose();
|
||||
this.retry.notificationService.error(
|
||||
new Error("Disconnected from shared process. Searching, installing, enabling, and disabling extensions will not work until the page is refreshed."),
|
||||
);
|
||||
});
|
||||
resolve(data);
|
||||
});
|
||||
});
|
||||
|
||||
window.addEventListener("contextmenu", (event) => {
|
||||
@@ -65,10 +80,6 @@ export abstract class IdeClient {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap a task in some logging, timing, and progress updates. Can optionally
|
||||
* wait on other tasks which won't count towards this task's time.
|
||||
*/
|
||||
public async task<T>(description: string, duration: number, task: () => Promise<T>): Promise<T>;
|
||||
public async task<T, V>(description: string, duration: number, task: (v: V) => Promise<T>, t: Promise<V>): Promise<T>;
|
||||
public async task<T, V1, V2>(description: string, duration: number, task: (v1: V1, v2: V2) => Promise<T>, t1: Promise<V1>, t2: Promise<V2>): Promise<T>;
|
||||
@@ -76,6 +87,10 @@ export abstract class IdeClient {
|
||||
public async task<T, V1, V2, V3, V4>(description: string, duration: number, task: (v1: V1, v2: V2, v3: V3, v4: V4) => Promise<T>, t1: Promise<V1>, t2: Promise<V2>, t3: Promise<V3>, t4: Promise<V4>): Promise<T>;
|
||||
public async task<T, V1, V2, V3, V4, V5>(description: string, duration: number, task: (v1: V1, v2: V2, v3: V3, v4: V4, v5: V5) => Promise<T>, t1: Promise<V1>, t2: Promise<V2>, t3: Promise<V3>, t4: Promise<V4>, t5: Promise<V5>): Promise<T>;
|
||||
public async task<T, V1, V2, V3, V4, V5, V6>(description: string, duration: number, task: (v1: V1, v2: V2, v3: V3, v4: V4, v5: V5, v6: V6) => Promise<T>, t1: Promise<V1>, t2: Promise<V2>, t3: Promise<V3>, t4: Promise<V4>, t5: Promise<V5>, t6: Promise<V6>): Promise<T>;
|
||||
/**
|
||||
* Wrap a task in some logging, timing, and progress updates. Can optionally
|
||||
* wait on other tasks which won't count towards this task's time.
|
||||
*/
|
||||
public async task<T>(
|
||||
description: string, duration: number = 100, task: (...args: any[]) => Promise<T>, ...after: Array<Promise<any>> // tslint:disable-line no-any
|
||||
): Promise<T> {
|
||||
|
||||
@@ -132,7 +132,7 @@ export class Dialog {
|
||||
public show(): void {
|
||||
if (!this.cachedActiveElement) {
|
||||
this.cachedActiveElement = document.activeElement as HTMLElement;
|
||||
(document.getElementById("workbench.main.container") || document.body).appendChild(this.overlay);
|
||||
(document.querySelector(".monaco-workbench") || document.body).appendChild(this.overlay);
|
||||
document.addEventListener("keydown", this.onKeydown);
|
||||
if (this.input) {
|
||||
this.input.focus();
|
||||
|
||||
@@ -45,7 +45,8 @@ const newCreateElement = <K extends keyof HTMLElementTagNameMap>(tagName: K): HT
|
||||
},
|
||||
set: (value: string): void => {
|
||||
if (value) {
|
||||
value = value.replace(/file:\/\//g, "/resource");
|
||||
const resourceBaseUrl = location.pathname.replace(/\/$/, "") + "/resource";
|
||||
value = value.replace(/file:\/\//g, resourceBaseUrl);
|
||||
}
|
||||
oldSrc!.set!.call(img, value);
|
||||
},
|
||||
@@ -66,7 +67,8 @@ const newCreateElement = <K extends keyof HTMLElementTagNameMap>(tagName: K): HT
|
||||
},
|
||||
set: (value: string): void => {
|
||||
if (value) {
|
||||
value = value.replace(/file:\/\//g, "/resource");
|
||||
const resourceBaseUrl = location.pathname.replace(/\/$/, "") + "/resource";
|
||||
value = value.replace(/file:\/\//g, resourceBaseUrl);
|
||||
}
|
||||
oldInnerHtml!.set!.call(style, value);
|
||||
},
|
||||
@@ -80,7 +82,8 @@ const newCreateElement = <K extends keyof HTMLElementTagNameMap>(tagName: K): HT
|
||||
if (sheet && !overridden) {
|
||||
const oldInsertRule = sheet.insertRule;
|
||||
sheet.insertRule = (rule: string, index?: number): void => {
|
||||
rule = rule.replace(/file:\/\//g, "/resource");
|
||||
const resourceBaseUrl = location.pathname.replace(/\/$/, "") + "/resource";
|
||||
rule = rule.replace(/file:\/\//g, resourceBaseUrl);
|
||||
oldInsertRule.call(sheet, rule, index);
|
||||
};
|
||||
overridden = true;
|
||||
@@ -137,12 +140,17 @@ const newCreateElement = <K extends keyof HTMLElementTagNameMap>(tagName: K): HT
|
||||
};
|
||||
},
|
||||
});
|
||||
view.src = require("!!file-loader?name=[path][name].[ext]!./webview.html");
|
||||
Object.defineProperty(view, "src", {
|
||||
set: (): void => { /* Nope. */ },
|
||||
});
|
||||
(view as any).getWebContents = (): void => undefined; // tslint:disable-line no-any
|
||||
(view as any).send = (channel: string, ...args: any[]): void => { // tslint:disable-line no-any
|
||||
if (args[0] && typeof args[0] === "object" && args[0].contents) {
|
||||
// TODO
|
||||
args[0].contents = (args[0].contents as string).replace(/"(file:\/\/[^"]*)"/g, (m1) => `"/resource${m1}"`);
|
||||
args[0].contents = (args[0].contents as string).replace(/"vscode-resource:([^"]*)"/g, (m, m1) => `"/resource${m1}"`);
|
||||
const resourceBaseUrl = location.pathname.replace(/\/$/, "") + "/resource";
|
||||
args[0].contents = (args[0].contents as string).replace(/"(file:\/\/[^"]*)"/g, (m1) => `"${resourceBaseUrl}${m1}"`);
|
||||
args[0].contents = (args[0].contents as string).replace(/"vscode-resource:([^"]*)"/g, (m, m1) => `"${resourceBaseUrl}${m1}"`);
|
||||
args[0].contents = (args[0].contents as string).replace(/style-src vscode-core-resource:/g, "style-src 'self'");
|
||||
}
|
||||
if (view.contentWindow) {
|
||||
@@ -163,8 +171,10 @@ const newCreateElement = <K extends keyof HTMLElementTagNameMap>(tagName: K): HT
|
||||
document.createElement = newCreateElement;
|
||||
|
||||
class Clipboard {
|
||||
public has(): boolean {
|
||||
return false;
|
||||
private readonly buffers = new Map<string, Buffer>();
|
||||
|
||||
public has(format: string): boolean {
|
||||
return this.buffers.has(format);
|
||||
}
|
||||
|
||||
public readFindText(): string {
|
||||
@@ -178,6 +188,18 @@ class Clipboard {
|
||||
public writeText(value: string): Promise<void> {
|
||||
return clipboard.writeText(value);
|
||||
}
|
||||
|
||||
public readText(): Promise<string> {
|
||||
return clipboard.readText();
|
||||
}
|
||||
|
||||
public writeBuffer(format: string, buffer: Buffer): void {
|
||||
this.buffers.set(format, buffer);
|
||||
}
|
||||
|
||||
public readBuffer(format: string): Buffer | undefined {
|
||||
return this.buffers.get(format);
|
||||
}
|
||||
}
|
||||
|
||||
class Shell {
|
||||
@@ -356,14 +378,31 @@ class BrowserWindow extends EventEmitter {
|
||||
|
||||
public setFullScreen(fullscreen: boolean): void {
|
||||
if (fullscreen) {
|
||||
document.documentElement.requestFullscreen();
|
||||
document.documentElement.requestFullscreen().catch((error) => {
|
||||
logger.error(error.message);
|
||||
});
|
||||
} else {
|
||||
document.exitFullscreen();
|
||||
document.exitFullscreen().catch((error) => {
|
||||
logger.error(error.message);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public isFullScreen(): boolean {
|
||||
return document.fullscreenEnabled;
|
||||
// TypeScript doesn't recognize this property.
|
||||
// tslint:disable no-any
|
||||
if (typeof (window as any)["fullScreen"] !== "undefined") {
|
||||
return (window as any)["fullScreen"];
|
||||
}
|
||||
// tslint:enable no-any
|
||||
|
||||
try {
|
||||
return window.matchMedia("(display-mode: fullscreen)").matches;
|
||||
} catch (error) {
|
||||
logger.error(error.message);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public isFocused(): boolean {
|
||||
|
||||
@@ -35,6 +35,10 @@ class OS {
|
||||
default: this._platform = "linux"; break;
|
||||
}
|
||||
process.platform = this._platform;
|
||||
process.env = {};
|
||||
data.env.forEach((v, k) => {
|
||||
process.env[k] = v;
|
||||
});
|
||||
}
|
||||
|
||||
public release(): string {
|
||||
|
||||
8
packages/ide/src/fill/webview.html
Normal file
8
packages/ide/src/fill/webview.html
Normal file
@@ -0,0 +1,8 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" style="width: 100%; height: 100%">
|
||||
<head>
|
||||
<title>Virtual Document</title>
|
||||
</head>
|
||||
<body style="margin: 0; overflow: hidden; width: 100%; height: 100%">
|
||||
</body>
|
||||
</html>
|
||||
@@ -75,7 +75,7 @@ export class Retry {
|
||||
|
||||
// Times are in seconds.
|
||||
private readonly retryMinDelay = 1;
|
||||
private readonly retryMaxDelay = 10;
|
||||
private readonly retryMaxDelay = 3;
|
||||
private readonly maxImmediateRetries = 5;
|
||||
private readonly retryExponent = 1.5;
|
||||
private blocked: string | boolean | undefined;
|
||||
@@ -147,7 +147,7 @@ export class Retry {
|
||||
*
|
||||
* Blocking without a name will override a block with a name.
|
||||
*/
|
||||
private block(name?: string): void {
|
||||
public block(name?: string): void {
|
||||
if (!this.blocked || !name) {
|
||||
this.blocked = name || true;
|
||||
this.items.forEach((item) => {
|
||||
|
||||
@@ -5,9 +5,12 @@
|
||||
"build": "tsc -p tsconfig.build.json && cp ./out/packages/logger/src/* ./out && rm -rf out/packages && ../../node_modules/.bin/webpack --config ./webpack.config.js",
|
||||
"postinstall": "if [ ! -d out ];then npm run build; fi"
|
||||
},
|
||||
"version": "1.0.3",
|
||||
"version": "1.1.3",
|
||||
"main": "out/main.js",
|
||||
"types": "out/index.d.ts",
|
||||
"author": "Coder",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@google-cloud/logging": "^4.5.2"
|
||||
}
|
||||
}
|
||||
|
||||
12
packages/logger/src/extender.test.ts
Normal file
12
packages/logger/src/extender.test.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { field, logger } from "./logger";
|
||||
import { createStackdriverExtender } from "./extender";
|
||||
|
||||
describe("Extender", () => {
|
||||
it("should add stackdriver extender", () => {
|
||||
logger.extend(createStackdriverExtender("coder-dev-1", "logging-package-tests"));
|
||||
});
|
||||
|
||||
it("should log", async () => {
|
||||
logger.debug("Bananas!", field("frog", { hi: "wow" }));
|
||||
});
|
||||
});
|
||||
63
packages/logger/src/extender.ts
Normal file
63
packages/logger/src/extender.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
import * as gcl from "@google-cloud/logging";
|
||||
import { Extender, logger, field } from "./logger";
|
||||
|
||||
export const createStackdriverExtender = (projectId: string, logId: string): Extender => {
|
||||
enum GcpLogSeverity {
|
||||
DEFAULT = 0,
|
||||
DEBUG = 100,
|
||||
INFO = 200,
|
||||
NOTICE = 300,
|
||||
WARNING = 400,
|
||||
ERROR = 500,
|
||||
CRITICAL = 600,
|
||||
ALERT = 700,
|
||||
EMERGENCY = 800,
|
||||
}
|
||||
|
||||
const logging = new gcl.Logging({
|
||||
autoRetry: true,
|
||||
projectId,
|
||||
});
|
||||
|
||||
const log = logging.log(logId);
|
||||
const convertSeverity = (severity: "trace" | "info" | "warn" | "debug" | "error"): GcpLogSeverity => {
|
||||
switch (severity) {
|
||||
case "trace":
|
||||
case "debug":
|
||||
return GcpLogSeverity.DEBUG;
|
||||
case "info":
|
||||
return GcpLogSeverity.INFO;
|
||||
case "error":
|
||||
return GcpLogSeverity.ERROR;
|
||||
case "warn":
|
||||
return GcpLogSeverity.WARNING;
|
||||
}
|
||||
};
|
||||
|
||||
return (options): void => {
|
||||
const severity = convertSeverity(options.type);
|
||||
// tslint:disable-next-line:no-any
|
||||
const metadata = {} as any;
|
||||
if (options.fields) {
|
||||
options.fields.forEach((f) => {
|
||||
if (!f) {
|
||||
return;
|
||||
}
|
||||
metadata[f.identifier] = f.value;
|
||||
});
|
||||
}
|
||||
|
||||
const entry = log.entry({
|
||||
// tslint:disable-next-line:no-any
|
||||
severity: severity as any,
|
||||
}, {
|
||||
...metadata,
|
||||
message: options.message,
|
||||
});
|
||||
|
||||
log.write(entry).catch((ex) => {
|
||||
logger.named("GCP").error("Failed to log", field("error", ex));
|
||||
});
|
||||
};
|
||||
|
||||
};
|
||||
@@ -59,6 +59,14 @@ export const field = <T>(name: string, value: T): Field<T> => {
|
||||
return new Field(name, value);
|
||||
};
|
||||
|
||||
export type Extender = (msg: {
|
||||
message: string,
|
||||
level: Level,
|
||||
type: "trace" | "info" | "warn" | "debug" | "error",
|
||||
fields?: FieldArray,
|
||||
section?: string,
|
||||
}) => void;
|
||||
|
||||
/**
|
||||
* This formats & builds text for logging.
|
||||
* It should only be used to build one log item at a time since it stores the
|
||||
@@ -221,6 +229,7 @@ export class Logger {
|
||||
private _formatter: Formatter,
|
||||
private readonly name?: string,
|
||||
private readonly defaultFields?: FieldArray,
|
||||
private readonly extenders: Extender[] = [],
|
||||
) {
|
||||
if (name) {
|
||||
this.nameColor = this.hashStringToColor(name);
|
||||
@@ -248,6 +257,10 @@ export class Logger {
|
||||
this.muted = true;
|
||||
}
|
||||
|
||||
public extend(extender: Extender): void {
|
||||
this.extenders.push(extender);
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs information.
|
||||
*/
|
||||
@@ -328,7 +341,7 @@ export class Logger {
|
||||
* Each name is deterministically generated a color.
|
||||
*/
|
||||
public named(name: string, ...fields: FieldArray): Logger {
|
||||
const l = new Logger(this._formatter, name, fields);
|
||||
const l = new Logger(this._formatter, name, fields, this.extenders);
|
||||
if (this.muted) {
|
||||
l.mute();
|
||||
}
|
||||
@@ -393,6 +406,16 @@ export class Logger {
|
||||
console.log(...this._formatter.flush());
|
||||
}
|
||||
// tslint:enable no-console
|
||||
|
||||
this.extenders.forEach((extender) => {
|
||||
extender({
|
||||
section: this.name,
|
||||
fields: options.fields,
|
||||
level: options.level,
|
||||
message: options.message as string,
|
||||
type: options.type,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
const path = require("path");
|
||||
const merge = require("webpack-merge");
|
||||
|
||||
module.exports = merge(require(path.join(__dirname, "../../scripts", "webpack.general.config.js"))(), {
|
||||
module.exports = [
|
||||
merge(require(path.join(__dirname, "../../scripts", "webpack.general.config.js"))(), {
|
||||
devtool: "none",
|
||||
mode: "production",
|
||||
target: "node",
|
||||
@@ -13,4 +14,21 @@ module.exports = merge(require(path.join(__dirname, "../../scripts", "webpack.ge
|
||||
entry: [
|
||||
"./packages/logger/src/index.ts"
|
||||
],
|
||||
});
|
||||
}),
|
||||
merge(require(path.join(__dirname, "../../scripts", "webpack.general.config.js"))(), {
|
||||
devtool: "none",
|
||||
mode: "production",
|
||||
target: "node",
|
||||
output: {
|
||||
path: path.join(__dirname, "out"),
|
||||
filename: "extender.js",
|
||||
libraryTarget: "commonjs",
|
||||
},
|
||||
externals: {
|
||||
"@google-cloud/logging": "commonjs @google-cloud/logging",
|
||||
},
|
||||
entry: [
|
||||
"./packages/logger/src/extender.ts"
|
||||
],
|
||||
}),
|
||||
];
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -33,8 +33,7 @@
|
||||
"@coder/(.*)/test": "<rootDir>/$1/test",
|
||||
"@coder/(.*)": "<rootDir>/$1/src",
|
||||
"vs/(.*)": "<rootDir>/../lib/vscode/src/vs/$1",
|
||||
"vszip": "<rootDir>/../lib/vscode/src/vs/base/node/zip.ts",
|
||||
"^node-pty": "node-pty-prebuilt"
|
||||
"vszip": "<rootDir>/../lib/vscode/src/vs/base/node/zip.ts"
|
||||
},
|
||||
"transform": {
|
||||
"^.+\\.tsx?$": "ts-jest"
|
||||
|
||||
47
packages/protocol/README.md
Normal file
47
packages/protocol/README.md
Normal file
@@ -0,0 +1,47 @@
|
||||
# Protocol
|
||||
|
||||
This module provides a way for the browser to run Node modules like `fs`, `net`,
|
||||
etc.
|
||||
|
||||
## Internals
|
||||
|
||||
### Server-side proxies
|
||||
The server-side proxies are regular classes that call native Node functions. The
|
||||
only thing special about them is that they must return promises and they must
|
||||
return serializable values.
|
||||
|
||||
The only exception to the promise rule are event-related methods such as
|
||||
`onEvent` and `onDone` (these are synchronous). The server will simply
|
||||
immediately bind and push all events it can to the client. It doesn't wait for
|
||||
the client to start listening. This prevents issues with the server not
|
||||
receiving the client's request to start listening in time.
|
||||
|
||||
However, there is a way to specify events that should not bind immediately and
|
||||
should wait for the client to request it, because some events (like `data` on a
|
||||
stream) cannot be bound immediately (because doing so changes how the stream
|
||||
behaves).
|
||||
|
||||
### Client-side proxies
|
||||
Client-side proxies are `Proxy` instances. They simply make remote calls for any
|
||||
method you call on it. The only exception is for events. Each client proxy has a
|
||||
local emitter which it uses in place of a remote call (this allows the call to
|
||||
be completed synchronously on the client). Then when an event is received from
|
||||
the server, it gets emitted on that local emitter.
|
||||
|
||||
When an event is listened to, the proxy also notifies the server so it can start
|
||||
listening in case it isn't already (see the `data` example above). This only
|
||||
works for events that only fire after they are bound.
|
||||
|
||||
### Client-side fills
|
||||
The client-side fills implement the Node API and make calls to the server-side
|
||||
proxies using the client-side proxies.
|
||||
|
||||
When a proxy returns a proxy (for example `fs.createWriteStream`), that proxy is
|
||||
a promise (since communicating with the server is asynchronous). We have to
|
||||
return the fill from `fs.createWriteStream` synchronously, so that means the
|
||||
fill has to contain a proxy promise. To eliminate the need for calling `then`
|
||||
and to keep the code looking clean every time you use the proxy, the proxy is
|
||||
itself wrapped in another proxy which just calls the method after a `then`. This
|
||||
works since all the methods return promises (aside from the event methods, but
|
||||
those are not used by the fills directly—they are only used internally to
|
||||
forward events to the fill if it is an event emitter).
|
||||
@@ -4,8 +4,6 @@
|
||||
"dependencies": {
|
||||
"express": "^4.16.4",
|
||||
"google-protobuf": "^3.6.1",
|
||||
"node-pty-prebuilt": "^0.7.6",
|
||||
"spdlog": "^0.7.2",
|
||||
"trash": "^4.3.0",
|
||||
"ws": "^6.1.2"
|
||||
},
|
||||
@@ -16,5 +14,8 @@
|
||||
"rimraf": "^2.6.3",
|
||||
"text-encoding": "^0.7.0",
|
||||
"ts-protoc-gen": "^0.8.0"
|
||||
},
|
||||
"scripts": {
|
||||
"gen": "./scripts/generate_proto.sh"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#!/bin/bash
|
||||
|
||||
cd "$(dirname "$0")/.."
|
||||
|
||||
protoc --plugin="protoc-gen-ts=./node_modules/.bin/protoc-gen-ts" --js_out="import_style=commonjs,binary:./src/proto" --ts_out="./src/proto" ./src/proto/*.proto --proto_path="./src/proto"
|
||||
@@ -4,7 +4,7 @@ import { promisify } from "util";
|
||||
import { Emitter } from "@coder/events";
|
||||
import { logger, field } from "@coder/logger";
|
||||
import { ReadWriteConnection, InitData, SharedProcessData } from "../common/connection";
|
||||
import { Module, ServerProxy } from "../common/proxy";
|
||||
import { ClientServerProxy, Module, ServerProxy } from "../common/proxy";
|
||||
import { argumentToProto, protoToArgument, moduleToProto, protoToModule, protoToOperatingSystem } from "../common/util";
|
||||
import { Argument, Ping, ServerMessage, ClientMessage, Method, Event, Callback } from "../proto";
|
||||
import { FsModule, ChildProcessModule, NetModule, NodePtyModule, SpdlogModule, TrashModule } from "./modules";
|
||||
@@ -174,9 +174,10 @@ export class Client {
|
||||
* Make a remote call for a proxy's method using proto.
|
||||
*/
|
||||
private remoteCall(proxyId: number | Module, method: string, args: any[]): Promise<any> {
|
||||
if (this.disconnected && typeof proxyId === "number") {
|
||||
// Can assume killing or closing works because a disconnected proxy
|
||||
// is disposed on the server's side.
|
||||
if (typeof proxyId === "number" && (this.disconnected || !this.proxies.has(proxyId))) {
|
||||
// Can assume killing or closing works because a disconnected proxy is
|
||||
// disposed on the server's side, and a non-existent proxy has already
|
||||
// been disposed.
|
||||
switch (method) {
|
||||
case "close":
|
||||
case "kill":
|
||||
@@ -223,7 +224,11 @@ export class Client {
|
||||
field("method", method),
|
||||
]);
|
||||
|
||||
proxyMessage.setArgsList(args.map((a) => argumentToProto(a, storeCallback)));
|
||||
proxyMessage.setArgsList(args.map((a) => argumentToProto<ClientServerProxy>(
|
||||
a,
|
||||
storeCallback,
|
||||
(p) => p.proxyId,
|
||||
)));
|
||||
|
||||
const clientMessage = new ClientMessage();
|
||||
clientMessage.setMethod(message);
|
||||
@@ -273,6 +278,9 @@ export class Client {
|
||||
shell: init.getShell(),
|
||||
extensionsDirectory: init.getExtensionsDirectory(),
|
||||
builtInExtensionsDirectory: init.getBuiltinExtensionsDir(),
|
||||
extraExtensionDirectories: init.getExtraExtensionDirectoriesList(),
|
||||
extraBuiltinExtensionDirectories: init.getExtraBuiltinExtensionDirectoriesList(),
|
||||
env: init.getEnvMap(),
|
||||
};
|
||||
this.initDataEmitter.emit(this._initData);
|
||||
break;
|
||||
@@ -428,7 +436,7 @@ export class Client {
|
||||
/**
|
||||
* Return a proxy that makes remote calls.
|
||||
*/
|
||||
private createProxy<T>(proxyId: number | Module, promise: Promise<any> = Promise.resolve()): T {
|
||||
private createProxy<T extends ClientServerProxy>(proxyId: number | Module, promise: Promise<any> = Promise.resolve()): T {
|
||||
logger.trace(() => [
|
||||
"creating proxy",
|
||||
field("proxyId", proxyId),
|
||||
@@ -448,7 +456,7 @@ export class Client {
|
||||
cb(event.event, ...event.args);
|
||||
});
|
||||
},
|
||||
}, {
|
||||
} as ClientServerProxy, {
|
||||
get: (target: any, name: string): any => {
|
||||
// When resolving a promise with a proxy, it will check for "then".
|
||||
if (name === "then") {
|
||||
|
||||
@@ -2,13 +2,22 @@ import * as cp from "child_process";
|
||||
import * as net from "net";
|
||||
import * as stream from "stream";
|
||||
import { callbackify } from "util";
|
||||
import { ClientProxy } from "../../common/proxy";
|
||||
import { ChildProcessModuleProxy, ChildProcessProxy, ChildProcessProxies } from "../../node/modules/child_process";
|
||||
import { Readable, Writable } from "./stream";
|
||||
import { ClientProxy, ClientServerProxy } from "../../common/proxy";
|
||||
import { ChildProcessModuleProxy, ChildProcessProxy } from "../../node/modules/child_process";
|
||||
import { ClientWritableProxy, ClientReadableProxy, Readable, Writable } from "./stream";
|
||||
|
||||
// tslint:disable completed-docs
|
||||
|
||||
export class ChildProcess extends ClientProxy<ChildProcessProxy> implements cp.ChildProcess {
|
||||
export interface ClientChildProcessProxy extends ChildProcessProxy, ClientServerProxy<cp.ChildProcess> {}
|
||||
|
||||
export interface ClientChildProcessProxies {
|
||||
childProcess: ClientChildProcessProxy;
|
||||
stdin?: ClientWritableProxy | null;
|
||||
stdout?: ClientReadableProxy | null;
|
||||
stderr?: ClientReadableProxy | null;
|
||||
}
|
||||
|
||||
export class ChildProcess extends ClientProxy<ClientChildProcessProxy> implements cp.ChildProcess {
|
||||
public readonly stdin: stream.Writable;
|
||||
public readonly stdout: stream.Readable;
|
||||
public readonly stderr: stream.Readable;
|
||||
@@ -18,7 +27,7 @@ export class ChildProcess extends ClientProxy<ChildProcessProxy> implements cp.C
|
||||
private _killed: boolean = false;
|
||||
private _pid = -1;
|
||||
|
||||
public constructor(proxyPromises: Promise<ChildProcessProxies>) {
|
||||
public constructor(proxyPromises: Promise<ClientChildProcessProxies>) {
|
||||
super(proxyPromises.then((p) => p.childProcess));
|
||||
this.stdin = new Writable(proxyPromises.then((p) => p.stdin!));
|
||||
this.stdout = new Readable(proxyPromises.then((p) => p.stdout!));
|
||||
@@ -99,8 +108,14 @@ export class ChildProcess extends ClientProxy<ChildProcessProxy> implements cp.C
|
||||
}
|
||||
}
|
||||
|
||||
interface ClientChildProcessModuleProxy extends ChildProcessModuleProxy, ClientServerProxy {
|
||||
exec(command: string, options?: { encoding?: string | null } & cp.ExecOptions | null, callback?: ((error: cp.ExecException | null, stdin: string | Buffer, stdout: string | Buffer) => void)): Promise<ClientChildProcessProxies>;
|
||||
fork(modulePath: string, args?: string[], options?: cp.ForkOptions): Promise<ClientChildProcessProxies>;
|
||||
spawn(command: string, args?: string[], options?: cp.SpawnOptions): Promise<ClientChildProcessProxies>;
|
||||
}
|
||||
|
||||
export class ChildProcessModule {
|
||||
public constructor(private readonly proxy: ChildProcessModuleProxy) {}
|
||||
public constructor(private readonly proxy: ClientChildProcessModuleProxy) {}
|
||||
|
||||
public exec = (
|
||||
command: string,
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import * as fs from "fs";
|
||||
import { callbackify } from "util";
|
||||
import { ClientProxy, Batch } from "../../common/proxy";
|
||||
import { Batch, ClientProxy, ClientServerProxy } from "../../common/proxy";
|
||||
import { IEncodingOptions, IEncodingOptionsCallback } from "../../common/util";
|
||||
import { FsModuleProxy, Stats as IStats, WatcherProxy, WriteStreamProxy } from "../../node/modules/fs";
|
||||
import { Writable } from "./stream";
|
||||
import { FsModuleProxy, ReadStreamProxy, Stats as IStats, WatcherProxy, WriteStreamProxy } from "../../node/modules/fs";
|
||||
import { Readable, Writable } from "./stream";
|
||||
|
||||
// tslint:disable no-any
|
||||
// tslint:disable completed-docs
|
||||
// tslint:disable completed-docs no-any
|
||||
|
||||
class StatBatch extends Batch<IStats, { path: fs.PathLike }> {
|
||||
public constructor(private readonly proxy: FsModuleProxy) {
|
||||
@@ -38,7 +37,9 @@ class ReaddirBatch extends Batch<Buffer[] | fs.Dirent[] | string[], { path: fs.P
|
||||
}
|
||||
}
|
||||
|
||||
class Watcher extends ClientProxy<WatcherProxy> implements fs.FSWatcher {
|
||||
interface ClientWatcherProxy extends WatcherProxy, ClientServerProxy<fs.FSWatcher> {}
|
||||
|
||||
class Watcher extends ClientProxy<ClientWatcherProxy> implements fs.FSWatcher {
|
||||
public close(): void {
|
||||
this.catch(this.proxy.close());
|
||||
}
|
||||
@@ -48,7 +49,25 @@ class Watcher extends ClientProxy<WatcherProxy> implements fs.FSWatcher {
|
||||
}
|
||||
}
|
||||
|
||||
class WriteStream extends Writable<WriteStreamProxy> implements fs.WriteStream {
|
||||
interface ClientReadStreamProxy extends ReadStreamProxy, ClientServerProxy<fs.ReadStream> {}
|
||||
|
||||
class ReadStream extends Readable<ClientReadStreamProxy> implements fs.ReadStream {
|
||||
public get bytesRead(): number {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public get path(): string | Buffer {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public close(): void {
|
||||
this.catch(this.proxy.close());
|
||||
}
|
||||
}
|
||||
|
||||
interface ClientWriteStreamProxy extends WriteStreamProxy, ClientServerProxy<fs.WriteStream> {}
|
||||
|
||||
class WriteStream extends Writable<ClientWriteStreamProxy> implements fs.WriteStream {
|
||||
public get bytesWritten(): number {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
@@ -62,12 +81,18 @@ class WriteStream extends Writable<WriteStreamProxy> implements fs.WriteStream {
|
||||
}
|
||||
}
|
||||
|
||||
interface ClientFsModuleProxy extends FsModuleProxy, ClientServerProxy {
|
||||
createReadStream(path: fs.PathLike, options?: any): Promise<ClientReadStreamProxy>;
|
||||
createWriteStream(path: fs.PathLike, options?: any): Promise<ClientWriteStreamProxy>;
|
||||
watch(filename: fs.PathLike, options?: IEncodingOptions): Promise<ClientWatcherProxy>;
|
||||
}
|
||||
|
||||
export class FsModule {
|
||||
private readonly statBatch: StatBatch;
|
||||
private readonly lstatBatch: LstatBatch;
|
||||
private readonly readdirBatch: ReaddirBatch;
|
||||
|
||||
public constructor(private readonly proxy: FsModuleProxy) {
|
||||
public constructor(private readonly proxy: ClientFsModuleProxy) {
|
||||
this.statBatch = new StatBatch(this.proxy);
|
||||
this.lstatBatch = new LstatBatch(this.proxy);
|
||||
this.readdirBatch = new ReaddirBatch(this.proxy);
|
||||
@@ -110,6 +135,10 @@ export class FsModule {
|
||||
);
|
||||
}
|
||||
|
||||
public createReadStream = (path: fs.PathLike, options?: any): fs.ReadStream => {
|
||||
return new ReadStream(this.proxy.createReadStream(path, options));
|
||||
}
|
||||
|
||||
public createWriteStream = (path: fs.PathLike, options?: any): fs.WriteStream => {
|
||||
return new WriteStream(this.proxy.createWriteStream(path, options));
|
||||
}
|
||||
@@ -317,17 +346,7 @@ export class FsModule {
|
||||
}
|
||||
|
||||
class Stats implements fs.Stats {
|
||||
public readonly atime: Date;
|
||||
public readonly mtime: Date;
|
||||
public readonly ctime: Date;
|
||||
public readonly birthtime: Date;
|
||||
|
||||
public constructor(private readonly stats: IStats) {
|
||||
this.atime = new Date(stats.atime);
|
||||
this.mtime = new Date(stats.mtime);
|
||||
this.ctime = new Date(stats.ctime);
|
||||
this.birthtime = new Date(stats.birthtime);
|
||||
}
|
||||
public constructor(private readonly stats: IStats) {}
|
||||
|
||||
public get dev(): number { return this.stats.dev; }
|
||||
public get ino(): number { return this.stats.ino; }
|
||||
@@ -339,6 +358,10 @@ class Stats implements fs.Stats {
|
||||
public get size(): number { return this.stats.size; }
|
||||
public get blksize(): number { return this.stats.blksize; }
|
||||
public get blocks(): number { return this.stats.blocks; }
|
||||
public get atime(): Date { return this.stats.atime; }
|
||||
public get mtime(): Date { return this.stats.mtime; }
|
||||
public get ctime(): Date { return this.stats.ctime; }
|
||||
public get birthtime(): Date { return this.stats.birthtime; }
|
||||
public get atimeMs(): number { return this.stats.atimeMs; }
|
||||
public get mtimeMs(): number { return this.stats.mtimeMs; }
|
||||
public get ctimeMs(): number { return this.stats.ctimeMs; }
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
import * as net from "net";
|
||||
import { callbackify } from "util";
|
||||
import { ClientProxy } from "../../common/proxy";
|
||||
import { ClientProxy, ClientServerProxy } from "../../common/proxy";
|
||||
import { NetModuleProxy, NetServerProxy, NetSocketProxy } from "../../node/modules/net";
|
||||
import { Duplex } from "./stream";
|
||||
|
||||
// tslint:disable completed-docs
|
||||
|
||||
export class Socket extends Duplex<NetSocketProxy> implements net.Socket {
|
||||
interface ClientNetSocketProxy extends NetSocketProxy, ClientServerProxy<net.Socket> {}
|
||||
|
||||
export class Socket extends Duplex<ClientNetSocketProxy> implements net.Socket {
|
||||
private _connecting: boolean = false;
|
||||
private _destroyed: boolean = false;
|
||||
|
||||
public constructor(proxyPromise: Promise<NetSocketProxy> | NetSocketProxy, connecting?: boolean) {
|
||||
public constructor(proxyPromise: Promise<ClientNetSocketProxy> | ClientNetSocketProxy, connecting?: boolean) {
|
||||
super(proxyPromise);
|
||||
if (connecting) {
|
||||
this._connecting = connecting;
|
||||
@@ -126,12 +128,16 @@ export class Socket extends Duplex<NetSocketProxy> implements net.Socket {
|
||||
}
|
||||
}
|
||||
|
||||
export class Server extends ClientProxy<NetServerProxy> implements net.Server {
|
||||
interface ClientNetServerProxy extends NetServerProxy, ClientServerProxy<net.Server> {
|
||||
onConnection(cb: (proxy: ClientNetSocketProxy) => void): Promise<void>;
|
||||
}
|
||||
|
||||
export class Server extends ClientProxy<ClientNetServerProxy> implements net.Server {
|
||||
private socketId = 0;
|
||||
private readonly sockets = new Map<number, net.Socket>();
|
||||
private _listening: boolean = false;
|
||||
|
||||
public constructor(proxyPromise: Promise<NetServerProxy> | NetServerProxy) {
|
||||
public constructor(proxyPromise: Promise<ClientNetServerProxy> | ClientNetServerProxy) {
|
||||
super(proxyPromise);
|
||||
|
||||
this.catch(this.proxy.onConnection((socketProxy) => {
|
||||
@@ -208,11 +214,17 @@ export class Server extends ClientProxy<NetServerProxy> implements net.Server {
|
||||
|
||||
type NodeNet = typeof net;
|
||||
|
||||
interface ClientNetModuleProxy extends NetModuleProxy, ClientServerProxy {
|
||||
createSocket(options?: net.SocketConstructorOpts): Promise<ClientNetSocketProxy>;
|
||||
createConnection(target: string | number | net.NetConnectOpts, host?: string): Promise<ClientNetSocketProxy>;
|
||||
createServer(options?: { allowHalfOpen?: boolean, pauseOnConnect?: boolean }): Promise<ClientNetServerProxy>;
|
||||
}
|
||||
|
||||
export class NetModule implements NodeNet {
|
||||
public readonly Socket: typeof net.Socket;
|
||||
public readonly Server: typeof net.Server;
|
||||
|
||||
public constructor(private readonly proxy: NetModuleProxy) {
|
||||
public constructor(private readonly proxy: ClientNetModuleProxy) {
|
||||
// @ts-ignore this is because Socket is missing things from the Stream
|
||||
// namespace but I'm unsure how best to provide them (finished,
|
||||
// finished.__promisify__, pipeline, and some others) or if it even matters.
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
import * as pty from "node-pty";
|
||||
import { ClientProxy } from "../../common/proxy";
|
||||
import { ClientProxy, ClientServerProxy } from "../../common/proxy";
|
||||
import { NodePtyModuleProxy, NodePtyProcessProxy } from "../../node/modules/node-pty";
|
||||
|
||||
// tslint:disable completed-docs
|
||||
|
||||
export class NodePtyProcess extends ClientProxy<NodePtyProcessProxy> implements pty.IPty {
|
||||
interface ClientNodePtyProcessProxy extends NodePtyProcessProxy, ClientServerProxy {}
|
||||
|
||||
export class NodePtyProcess extends ClientProxy<ClientNodePtyProcessProxy> implements pty.IPty {
|
||||
private _pid = -1;
|
||||
private _process = "";
|
||||
private lastCols: number | undefined;
|
||||
private lastRows: number | undefined;
|
||||
|
||||
public constructor(
|
||||
private readonly moduleProxy: NodePtyModuleProxy,
|
||||
private readonly moduleProxy: ClientNodePtyModuleProxy,
|
||||
private readonly file: string,
|
||||
private readonly args: string[] | string,
|
||||
private readonly options: pty.IPtyForkOptions,
|
||||
@@ -18,10 +22,12 @@ export class NodePtyProcess extends ClientProxy<NodePtyProcessProxy> implements
|
||||
this.on("process", (process) => this._process = process);
|
||||
}
|
||||
|
||||
protected initialize(proxyPromise: Promise<NodePtyProcessProxy>): void {
|
||||
super.initialize(proxyPromise);
|
||||
protected initialize(proxyPromise: Promise<ClientNodePtyProcessProxy>): ClientNodePtyProcessProxy {
|
||||
const proxy = super.initialize(proxyPromise);
|
||||
this.catch(this.proxy.getPid().then((p) => this._pid = p));
|
||||
this.catch(this.proxy.getProcess().then((p) => this._process = p));
|
||||
|
||||
return proxy;
|
||||
}
|
||||
|
||||
public get pid(): number {
|
||||
@@ -33,6 +39,9 @@ export class NodePtyProcess extends ClientProxy<NodePtyProcessProxy> implements
|
||||
}
|
||||
|
||||
public resize(columns: number, rows: number): void {
|
||||
this.lastCols = columns;
|
||||
this.lastRows = rows;
|
||||
|
||||
this.catch(this.proxy.resize(columns, rows));
|
||||
}
|
||||
|
||||
@@ -47,14 +56,22 @@ export class NodePtyProcess extends ClientProxy<NodePtyProcessProxy> implements
|
||||
protected handleDisconnect(): void {
|
||||
this._process += " (disconnected)";
|
||||
this.emit("data", "\r\n\nLost connection...\r\n\n");
|
||||
this.initialize(this.moduleProxy.spawn(this.file, this.args, this.options));
|
||||
this.initialize(this.moduleProxy.spawn(this.file, this.args, {
|
||||
...this.options,
|
||||
cols: this.lastCols || this.options.cols,
|
||||
rows: this.lastRows || this.options.rows,
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
type NodePty = typeof pty;
|
||||
|
||||
interface ClientNodePtyModuleProxy extends NodePtyModuleProxy, ClientServerProxy {
|
||||
spawn(file: string, args: string[] | string, options: pty.IPtyForkOptions): Promise<ClientNodePtyProcessProxy>;
|
||||
}
|
||||
|
||||
export class NodePtyModule implements NodePty {
|
||||
public constructor(private readonly proxy: NodePtyModuleProxy) {}
|
||||
public constructor(private readonly proxy: ClientNodePtyModuleProxy) {}
|
||||
|
||||
public spawn = (file: string, args: string[] | string, options: pty.IPtyForkOptions): pty.IPty => {
|
||||
return new NodePtyProcess(this.proxy, file, args, options);
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import * as spdlog from "spdlog";
|
||||
import { ClientProxy } from "../../common/proxy";
|
||||
import { ClientProxy, ClientServerProxy } from "../../common/proxy";
|
||||
import { RotatingLoggerProxy, SpdlogModuleProxy } from "../../node/modules/spdlog";
|
||||
|
||||
// tslint:disable completed-docs
|
||||
|
||||
class RotatingLogger extends ClientProxy<RotatingLoggerProxy> implements spdlog.RotatingLogger {
|
||||
interface ClientRotatingLoggerProxy extends RotatingLoggerProxy, ClientServerProxy {}
|
||||
|
||||
class RotatingLogger extends ClientProxy<ClientRotatingLoggerProxy> implements spdlog.RotatingLogger {
|
||||
public constructor(
|
||||
private readonly moduleProxy: SpdlogModuleProxy,
|
||||
private readonly moduleProxy: ClientSpdlogModuleProxy,
|
||||
private readonly name: string,
|
||||
private readonly filename: string,
|
||||
private readonly filesize: number,
|
||||
@@ -31,10 +33,14 @@ class RotatingLogger extends ClientProxy<RotatingLoggerProxy> implements spdlog.
|
||||
}
|
||||
}
|
||||
|
||||
interface ClientSpdlogModuleProxy extends SpdlogModuleProxy, ClientServerProxy {
|
||||
createLogger(name: string, filePath: string, fileSize: number, fileCount: number): Promise<ClientRotatingLoggerProxy>;
|
||||
}
|
||||
|
||||
export class SpdlogModule {
|
||||
public readonly RotatingLogger: typeof spdlog.RotatingLogger;
|
||||
|
||||
public constructor(private readonly proxy: SpdlogModuleProxy) {
|
||||
public constructor(private readonly proxy: ClientSpdlogModuleProxy) {
|
||||
this.RotatingLogger = class extends RotatingLogger {
|
||||
public constructor(name: string, filename: string, filesize: number, filecount: number) {
|
||||
super(proxy, name, filename, filesize, filecount);
|
||||
@@ -45,4 +51,12 @@ export class SpdlogModule {
|
||||
public setAsyncMode = (bufferSize: number, flushInterval: number): Promise<void> => {
|
||||
return this.proxy.setAsyncMode(bufferSize, flushInterval);
|
||||
}
|
||||
|
||||
public createRotatingLogger(name: string, filename: string, filesize: number, filecount: number): RotatingLogger {
|
||||
return new RotatingLogger(this.proxy, name, filename, filesize, filecount);
|
||||
}
|
||||
|
||||
public createRotatingLoggerAsync(name: string, filename: string, filesize: number, filecount: number): Promise<RotatingLogger> {
|
||||
return Promise.resolve(this.createRotatingLogger(name, filename, filesize, filecount));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
import * as stream from "stream";
|
||||
import { callbackify } from "util";
|
||||
import { ClientProxy } from "../../common/proxy";
|
||||
import { DuplexProxy, IReadableProxy, WritableProxy } from "../../node/modules/stream";
|
||||
import { ClientProxy, ClientServerProxy } from "../../common/proxy";
|
||||
import { isPromise } from "../../common/util";
|
||||
import { DuplexProxy, ReadableProxy, WritableProxy } from "../../node/modules/stream";
|
||||
|
||||
// tslint:disable completed-docs
|
||||
// tslint:disable completed-docs no-any
|
||||
|
||||
export class Writable<T extends WritableProxy = WritableProxy> extends ClientProxy<T> implements stream.Writable {
|
||||
export interface ClientWritableProxy extends WritableProxy, ClientServerProxy<stream.Writable> {}
|
||||
|
||||
export class Writable<T extends ClientWritableProxy = ClientWritableProxy> extends ClientProxy<T> implements stream.Writable {
|
||||
public get writable(): boolean {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
@@ -50,7 +53,6 @@ export class Writable<T extends WritableProxy = WritableProxy> extends ClientPro
|
||||
return this.catch(this.proxy.setDefaultEncoding(encoding));
|
||||
}
|
||||
|
||||
// tslint:disable-next-line no-any
|
||||
public write(chunk: any, encoding?: string | ((error?: Error | null) => void), callback?: (error?: Error | null) => void): boolean {
|
||||
if (typeof encoding === "function") {
|
||||
callback = encoding;
|
||||
@@ -65,7 +67,6 @@ export class Writable<T extends WritableProxy = WritableProxy> extends ClientPro
|
||||
return true; // Always true since we can't get this synchronously.
|
||||
}
|
||||
|
||||
// tslint:disable-next-line no-any
|
||||
public end(data?: any | (() => void), encoding?: string | (() => void), callback?: (() => void)): void {
|
||||
if (typeof data === "function") {
|
||||
callback = data;
|
||||
@@ -88,7 +89,9 @@ export class Writable<T extends WritableProxy = WritableProxy> extends ClientPro
|
||||
}
|
||||
}
|
||||
|
||||
export class Readable<T extends IReadableProxy = IReadableProxy> extends ClientProxy<T> implements stream.Readable {
|
||||
export interface ClientReadableProxy extends ReadableProxy, ClientServerProxy<stream.Readable> {}
|
||||
|
||||
export class Readable<T extends ClientReadableProxy = ClientReadableProxy> extends ClientProxy<T> implements stream.Readable {
|
||||
public get readable(): boolean {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
@@ -141,11 +144,20 @@ export class Readable<T extends IReadableProxy = IReadableProxy> extends ClientP
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public pipe<T>(): T {
|
||||
throw new Error("not implemented");
|
||||
public pipe<P extends NodeJS.WritableStream>(destination: P, options?: { end?: boolean }): P {
|
||||
const writableProxy = (destination as any as Writable).proxyPromise;
|
||||
if (!writableProxy) {
|
||||
throw new Error("can only pipe stream proxies");
|
||||
}
|
||||
this.catch(
|
||||
isPromise(writableProxy)
|
||||
? writableProxy.then((p) => this.proxy.pipe(p, options))
|
||||
: this.proxy.pipe(writableProxy, options),
|
||||
);
|
||||
|
||||
return destination;
|
||||
}
|
||||
|
||||
// tslint:disable-next-line no-any
|
||||
public [Symbol.asyncIterator](): AsyncIterableIterator<any> {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
@@ -164,7 +176,9 @@ export class Readable<T extends IReadableProxy = IReadableProxy> extends ClientP
|
||||
}
|
||||
}
|
||||
|
||||
export class Duplex<T extends DuplexProxy = DuplexProxy> extends Writable<T> implements stream.Duplex, stream.Readable {
|
||||
export interface ClientDuplexProxy extends DuplexProxy, ClientServerProxy<stream.Duplex> {}
|
||||
|
||||
export class Duplex<T extends ClientDuplexProxy = ClientDuplexProxy> extends Writable<T> implements stream.Duplex, stream.Readable {
|
||||
private readonly _readable: Readable;
|
||||
|
||||
public constructor(proxyPromise: Promise<T> | T) {
|
||||
@@ -228,7 +242,6 @@ export class Duplex<T extends DuplexProxy = DuplexProxy> extends Writable<T> imp
|
||||
this._readable.unshift();
|
||||
}
|
||||
|
||||
// tslint:disable-next-line no-any
|
||||
public [Symbol.asyncIterator](): AsyncIterableIterator<any> {
|
||||
return this._readable[Symbol.asyncIterator]();
|
||||
}
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
import * as trash from "trash";
|
||||
import { ClientServerProxy } from "../../common/proxy";
|
||||
import { TrashModuleProxy } from "../../node/modules/trash";
|
||||
|
||||
// tslint:disable completed-docs
|
||||
|
||||
interface ClientTrashModuleProxy extends TrashModuleProxy, ClientServerProxy {}
|
||||
|
||||
export class TrashModule {
|
||||
public constructor(private readonly proxy: TrashModuleProxy) {}
|
||||
public constructor(private readonly proxy: ClientTrashModuleProxy) {}
|
||||
|
||||
public trash = (path: string, options?: trash.Options): Promise<void> => {
|
||||
return this.proxy.trash(path, options);
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import * as jspb from "google-protobuf";
|
||||
|
||||
export interface SendableConnection {
|
||||
send(data: Buffer | Uint8Array): void;
|
||||
}
|
||||
@@ -25,6 +27,9 @@ export interface InitData {
|
||||
readonly shell: string;
|
||||
readonly extensionsDirectory: string;
|
||||
readonly builtInExtensionsDirectory: string;
|
||||
readonly extraExtensionDirectories: string[];
|
||||
readonly extraBuiltinExtensionDirectories: string[];
|
||||
readonly env: jspb.Map<string, string>;
|
||||
}
|
||||
|
||||
export interface SharedProcessData {
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { EventEmitter } from "events";
|
||||
import { isPromise } from "./util";
|
||||
import { isPromise, EventCallback } from "./util";
|
||||
|
||||
// tslint:disable no-any
|
||||
|
||||
/**
|
||||
* Allow using a proxy like it's returned synchronously. This only works because
|
||||
* all proxy methods return promises.
|
||||
* all proxy methods must return promises.
|
||||
*/
|
||||
const unpromisify = <T extends ServerProxy>(proxyPromise: Promise<T>): T => {
|
||||
const unpromisify = <T extends ClientServerProxy>(proxyPromise: Promise<T>): T => {
|
||||
return new Proxy({}, {
|
||||
get: (target: any, name: string): any => {
|
||||
if (typeof target[name] === "undefined") {
|
||||
@@ -24,23 +24,23 @@ const unpromisify = <T extends ServerProxy>(proxyPromise: Promise<T>): T => {
|
||||
};
|
||||
|
||||
/**
|
||||
* Client-side emitter that just forwards proxy events to its own emitter.
|
||||
* It also turns a promisified proxy into a non-promisified proxy so we don't
|
||||
* need a bunch of `then` calls everywhere.
|
||||
* Client-side emitter that just forwards server proxy events to its own
|
||||
* emitter. It also turns a promisified server proxy into a non-promisified
|
||||
* proxy so we don't need a bunch of `then` calls everywhere.
|
||||
*/
|
||||
export abstract class ClientProxy<T extends ServerProxy> extends EventEmitter {
|
||||
private _proxy: T | undefined;
|
||||
export abstract class ClientProxy<T extends ClientServerProxy> extends EventEmitter {
|
||||
private _proxy: T;
|
||||
|
||||
/**
|
||||
* You can specify not to bind events in order to avoid emitting twice for
|
||||
* duplex streams.
|
||||
*/
|
||||
public constructor(
|
||||
proxyPromise: Promise<T> | T,
|
||||
private _proxyPromise: Promise<T> | T,
|
||||
private readonly bindEvents: boolean = true,
|
||||
) {
|
||||
super();
|
||||
this.initialize(proxyPromise);
|
||||
this._proxy = this.initialize(this._proxyPromise);
|
||||
if (this.bindEvents) {
|
||||
this.on("disconnected", (error) => {
|
||||
try {
|
||||
@@ -53,11 +53,45 @@ export abstract class ClientProxy<T extends ServerProxy> extends EventEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
protected get proxy(): T {
|
||||
if (!this._proxy) {
|
||||
throw new Error("not initialized");
|
||||
/**
|
||||
* Remove an event listener.
|
||||
*/
|
||||
public off(event: string, cb: (...args: any[]) => void): this {
|
||||
// Fill it here because the fill we're using to provide EventEmitter for the
|
||||
// browser doesn't appear to include `off`.
|
||||
this.removeListener(event, cb);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind the event locally and ensure the event is bound on the server.
|
||||
*/
|
||||
public addListener(event: string, listener: (...args: any[]) => void): this {
|
||||
this.catch(this.proxy.bindDelayedEvent(event));
|
||||
|
||||
return super.on(event, listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias for `addListener`.
|
||||
*/
|
||||
public on(event: string, listener: (...args: any[]) => void): this {
|
||||
return this.addListener(event, listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Original promise for the server proxy. Can be used to be passed as an
|
||||
* argument.
|
||||
*/
|
||||
public get proxyPromise(): Promise<T> | T {
|
||||
return this._proxyPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Server proxy.
|
||||
*/
|
||||
protected get proxy(): T {
|
||||
return this._proxy;
|
||||
}
|
||||
|
||||
@@ -65,13 +99,18 @@ export abstract class ClientProxy<T extends ServerProxy> extends EventEmitter {
|
||||
* Initialize the proxy by unpromisifying if necessary and binding to its
|
||||
* events.
|
||||
*/
|
||||
protected initialize(proxyPromise: Promise<T> | T): void {
|
||||
this._proxy = isPromise(proxyPromise) ? unpromisify(proxyPromise) : proxyPromise;
|
||||
protected initialize(proxyPromise: Promise<T> | T): T {
|
||||
this._proxyPromise = proxyPromise;
|
||||
this._proxy = isPromise(this._proxyPromise)
|
||||
? unpromisify(this._proxyPromise)
|
||||
: this._proxyPromise;
|
||||
if (this.bindEvents) {
|
||||
this.catch(this.proxy.onEvent((event, ...args): void => {
|
||||
this.proxy.onEvent((event, ...args): void => {
|
||||
this.emit(event, ...args);
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
return this._proxy;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -91,34 +130,107 @@ export abstract class ClientProxy<T extends ServerProxy> extends EventEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
export interface ServerProxyOptions<T> {
|
||||
/**
|
||||
* Proxy to the actual instance on the server. Every method must only accept
|
||||
* serializable arguments and must return promises with serializable values. If
|
||||
* a proxy itself has proxies on creation (like how ChildProcess has stdin),
|
||||
* The events to bind immediately.
|
||||
*/
|
||||
bindEvents: string[];
|
||||
/**
|
||||
* Events that signal the proxy is done.
|
||||
*/
|
||||
doneEvents: string[];
|
||||
/**
|
||||
* Events that should only be bound when asked
|
||||
*/
|
||||
delayedEvents?: string[];
|
||||
/**
|
||||
* Whatever is emitting events (stream, child process, etc).
|
||||
*/
|
||||
instance: T;
|
||||
}
|
||||
|
||||
/**
|
||||
* The actual proxy instance on the server. Every method must only accept
|
||||
* serializable arguments and must return promises with serializable values.
|
||||
*
|
||||
* If a proxy itself has proxies on creation (like how ChildProcess has stdin),
|
||||
* then it should return all of those at once, otherwise you will miss events
|
||||
* from those child proxies and fail to dispose them properly.
|
||||
*
|
||||
* Events listeners are added client-side (since all events automatically
|
||||
* forward to the client), so onDone and onEvent do not need to be asynchronous.
|
||||
*/
|
||||
export interface ServerProxy {
|
||||
export abstract class ServerProxy<T extends EventEmitter = EventEmitter> {
|
||||
public readonly instance: T;
|
||||
|
||||
private readonly callbacks = <EventCallback[]>[];
|
||||
|
||||
public constructor(private readonly options: ServerProxyOptions<T>) {
|
||||
this.instance = options.instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispose the proxy.
|
||||
*/
|
||||
dispose(): Promise<void>;
|
||||
public async dispose(): Promise<void> {
|
||||
this.instance.removeAllListeners();
|
||||
}
|
||||
|
||||
/**
|
||||
* This is used instead of an event to force it to be implemented since there
|
||||
* would be no guarantee the implementation would remember to emit the event.
|
||||
*/
|
||||
onDone(cb: () => void): Promise<void>;
|
||||
public onDone(cb: () => void): void {
|
||||
this.options.doneEvents.forEach((event) => {
|
||||
this.instance.on(event, cb);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind an event that will not fire without first binding it and shouldn't be
|
||||
* bound immediately.
|
||||
|
||||
* For example, binding to `data` switches a stream to flowing mode, so we
|
||||
* don't want to do it until we're asked. Otherwise something like `pipe`
|
||||
* won't work because potentially some or all of the data will already have
|
||||
* been flushed out.
|
||||
*/
|
||||
public async bindDelayedEvent(event: string): Promise<void> {
|
||||
if (this.options.delayedEvents
|
||||
&& this.options.delayedEvents.includes(event)
|
||||
&& !this.options.bindEvents.includes(event)) {
|
||||
this.options.bindEvents.push(event);
|
||||
this.callbacks.forEach((cb) => {
|
||||
this.instance.on(event, (...args: any[]) => cb(event, ...args));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Listen to all possible events. On the client, this is to reduce boilerplate
|
||||
* that would just be a bunch of error-prone forwarding of each individual
|
||||
* event from the proxy to its own emitter. It also fixes a timing issue
|
||||
* because we just always send all events from the server, so we never miss
|
||||
* any due to listening too late.
|
||||
* event from the proxy to its own emitter.
|
||||
*
|
||||
* It also fixes a timing issue because we just always send all events from
|
||||
* the server, so we never miss any due to listening too late.
|
||||
*
|
||||
* This cannot be async because then we can bind to the events too late.
|
||||
*/
|
||||
// tslint:disable-next-line no-any
|
||||
onEvent(cb: (event: string, ...args: any[]) => void): Promise<void>;
|
||||
public onEvent(cb: EventCallback): void {
|
||||
this.callbacks.push(cb);
|
||||
this.options.bindEvents.forEach((event) => {
|
||||
this.instance.on(event, (...args: any[]) => cb(event, ...args));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A server-side proxy stored on the client. The proxy ID only exists on the
|
||||
* client-side version of the server proxy. The event listeners are handled by
|
||||
* the client and the remaining methods are proxied to the server.
|
||||
*/
|
||||
export interface ClientServerProxy<T extends EventEmitter = EventEmitter> extends ServerProxy<T> {
|
||||
proxyId: number | Module;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -158,8 +270,10 @@ export abstract class Batch<T, A> {
|
||||
private readonly maxCount: number = 100,
|
||||
/**
|
||||
* Flush after not receiving more requests for this amount of time.
|
||||
* This is pretty low by default so essentially we just end up batching
|
||||
* requests that are all made at the same time.
|
||||
*/
|
||||
private readonly idleTime: number = 100,
|
||||
private readonly idleTime: number = 1,
|
||||
) {}
|
||||
|
||||
public add = (args: A): Promise<T> => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Argument, Module as ProtoModule, WorkingInit } from "../proto";
|
||||
import { OperatingSystem } from "../common/connection";
|
||||
import { Module, ServerProxy } from "./proxy";
|
||||
import { ClientServerProxy, Module, ServerProxy } from "./proxy";
|
||||
|
||||
// tslint:disable no-any
|
||||
|
||||
@@ -19,6 +19,8 @@ export const escapePath = (path: string): string => {
|
||||
return `'${path.replace(/'/g, "'\\''")}'`;
|
||||
};
|
||||
|
||||
export type EventCallback = (event: string, ...args: any[]) => void;
|
||||
|
||||
export type IEncodingOptions = {
|
||||
encoding?: BufferEncoding | null;
|
||||
flag?: string;
|
||||
@@ -34,15 +36,26 @@ export type IEncodingOptionsCallback = IEncodingOptions | ((err: NodeJS.ErrnoExc
|
||||
* If sending a function is possible, provide `storeFunction`.
|
||||
* If sending a proxy is possible, provide `storeProxy`.
|
||||
*/
|
||||
export const argumentToProto = (
|
||||
export const argumentToProto = <P = ClientServerProxy | ServerProxy>(
|
||||
value: any,
|
||||
storeFunction?: (fn: () => void) => number,
|
||||
storeProxy?: (proxy: ServerProxy) => number,
|
||||
storeProxy?: (proxy: P) => number | Module,
|
||||
): Argument => {
|
||||
const convert = (currentValue: any): Argument => {
|
||||
const message = new Argument();
|
||||
|
||||
if (currentValue instanceof Error
|
||||
if (isProxy<P>(currentValue)) {
|
||||
if (!storeProxy) {
|
||||
throw new Error("no way to serialize proxy");
|
||||
}
|
||||
const arg = new Argument.ProxyValue();
|
||||
const id = storeProxy(currentValue);
|
||||
if (typeof id === "string") {
|
||||
throw new Error("unable to serialize module proxy");
|
||||
}
|
||||
arg.setId(id);
|
||||
message.setProxy(arg);
|
||||
} else if (currentValue instanceof Error
|
||||
|| (currentValue && typeof currentValue.message !== "undefined"
|
||||
&& typeof currentValue.stack !== "undefined")) {
|
||||
const arg = new Argument.ErrorValue();
|
||||
@@ -58,13 +71,11 @@ export const argumentToProto = (
|
||||
const arg = new Argument.ArrayValue();
|
||||
arg.setDataList(currentValue.map(convert));
|
||||
message.setArray(arg);
|
||||
} else if (isProxy(currentValue)) {
|
||||
if (!storeProxy) {
|
||||
throw new Error("no way to serialize proxy");
|
||||
}
|
||||
const arg = new Argument.ProxyValue();
|
||||
arg.setId(storeProxy(currentValue));
|
||||
message.setProxy(arg);
|
||||
} else if (currentValue instanceof Date
|
||||
|| (currentValue && typeof currentValue.getTime === "function")) {
|
||||
const arg = new Argument.DateValue();
|
||||
arg.setDate(currentValue.toString());
|
||||
message.setDate(arg);
|
||||
} else if (currentValue !== null && typeof currentValue === "object") {
|
||||
const arg = new Argument.ObjectValue();
|
||||
const map = arg.getDataMap();
|
||||
@@ -136,6 +147,8 @@ export const protoToArgument = (
|
||||
}
|
||||
|
||||
return createProxy(currentMessage.getProxy()!.getId());
|
||||
case Argument.MsgCase.DATE:
|
||||
return new Date(currentMessage.getDate()!.getDate());
|
||||
case Argument.MsgCase.OBJECT:
|
||||
const obj: { [Key: string]: any } = {};
|
||||
currentMessage.getObject()!.getDataMap().forEach((argument, key) => {
|
||||
@@ -211,7 +224,7 @@ export const platformToProto = (platform: NodeJS.Platform): WorkingInit.Operatin
|
||||
}
|
||||
};
|
||||
|
||||
export const isProxy = (value: any): value is ServerProxy => {
|
||||
export const isProxy = <P = ClientServerProxy | ServerProxy>(value: any): value is P => {
|
||||
return value && typeof value === "object" && typeof value.onEvent === "function";
|
||||
};
|
||||
|
||||
@@ -223,8 +236,11 @@ export const isPromise = (value: any): value is Promise<any> => {
|
||||
* When spawning VS Code tries to preserve the environment but since it's in
|
||||
* the browser, it doesn't work.
|
||||
*/
|
||||
export const preserveEnv = (options?: { env?: NodeJS.ProcessEnv } | null): void => {
|
||||
if (options && options.env) {
|
||||
options.env = { ...process.env, ...options.env };
|
||||
}
|
||||
export const withEnv = <T extends { env?: NodeJS.ProcessEnv }>(options?: T): T | undefined => {
|
||||
return options && options.env ? {
|
||||
...options,
|
||||
env: {
|
||||
...process.env, ...options.env,
|
||||
},
|
||||
} : options;
|
||||
};
|
||||
|
||||
@@ -1,35 +1,41 @@
|
||||
import * as cp from "child_process";
|
||||
import { ServerProxy } from "../../common/proxy";
|
||||
import { preserveEnv } from "../../common/util";
|
||||
import { withEnv } from "../../common/util";
|
||||
import { WritableProxy, ReadableProxy } from "./stream";
|
||||
|
||||
// tslint:disable completed-docs
|
||||
|
||||
export type ForkProvider = (modulePath: string, args?: string[], options?: cp.ForkOptions) => cp.ChildProcess;
|
||||
|
||||
export class ChildProcessProxy implements ServerProxy {
|
||||
public constructor(private readonly process: cp.ChildProcess) {}
|
||||
export class ChildProcessProxy extends ServerProxy<cp.ChildProcess> {
|
||||
public constructor(instance: cp.ChildProcess) {
|
||||
super({
|
||||
bindEvents: ["close", "disconnect", "error", "exit", "message"],
|
||||
doneEvents: ["close"],
|
||||
instance,
|
||||
});
|
||||
}
|
||||
|
||||
public async kill(signal?: string): Promise<void> {
|
||||
this.process.kill(signal);
|
||||
this.instance.kill(signal);
|
||||
}
|
||||
|
||||
public async disconnect(): Promise<void> {
|
||||
this.process.disconnect();
|
||||
this.instance.disconnect();
|
||||
}
|
||||
|
||||
public async ref(): Promise<void> {
|
||||
this.process.ref();
|
||||
this.instance.ref();
|
||||
}
|
||||
|
||||
public async unref(): Promise<void> {
|
||||
this.process.unref();
|
||||
this.instance.unref();
|
||||
}
|
||||
|
||||
// tslint:disable-next-line no-any
|
||||
public async send(message: any): Promise<void> {
|
||||
return new Promise((resolve, reject): void => {
|
||||
this.process.send(message, (error) => {
|
||||
this.instance.send(message, (error) => {
|
||||
if (error) {
|
||||
reject(error);
|
||||
} else {
|
||||
@@ -40,25 +46,13 @@ export class ChildProcessProxy implements ServerProxy {
|
||||
}
|
||||
|
||||
public async getPid(): Promise<number> {
|
||||
return this.process.pid;
|
||||
}
|
||||
|
||||
public async onDone(cb: () => void): Promise<void> {
|
||||
this.process.on("close", cb);
|
||||
return this.instance.pid;
|
||||
}
|
||||
|
||||
public async dispose(): Promise<void> {
|
||||
this.process.kill();
|
||||
setTimeout(() => this.process.kill("SIGKILL"), 5000); // Double tap.
|
||||
}
|
||||
|
||||
// tslint:disable-next-line no-any
|
||||
public async onEvent(cb: (event: string, ...args: any[]) => void): Promise<void> {
|
||||
this.process.on("close", (code, signal) => cb("close", code, signal));
|
||||
this.process.on("disconnect", () => cb("disconnect"));
|
||||
this.process.on("error", (error) => cb("error", error));
|
||||
this.process.on("exit", (exitCode, signal) => cb("exit", exitCode, signal));
|
||||
this.process.on("message", (message) => cb("message", message));
|
||||
this.instance.kill();
|
||||
setTimeout(() => this.instance.kill("SIGKILL"), 5000); // Double tap.
|
||||
await super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,29 +71,25 @@ export class ChildProcessModuleProxy {
|
||||
options?: { encoding?: string | null } & cp.ExecOptions | null,
|
||||
callback?: ((error: cp.ExecException | null, stdin: string | Buffer, stdout: string | Buffer) => void),
|
||||
): Promise<ChildProcessProxies> {
|
||||
preserveEnv(options);
|
||||
|
||||
return this.returnProxies(cp.exec(command, options, callback));
|
||||
return this.returnProxies(cp.exec(command, options && withEnv(options), callback));
|
||||
}
|
||||
|
||||
public async fork(modulePath: string, args?: string[], options?: cp.ForkOptions): Promise<ChildProcessProxies> {
|
||||
preserveEnv(options);
|
||||
|
||||
return this.returnProxies((this.forkProvider || cp.fork)(modulePath, args, options));
|
||||
return this.returnProxies((this.forkProvider || cp.fork)(modulePath, args, withEnv(options)));
|
||||
}
|
||||
|
||||
public async spawn(command: string, args?: string[], options?: cp.SpawnOptions): Promise<ChildProcessProxies> {
|
||||
preserveEnv(options);
|
||||
|
||||
return this.returnProxies(cp.spawn(command, args, options));
|
||||
return this.returnProxies(cp.spawn(command, args, withEnv(options)));
|
||||
}
|
||||
|
||||
private returnProxies(process: cp.ChildProcess): ChildProcessProxies {
|
||||
return {
|
||||
childProcess: new ChildProcessProxy(process),
|
||||
stdin: process.stdin && new WritableProxy(process.stdin),
|
||||
stdout: process.stdout && new ReadableProxy(process.stdout),
|
||||
stderr: process.stderr && new ReadableProxy(process.stderr),
|
||||
// Child processes streams appear to immediately flow so we need to bind
|
||||
// to the data event right away.
|
||||
stdout: process.stdout && new ReadableProxy(process.stdout, ["data"]),
|
||||
stderr: process.stderr && new ReadableProxy(process.stderr, ["data"]),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,9 @@ import * as fs from "fs";
|
||||
import { promisify } from "util";
|
||||
import { ServerProxy } from "../../common/proxy";
|
||||
import { IEncodingOptions } from "../../common/util";
|
||||
import { WritableProxy } from "./stream";
|
||||
import { ReadableProxy, WritableProxy } from "./stream";
|
||||
|
||||
// tslint:disable completed-docs
|
||||
// tslint:disable completed-docs no-any
|
||||
|
||||
/**
|
||||
* A serializable version of fs.Stats.
|
||||
@@ -24,10 +24,10 @@ export interface Stats {
|
||||
mtimeMs: number;
|
||||
ctimeMs: number;
|
||||
birthtimeMs: number;
|
||||
atime: Date | string;
|
||||
mtime: Date | string;
|
||||
ctime: Date | string;
|
||||
birthtime: Date | string;
|
||||
atime: Date;
|
||||
mtime: Date;
|
||||
ctime: Date;
|
||||
birthtime: Date;
|
||||
_isFile: boolean;
|
||||
_isDirectory: boolean;
|
||||
_isBlockDevice: boolean;
|
||||
@@ -37,45 +37,52 @@ export interface Stats {
|
||||
_isSocket: boolean;
|
||||
}
|
||||
|
||||
export class WriteStreamProxy extends WritableProxy<fs.WriteStream> {
|
||||
export class ReadStreamProxy extends ReadableProxy<fs.ReadStream> {
|
||||
public constructor(stream: fs.ReadStream) {
|
||||
super(stream, ["open"]);
|
||||
}
|
||||
|
||||
public async close(): Promise<void> {
|
||||
this.stream.close();
|
||||
this.instance.close();
|
||||
}
|
||||
|
||||
public async dispose(): Promise<void> {
|
||||
this.instance.close();
|
||||
await super.dispose();
|
||||
this.stream.close();
|
||||
}
|
||||
|
||||
// tslint:disable-next-line no-any
|
||||
public async onEvent(cb: (event: string, ...args: any[]) => void): Promise<void> {
|
||||
await super.onEvent(cb);
|
||||
this.stream.on("open", (fd) => cb("open", fd));
|
||||
}
|
||||
}
|
||||
|
||||
export class WatcherProxy implements ServerProxy {
|
||||
public constructor(private readonly watcher: fs.FSWatcher) {}
|
||||
export class WriteStreamProxy extends WritableProxy<fs.WriteStream> {
|
||||
public constructor(stream: fs.WriteStream) {
|
||||
super(stream, ["open"]);
|
||||
}
|
||||
|
||||
public async close(): Promise<void> {
|
||||
this.watcher.close();
|
||||
this.instance.close();
|
||||
}
|
||||
|
||||
public async dispose(): Promise<void> {
|
||||
this.watcher.close();
|
||||
this.watcher.removeAllListeners();
|
||||
this.instance.close();
|
||||
await super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public async onDone(cb: () => void): Promise<void> {
|
||||
this.watcher.on("close", cb);
|
||||
this.watcher.on("error", cb);
|
||||
export class WatcherProxy extends ServerProxy<fs.FSWatcher> {
|
||||
public constructor(watcher: fs.FSWatcher) {
|
||||
super({
|
||||
bindEvents: ["change", "close", "error"],
|
||||
doneEvents: ["close", "error"],
|
||||
instance: watcher,
|
||||
});
|
||||
}
|
||||
|
||||
// tslint:disable-next-line no-any
|
||||
public async onEvent(cb: (event: string, ...args: any[]) => void): Promise<void> {
|
||||
this.watcher.on("change", (event, filename) => cb("change", event, filename));
|
||||
this.watcher.on("close", () => cb("close"));
|
||||
this.watcher.on("error", (error) => cb("error", error));
|
||||
public async close(): Promise<void> {
|
||||
this.instance.close();
|
||||
}
|
||||
|
||||
public async dispose(): Promise<void> {
|
||||
this.instance.close();
|
||||
await super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,7 +91,6 @@ export class FsModuleProxy {
|
||||
return promisify(fs.access)(path, mode);
|
||||
}
|
||||
|
||||
// tslint:disable-next-line no-any
|
||||
public appendFile(file: fs.PathLike | number, data: any, options?: fs.WriteFileOptions): Promise<void> {
|
||||
return promisify(fs.appendFile)(file, data, options);
|
||||
}
|
||||
@@ -105,7 +111,10 @@ export class FsModuleProxy {
|
||||
return promisify(fs.copyFile)(src, dest, flags);
|
||||
}
|
||||
|
||||
// tslint:disable-next-line no-any
|
||||
public async createReadStream(path: fs.PathLike, options?: any): Promise<ReadStreamProxy> {
|
||||
return new ReadStreamProxy(fs.createReadStream(path, options));
|
||||
}
|
||||
|
||||
public async createWriteStream(path: fs.PathLike, options?: any): Promise<WriteStreamProxy> {
|
||||
return new WriteStreamProxy(fs.createWriteStream(path, options));
|
||||
}
|
||||
@@ -236,7 +245,6 @@ export class FsModuleProxy {
|
||||
return promisify(fs.write)(fd, buffer, offset, length, position);
|
||||
}
|
||||
|
||||
// tslint:disable-next-line no-any
|
||||
public writeFile (path: fs.PathLike | number, data: any, options: IEncodingOptions): Promise<void> {
|
||||
return promisify(fs.writeFile)(path, data, options);
|
||||
}
|
||||
|
||||
@@ -2,78 +2,65 @@ import * as net from "net";
|
||||
import { ServerProxy } from "../../common/proxy";
|
||||
import { DuplexProxy } from "./stream";
|
||||
|
||||
// tslint:disable completed-docs
|
||||
// tslint:disable completed-docs no-any
|
||||
|
||||
export class NetSocketProxy extends DuplexProxy<net.Socket> {
|
||||
public constructor(socket: net.Socket) {
|
||||
super(socket, ["connect", "lookup", "timeout"]);
|
||||
}
|
||||
|
||||
public async connect(options: number | string | net.SocketConnectOpts, host?: string): Promise<void> {
|
||||
this.stream.connect(options as any, host as any); // tslint:disable-line no-any this works fine
|
||||
this.instance.connect(options as any, host as any);
|
||||
}
|
||||
|
||||
public async unref(): Promise<void> {
|
||||
this.stream.unref();
|
||||
this.instance.unref();
|
||||
}
|
||||
|
||||
public async ref(): Promise<void> {
|
||||
this.stream.ref();
|
||||
this.instance.ref();
|
||||
}
|
||||
|
||||
public async dispose(): Promise<void> {
|
||||
this.stream.removeAllListeners();
|
||||
this.stream.end();
|
||||
this.stream.destroy();
|
||||
this.stream.unref();
|
||||
}
|
||||
|
||||
public async onDone(cb: () => void): Promise<void> {
|
||||
this.stream.on("close", cb);
|
||||
}
|
||||
|
||||
// tslint:disable-next-line no-any
|
||||
public async onEvent(cb: (event: string, ...args: any[]) => void): Promise<void> {
|
||||
await super.onEvent(cb);
|
||||
this.stream.on("connect", () => cb("connect"));
|
||||
this.stream.on("lookup", (error, address, family, host) => cb("lookup", error, address, family, host));
|
||||
this.stream.on("timeout", () => cb("timeout"));
|
||||
this.instance.end();
|
||||
this.instance.destroy();
|
||||
this.instance.unref();
|
||||
await super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
export class NetServerProxy implements ServerProxy {
|
||||
public constructor(private readonly server: net.Server) {}
|
||||
export class NetServerProxy extends ServerProxy<net.Server> {
|
||||
public constructor(instance: net.Server) {
|
||||
super({
|
||||
bindEvents: ["close", "error", "listening"],
|
||||
doneEvents: ["close"],
|
||||
instance,
|
||||
});
|
||||
}
|
||||
|
||||
public async listen(handle?: net.ListenOptions | number | string, hostname?: string | number, backlog?: number): Promise<void> {
|
||||
this.server.listen(handle, hostname as any, backlog as any); // tslint:disable-line no-any this is fine
|
||||
this.instance.listen(handle, hostname as any, backlog as any);
|
||||
}
|
||||
|
||||
public async ref(): Promise<void> {
|
||||
this.server.ref();
|
||||
this.instance.ref();
|
||||
}
|
||||
|
||||
public async unref(): Promise<void> {
|
||||
this.server.unref();
|
||||
this.instance.unref();
|
||||
}
|
||||
|
||||
public async close(): Promise<void> {
|
||||
this.server.close();
|
||||
this.instance.close();
|
||||
}
|
||||
|
||||
public async onConnection(cb: (proxy: NetSocketProxy) => void): Promise<void> {
|
||||
this.server.on("connection", (socket) => cb(new NetSocketProxy(socket)));
|
||||
this.instance.on("connection", (socket) => cb(new NetSocketProxy(socket)));
|
||||
}
|
||||
|
||||
public async dispose(): Promise<void> {
|
||||
this.server.close();
|
||||
this.server.removeAllListeners();
|
||||
}
|
||||
|
||||
public async onDone(cb: () => void): Promise<void> {
|
||||
this.server.on("close", cb);
|
||||
}
|
||||
|
||||
// tslint:disable-next-line no-any
|
||||
public async onEvent(cb: (event: string, ...args: any[]) => void): Promise<void> {
|
||||
this.server.on("close", () => cb("close"));
|
||||
this.server.on("error", (error) => cb("error", error));
|
||||
this.server.on("listening", () => cb("listening"));
|
||||
this.instance.close();
|
||||
this.instance.removeAllListeners();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,7 +70,7 @@ export class NetModuleProxy {
|
||||
}
|
||||
|
||||
public async createConnection(target: string | number | net.NetConnectOpts, host?: string): Promise<NetSocketProxy> {
|
||||
return new NetSocketProxy(net.createConnection(target as any, host)); // tslint:disable-line no-any defeat stubborness
|
||||
return new NetSocketProxy(net.createConnection(target as any, host));
|
||||
}
|
||||
|
||||
public async createServer(options?: { allowHalfOpen?: boolean, pauseOnConnect?: boolean }): Promise<NetServerProxy> {
|
||||
|
||||
@@ -2,25 +2,32 @@
|
||||
import { EventEmitter } from "events";
|
||||
import * as pty from "node-pty";
|
||||
import { ServerProxy } from "../../common/proxy";
|
||||
import { preserveEnv } from "../../common/util";
|
||||
import { withEnv } from "../../common/util";
|
||||
|
||||
// tslint:disable completed-docs
|
||||
|
||||
/**
|
||||
* Server-side IPty proxy.
|
||||
*/
|
||||
export class NodePtyProcessProxy implements ServerProxy {
|
||||
private readonly emitter = new EventEmitter();
|
||||
|
||||
export class NodePtyProcessProxy extends ServerProxy {
|
||||
public constructor(private readonly process: pty.IPty) {
|
||||
super({
|
||||
bindEvents: ["process", "data", "exit"],
|
||||
doneEvents: ["exit"],
|
||||
instance: new EventEmitter(),
|
||||
});
|
||||
|
||||
this.process.on("data", (data) => this.instance.emit("data", data));
|
||||
this.process.on("exit", (exitCode, signal) => this.instance.emit("exit", exitCode, signal));
|
||||
|
||||
let name = process.process;
|
||||
setTimeout(() => { // Need to wait for the caller to listen to the event.
|
||||
this.emitter.emit("process", name);
|
||||
this.instance.emit("process", name);
|
||||
}, 1);
|
||||
const timer = setInterval(() => {
|
||||
if (process.process !== name) {
|
||||
name = process.process;
|
||||
this.emitter.emit("process", name);
|
||||
this.instance.emit("process", name);
|
||||
}
|
||||
}, 200);
|
||||
|
||||
@@ -47,21 +54,10 @@ export class NodePtyProcessProxy implements ServerProxy {
|
||||
this.process.write(data);
|
||||
}
|
||||
|
||||
public async onDone(cb: () => void): Promise<void> {
|
||||
this.process.on("exit", cb);
|
||||
}
|
||||
|
||||
public async dispose(): Promise<void> {
|
||||
this.process.kill();
|
||||
setTimeout(() => this.process.kill("SIGKILL"), 5000); // Double tap.
|
||||
this.emitter.removeAllListeners();
|
||||
}
|
||||
|
||||
// tslint:disable-next-line no-any
|
||||
public async onEvent(cb: (event: string, ...args: any[]) => void): Promise<void> {
|
||||
this.emitter.on("process", (process) => cb("process", process));
|
||||
this.process.on("data", (data) => cb("data", data));
|
||||
this.process.on("exit", (exitCode, signal) => cb("exit", exitCode, signal));
|
||||
await super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,8 +66,6 @@ export class NodePtyProcessProxy implements ServerProxy {
|
||||
*/
|
||||
export class NodePtyModuleProxy {
|
||||
public async spawn(file: string, args: string[] | string, options: pty.IPtyForkOptions): Promise<NodePtyProcessProxy> {
|
||||
preserveEnv(options);
|
||||
|
||||
return new NodePtyProcessProxy(require("node-pty").spawn(file, args, options));
|
||||
return new NodePtyProcessProxy(require("node-pty").spawn(file, args, withEnv(options)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,10 +5,14 @@ import { ServerProxy } from "../../common/proxy";
|
||||
|
||||
// tslint:disable completed-docs
|
||||
|
||||
export class RotatingLoggerProxy implements ServerProxy {
|
||||
private readonly emitter = new EventEmitter();
|
||||
|
||||
public constructor(private readonly logger: spdlog.RotatingLogger) {}
|
||||
export class RotatingLoggerProxy extends ServerProxy<EventEmitter> {
|
||||
public constructor(private readonly logger: spdlog.RotatingLogger) {
|
||||
super({
|
||||
bindEvents: [],
|
||||
doneEvents: ["dispose"],
|
||||
instance: new EventEmitter(),
|
||||
});
|
||||
}
|
||||
|
||||
public async trace (message: string): Promise<void> { this.logger.trace(message); }
|
||||
public async debug (message: string): Promise<void> { this.logger.debug(message); }
|
||||
@@ -21,19 +25,10 @@ export class RotatingLoggerProxy implements ServerProxy {
|
||||
public async flush (): Promise<void> { this.logger.flush(); }
|
||||
public async drop (): Promise<void> { this.logger.drop(); }
|
||||
|
||||
public async onDone(cb: () => void): Promise<void> {
|
||||
this.emitter.on("dispose", cb);
|
||||
}
|
||||
|
||||
public async dispose(): Promise<void> {
|
||||
await this.flush();
|
||||
this.emitter.emit("dispose");
|
||||
this.emitter.removeAllListeners();
|
||||
}
|
||||
|
||||
// tslint:disable-next-line no-any
|
||||
public async onEvent(_cb: (event: string, ...args: any[]) => void): Promise<void> {
|
||||
// No events.
|
||||
this.instance.emit("dispose");
|
||||
await super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,32 +1,38 @@
|
||||
import { EventEmitter } from "events";
|
||||
import * as stream from "stream";
|
||||
import { ServerProxy } from "../../common/proxy";
|
||||
|
||||
// tslint:disable completed-docs
|
||||
// tslint:disable completed-docs no-any
|
||||
|
||||
export class WritableProxy<T extends stream.Writable = stream.Writable> implements ServerProxy {
|
||||
public constructor(protected readonly stream: T) {}
|
||||
|
||||
public async destroy(): Promise<void> {
|
||||
this.stream.destroy();
|
||||
export class WritableProxy<T extends stream.Writable = stream.Writable> extends ServerProxy<T> {
|
||||
public constructor(instance: T, bindEvents: string[] = [], delayedEvents?: string[]) {
|
||||
super({
|
||||
bindEvents: ["close", "drain", "error", "finish"].concat(bindEvents),
|
||||
doneEvents: ["close"],
|
||||
delayedEvents,
|
||||
instance,
|
||||
});
|
||||
}
|
||||
|
||||
public async destroy(): Promise<void> {
|
||||
this.instance.destroy();
|
||||
}
|
||||
|
||||
// tslint:disable-next-line no-any
|
||||
public async end(data?: any, encoding?: string): Promise<void> {
|
||||
return new Promise((resolve): void => {
|
||||
this.stream.end(data, encoding, () => {
|
||||
this.instance.end(data, encoding, () => {
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public async setDefaultEncoding(encoding: string): Promise<void> {
|
||||
this.stream.setDefaultEncoding(encoding);
|
||||
this.instance.setDefaultEncoding(encoding);
|
||||
}
|
||||
|
||||
// tslint:disable-next-line no-any
|
||||
public async write(data: any, encoding?: string): Promise<void> {
|
||||
return new Promise((resolve, reject): void => {
|
||||
this.stream.write(data, encoding, (error) => {
|
||||
this.instance.write(data, encoding, (error) => {
|
||||
if (error) {
|
||||
reject(error);
|
||||
} else {
|
||||
@@ -37,22 +43,8 @@ export class WritableProxy<T extends stream.Writable = stream.Writable> implemen
|
||||
}
|
||||
|
||||
public async dispose(): Promise<void> {
|
||||
this.stream.end();
|
||||
this.stream.removeAllListeners();
|
||||
}
|
||||
|
||||
public async onDone(cb: () => void): Promise<void> {
|
||||
this.stream.on("close", cb);
|
||||
}
|
||||
|
||||
// tslint:disable-next-line no-any
|
||||
public async onEvent(cb: (event: string, ...args: any[]) => void): Promise<void> {
|
||||
// Sockets have an extra argument on "close".
|
||||
// tslint:disable-next-line no-any
|
||||
this.stream.on("close", (...args: any[]) => cb("close", ...args));
|
||||
this.stream.on("drain", () => cb("drain"));
|
||||
this.stream.on("error", (error) => cb("error", error));
|
||||
this.stream.on("finish", () => cb("finish"));
|
||||
this.instance.end();
|
||||
await super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,50 +52,58 @@ export class WritableProxy<T extends stream.Writable = stream.Writable> implemen
|
||||
* This noise is because we can't do multiple extends and we also can't seem to
|
||||
* do `extends WritableProxy<T> implement ReadableProxy<T>` (for `DuplexProxy`).
|
||||
*/
|
||||
export interface IReadableProxy extends ServerProxy {
|
||||
destroy(): Promise<void>;
|
||||
export interface IReadableProxy<T extends EventEmitter> extends ServerProxy<T> {
|
||||
pipe<P extends WritableProxy>(destination: P, options?: { end?: boolean; }): Promise<void>;
|
||||
setEncoding(encoding: string): Promise<void>;
|
||||
dispose(): Promise<void>;
|
||||
onDone(cb: () => void): Promise<void>;
|
||||
}
|
||||
|
||||
export class ReadableProxy<T extends stream.Readable = stream.Readable> implements IReadableProxy {
|
||||
public constructor(protected readonly stream: T) {}
|
||||
export class ReadableProxy<T extends stream.Readable = stream.Readable> extends ServerProxy<T> implements IReadableProxy<T> {
|
||||
public constructor(instance: T, bindEvents: string[] = []) {
|
||||
super({
|
||||
bindEvents: ["close", "end", "error"].concat(bindEvents),
|
||||
doneEvents: ["close"],
|
||||
delayedEvents: ["data"],
|
||||
instance,
|
||||
});
|
||||
}
|
||||
|
||||
public async pipe<P extends WritableProxy>(destination: P, options?: { end?: boolean; }): Promise<void> {
|
||||
this.instance.pipe(destination.instance, options);
|
||||
// `pipe` switches the stream to flowing mode and makes data start emitting.
|
||||
await this.bindDelayedEvent("data");
|
||||
}
|
||||
|
||||
public async destroy(): Promise<void> {
|
||||
this.stream.destroy();
|
||||
this.instance.destroy();
|
||||
}
|
||||
|
||||
public async setEncoding(encoding: string): Promise<void> {
|
||||
this.stream.setEncoding(encoding);
|
||||
this.instance.setEncoding(encoding);
|
||||
}
|
||||
|
||||
public async dispose(): Promise<void> {
|
||||
this.stream.destroy();
|
||||
}
|
||||
|
||||
public async onDone(cb: () => void): Promise<void> {
|
||||
this.stream.on("close", cb);
|
||||
}
|
||||
|
||||
// tslint:disable-next-line no-any
|
||||
public async onEvent(cb: (event: string, ...args: any[]) => void): Promise<void> {
|
||||
this.stream.on("close", () => cb("close"));
|
||||
this.stream.on("data", (chunk) => cb("data", chunk));
|
||||
this.stream.on("end", () => cb("end"));
|
||||
this.stream.on("error", (error) => cb("error", error));
|
||||
this.instance.destroy();
|
||||
await super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
export class DuplexProxy<T extends stream.Duplex = stream.Duplex> extends WritableProxy<T> implements IReadableProxy {
|
||||
export class DuplexProxy<T extends stream.Duplex = stream.Duplex> extends WritableProxy<T> implements IReadableProxy<T> {
|
||||
public constructor(stream: T, bindEvents: string[] = []) {
|
||||
super(stream, ["end"].concat(bindEvents), ["data"]);
|
||||
}
|
||||
|
||||
public async pipe<P extends WritableProxy>(destination: P, options?: { end?: boolean; }): Promise<void> {
|
||||
this.instance.pipe(destination.instance, options);
|
||||
// `pipe` switches the stream to flowing mode and makes data start emitting.
|
||||
await this.bindDelayedEvent("data");
|
||||
}
|
||||
|
||||
public async setEncoding(encoding: string): Promise<void> {
|
||||
this.stream.setEncoding(encoding);
|
||||
this.instance.setEncoding(encoding);
|
||||
}
|
||||
|
||||
// tslint:disable-next-line no-any
|
||||
public async onEvent(cb: (event: string, ...args: any[]) => void): Promise<void> {
|
||||
await super.onEvent(cb);
|
||||
this.stream.on("data", (chunk) => cb("data", chunk));
|
||||
this.stream.on("end", () => cb("end"));
|
||||
public async dispose(): Promise<void> {
|
||||
this.instance.destroy();
|
||||
await super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@ export interface ServerOptions {
|
||||
readonly cacheDirectory: string;
|
||||
readonly builtInExtensionsDirectory: string;
|
||||
readonly extensionsDirectory: string;
|
||||
readonly extraExtensionDirectories?: string[];
|
||||
readonly extraBuiltinExtensionDirectories?: string[];
|
||||
readonly fork?: ForkProvider;
|
||||
}
|
||||
|
||||
@@ -99,6 +101,13 @@ export class Server {
|
||||
initMsg.setTmpDirectory(os.tmpdir());
|
||||
initMsg.setOperatingSystem(platformToProto(os.platform()));
|
||||
initMsg.setShell(os.userInfo().shell || global.process.env.SHELL || "");
|
||||
initMsg.setExtraExtensionDirectoriesList(this.options.extraExtensionDirectories || []);
|
||||
initMsg.setExtraBuiltinExtensionDirectoriesList(this.options.extraBuiltinExtensionDirectories || []);
|
||||
|
||||
for (let key in process.env) {
|
||||
initMsg.getEnvMap().set(key, process.env[key] as string);
|
||||
}
|
||||
|
||||
const srvMsg = new ServerMessage();
|
||||
srvMsg.setInit(initMsg);
|
||||
connection.send(srvMsg.serializeBinary());
|
||||
@@ -136,6 +145,7 @@ export class Server {
|
||||
const args = proxyMessage.getArgsList().map((a) => protoToArgument(
|
||||
a,
|
||||
(id, args) => this.sendCallback(proxyId, id, args),
|
||||
(id) => this.getProxy(id).instance,
|
||||
));
|
||||
|
||||
logger.trace(() => [
|
||||
@@ -241,9 +251,7 @@ export class Server {
|
||||
this.proxies.set(proxyId, { instance });
|
||||
|
||||
if (isProxy(instance)) {
|
||||
instance.onEvent((event, ...args) => this.sendEvent(proxyId, event, ...args)).catch((error) => {
|
||||
logger.error(error.message);
|
||||
});
|
||||
instance.onEvent((event, ...args) => this.sendEvent(proxyId, event, ...args));
|
||||
instance.onDone(() => {
|
||||
// It might have finished because we disposed it due to a disconnect.
|
||||
if (!this.disconnected) {
|
||||
@@ -255,8 +263,6 @@ export class Server {
|
||||
this.removeProxy(proxyId);
|
||||
}, this.responseTimeout);
|
||||
}
|
||||
}).catch((error) => {
|
||||
logger.error(error.message);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -317,6 +323,7 @@ export class Server {
|
||||
logger.trace(() => [
|
||||
"sending reject",
|
||||
field("id", id) ,
|
||||
field("message", error.message),
|
||||
]);
|
||||
|
||||
const failedMessage = new Method.Fail();
|
||||
|
||||
@@ -42,4 +42,8 @@ message WorkingInit {
|
||||
string shell = 6;
|
||||
string builtin_extensions_dir = 7;
|
||||
string extensions_directory = 8;
|
||||
repeated string extra_extension_directories = 9;
|
||||
repeated string extra_builtin_extension_directories = 10;
|
||||
|
||||
map<string, string> env = 11;
|
||||
}
|
||||
|
||||
15
packages/protocol/src/proto/client_pb.d.ts
vendored
15
packages/protocol/src/proto/client_pb.d.ts
vendored
@@ -135,6 +135,18 @@ export class WorkingInit extends jspb.Message {
|
||||
getExtensionsDirectory(): string;
|
||||
setExtensionsDirectory(value: string): void;
|
||||
|
||||
clearExtraExtensionDirectoriesList(): void;
|
||||
getExtraExtensionDirectoriesList(): Array<string>;
|
||||
setExtraExtensionDirectoriesList(value: Array<string>): void;
|
||||
addExtraExtensionDirectories(value: string, index?: number): string;
|
||||
|
||||
clearExtraBuiltinExtensionDirectoriesList(): void;
|
||||
getExtraBuiltinExtensionDirectoriesList(): Array<string>;
|
||||
setExtraBuiltinExtensionDirectoriesList(value: Array<string>): void;
|
||||
addExtraBuiltinExtensionDirectories(value: string, index?: number): string;
|
||||
|
||||
getEnvMap(): jspb.Map<string, string>;
|
||||
clearEnvMap(): void;
|
||||
serializeBinary(): Uint8Array;
|
||||
toObject(includeInstance?: boolean): WorkingInit.AsObject;
|
||||
static toObject(includeInstance: boolean, msg: WorkingInit): WorkingInit.AsObject;
|
||||
@@ -155,6 +167,9 @@ export namespace WorkingInit {
|
||||
shell: string,
|
||||
builtinExtensionsDir: string,
|
||||
extensionsDirectory: string,
|
||||
extraExtensionDirectoriesList: Array<string>,
|
||||
extraBuiltinExtensionDirectoriesList: Array<string>,
|
||||
envMap: Array<[string, string]>,
|
||||
}
|
||||
|
||||
export enum OperatingSystem {
|
||||
|
||||
@@ -72,7 +72,7 @@ if (goog.DEBUG && !COMPILED) {
|
||||
* @constructor
|
||||
*/
|
||||
proto.WorkingInit = function(opt_data) {
|
||||
jspb.Message.initialize(this, opt_data, 0, -1, null, null);
|
||||
jspb.Message.initialize(this, opt_data, 0, -1, proto.WorkingInit.repeatedFields_, null);
|
||||
};
|
||||
goog.inherits(proto.WorkingInit, jspb.Message);
|
||||
if (goog.DEBUG && !COMPILED) {
|
||||
@@ -137,7 +137,7 @@ proto.ClientMessage.prototype.toObject = function(opt_includeInstance) {
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.ClientMessage.toObject = function(includeInstance, msg) {
|
||||
var obj = {
|
||||
var f, obj = {
|
||||
method: (f = msg.getMethod()) && node_pb.Method.toObject(includeInstance, f),
|
||||
ping: (f = msg.getPing()) && node_pb.Ping.toObject(includeInstance, f)
|
||||
};
|
||||
@@ -360,7 +360,7 @@ proto.ServerMessage.prototype.toObject = function(opt_includeInstance) {
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.ServerMessage.toObject = function(includeInstance, msg) {
|
||||
var obj = {
|
||||
var f, obj = {
|
||||
fail: (f = msg.getFail()) && node_pb.Method.Fail.toObject(includeInstance, f),
|
||||
success: (f = msg.getSuccess()) && node_pb.Method.Success.toObject(includeInstance, f),
|
||||
event: (f = msg.getEvent()) && node_pb.Event.toObject(includeInstance, f),
|
||||
@@ -759,6 +759,13 @@ proto.ServerMessage.prototype.hasSharedProcessActive = function() {
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* List of repeated fields within this message type.
|
||||
* @private {!Array<number>}
|
||||
* @const
|
||||
*/
|
||||
proto.WorkingInit.repeatedFields_ = [9,10];
|
||||
|
||||
|
||||
|
||||
if (jspb.Message.GENERATE_TO_OBJECT) {
|
||||
@@ -787,7 +794,7 @@ proto.WorkingInit.prototype.toObject = function(opt_includeInstance) {
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.WorkingInit.toObject = function(includeInstance, msg) {
|
||||
var obj = {
|
||||
var f, obj = {
|
||||
homeDirectory: jspb.Message.getFieldWithDefault(msg, 1, ""),
|
||||
tmpDirectory: jspb.Message.getFieldWithDefault(msg, 2, ""),
|
||||
dataDirectory: jspb.Message.getFieldWithDefault(msg, 3, ""),
|
||||
@@ -795,7 +802,10 @@ proto.WorkingInit.toObject = function(includeInstance, msg) {
|
||||
operatingSystem: jspb.Message.getFieldWithDefault(msg, 5, 0),
|
||||
shell: jspb.Message.getFieldWithDefault(msg, 6, ""),
|
||||
builtinExtensionsDir: jspb.Message.getFieldWithDefault(msg, 7, ""),
|
||||
extensionsDirectory: jspb.Message.getFieldWithDefault(msg, 8, "")
|
||||
extensionsDirectory: jspb.Message.getFieldWithDefault(msg, 8, ""),
|
||||
extraExtensionDirectoriesList: jspb.Message.getRepeatedField(msg, 9),
|
||||
extraBuiltinExtensionDirectoriesList: jspb.Message.getRepeatedField(msg, 10),
|
||||
envMap: (f = msg.getEnvMap()) ? f.toObject(includeInstance, undefined) : []
|
||||
};
|
||||
|
||||
if (includeInstance) {
|
||||
@@ -864,6 +874,20 @@ proto.WorkingInit.deserializeBinaryFromReader = function(msg, reader) {
|
||||
var value = /** @type {string} */ (reader.readString());
|
||||
msg.setExtensionsDirectory(value);
|
||||
break;
|
||||
case 9:
|
||||
var value = /** @type {string} */ (reader.readString());
|
||||
msg.addExtraExtensionDirectories(value);
|
||||
break;
|
||||
case 10:
|
||||
var value = /** @type {string} */ (reader.readString());
|
||||
msg.addExtraBuiltinExtensionDirectories(value);
|
||||
break;
|
||||
case 11:
|
||||
var value = msg.getEnvMap();
|
||||
reader.readMessage(value, function(message, reader) {
|
||||
jspb.Map.deserializeBinary(message, reader, jspb.BinaryReader.prototype.readString, jspb.BinaryReader.prototype.readString, null, "");
|
||||
});
|
||||
break;
|
||||
default:
|
||||
reader.skipField();
|
||||
break;
|
||||
@@ -949,6 +973,24 @@ proto.WorkingInit.serializeBinaryToWriter = function(message, writer) {
|
||||
f
|
||||
);
|
||||
}
|
||||
f = message.getExtraExtensionDirectoriesList();
|
||||
if (f.length > 0) {
|
||||
writer.writeRepeatedString(
|
||||
9,
|
||||
f
|
||||
);
|
||||
}
|
||||
f = message.getExtraBuiltinExtensionDirectoriesList();
|
||||
if (f.length > 0) {
|
||||
writer.writeRepeatedString(
|
||||
10,
|
||||
f
|
||||
);
|
||||
}
|
||||
f = message.getEnvMap(true);
|
||||
if (f && f.getLength() > 0) {
|
||||
f.serializeBinary(11, writer, jspb.BinaryWriter.prototype.writeString, jspb.BinaryWriter.prototype.writeString);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1081,4 +1123,89 @@ proto.WorkingInit.prototype.setExtensionsDirectory = function(value) {
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* repeated string extra_extension_directories = 9;
|
||||
* @return {!Array<string>}
|
||||
*/
|
||||
proto.WorkingInit.prototype.getExtraExtensionDirectoriesList = function() {
|
||||
return /** @type {!Array<string>} */ (jspb.Message.getRepeatedField(this, 9));
|
||||
};
|
||||
|
||||
|
||||
/** @param {!Array<string>} value */
|
||||
proto.WorkingInit.prototype.setExtraExtensionDirectoriesList = function(value) {
|
||||
jspb.Message.setField(this, 9, value || []);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} value
|
||||
* @param {number=} opt_index
|
||||
*/
|
||||
proto.WorkingInit.prototype.addExtraExtensionDirectories = function(value, opt_index) {
|
||||
jspb.Message.addToRepeatedField(this, 9, value, opt_index);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Clears the list making it empty but non-null.
|
||||
*/
|
||||
proto.WorkingInit.prototype.clearExtraExtensionDirectoriesList = function() {
|
||||
this.setExtraExtensionDirectoriesList([]);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* repeated string extra_builtin_extension_directories = 10;
|
||||
* @return {!Array<string>}
|
||||
*/
|
||||
proto.WorkingInit.prototype.getExtraBuiltinExtensionDirectoriesList = function() {
|
||||
return /** @type {!Array<string>} */ (jspb.Message.getRepeatedField(this, 10));
|
||||
};
|
||||
|
||||
|
||||
/** @param {!Array<string>} value */
|
||||
proto.WorkingInit.prototype.setExtraBuiltinExtensionDirectoriesList = function(value) {
|
||||
jspb.Message.setField(this, 10, value || []);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} value
|
||||
* @param {number=} opt_index
|
||||
*/
|
||||
proto.WorkingInit.prototype.addExtraBuiltinExtensionDirectories = function(value, opt_index) {
|
||||
jspb.Message.addToRepeatedField(this, 10, value, opt_index);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Clears the list making it empty but non-null.
|
||||
*/
|
||||
proto.WorkingInit.prototype.clearExtraBuiltinExtensionDirectoriesList = function() {
|
||||
this.setExtraBuiltinExtensionDirectoriesList([]);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* map<string, string> env = 11;
|
||||
* @param {boolean=} opt_noLazyCreate Do not create the map if
|
||||
* empty, instead returning `undefined`
|
||||
* @return {!jspb.Map<string,string>}
|
||||
*/
|
||||
proto.WorkingInit.prototype.getEnvMap = function(opt_noLazyCreate) {
|
||||
return /** @type {!jspb.Map<string,string>} */ (
|
||||
jspb.Message.getMapField(this, 11, opt_noLazyCreate,
|
||||
null));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Clears values from the map. The map will be non-null.
|
||||
*/
|
||||
proto.WorkingInit.prototype.clearEnvMap = function() {
|
||||
this.getEnvMap().clear();
|
||||
};
|
||||
|
||||
|
||||
goog.object.extend(exports, proto);
|
||||
|
||||
@@ -40,6 +40,10 @@ message Argument {
|
||||
|
||||
message UndefinedValue {}
|
||||
|
||||
message DateValue {
|
||||
string date = 1;
|
||||
}
|
||||
|
||||
oneof msg {
|
||||
ErrorValue error = 1;
|
||||
BufferValue buffer = 2;
|
||||
@@ -52,6 +56,7 @@ message Argument {
|
||||
double number = 9;
|
||||
string string = 10;
|
||||
bool boolean = 11;
|
||||
DateValue date = 12;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
27
packages/protocol/src/proto/node_pb.d.ts
vendored
27
packages/protocol/src/proto/node_pb.d.ts
vendored
@@ -59,6 +59,11 @@ export class Argument extends jspb.Message {
|
||||
getBoolean(): boolean;
|
||||
setBoolean(value: boolean): void;
|
||||
|
||||
hasDate(): boolean;
|
||||
clearDate(): void;
|
||||
getDate(): Argument.DateValue | undefined;
|
||||
setDate(value?: Argument.DateValue): void;
|
||||
|
||||
getMsgCase(): Argument.MsgCase;
|
||||
serializeBinary(): Uint8Array;
|
||||
toObject(includeInstance?: boolean): Argument.AsObject;
|
||||
@@ -83,6 +88,7 @@ export namespace Argument {
|
||||
number: number,
|
||||
string: string,
|
||||
pb_boolean: boolean,
|
||||
date?: Argument.DateValue.AsObject,
|
||||
}
|
||||
|
||||
export class ErrorValue extends jspb.Message {
|
||||
@@ -248,6 +254,26 @@ export namespace Argument {
|
||||
}
|
||||
}
|
||||
|
||||
export class DateValue extends jspb.Message {
|
||||
getDate(): string;
|
||||
setDate(value: string): void;
|
||||
|
||||
serializeBinary(): Uint8Array;
|
||||
toObject(includeInstance?: boolean): DateValue.AsObject;
|
||||
static toObject(includeInstance: boolean, msg: DateValue): DateValue.AsObject;
|
||||
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
|
||||
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
|
||||
static serializeBinaryToWriter(message: DateValue, writer: jspb.BinaryWriter): void;
|
||||
static deserializeBinary(bytes: Uint8Array): DateValue;
|
||||
static deserializeBinaryFromReader(message: DateValue, reader: jspb.BinaryReader): DateValue;
|
||||
}
|
||||
|
||||
export namespace DateValue {
|
||||
export type AsObject = {
|
||||
date: string,
|
||||
}
|
||||
}
|
||||
|
||||
export enum MsgCase {
|
||||
MSG_NOT_SET = 0,
|
||||
ERROR = 1,
|
||||
@@ -261,6 +287,7 @@ export namespace Argument {
|
||||
NUMBER = 9,
|
||||
STRING = 10,
|
||||
BOOLEAN = 11,
|
||||
DATE = 12,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ var global = Function('return this')();
|
||||
goog.exportSymbol('proto.Argument', null, global);
|
||||
goog.exportSymbol('proto.Argument.ArrayValue', null, global);
|
||||
goog.exportSymbol('proto.Argument.BufferValue', null, global);
|
||||
goog.exportSymbol('proto.Argument.DateValue', null, global);
|
||||
goog.exportSymbol('proto.Argument.ErrorValue', null, global);
|
||||
goog.exportSymbol('proto.Argument.FunctionValue', null, global);
|
||||
goog.exportSymbol('proto.Argument.NullValue', null, global);
|
||||
@@ -223,6 +224,27 @@ if (goog.DEBUG && !COMPILED) {
|
||||
*/
|
||||
proto.Argument.UndefinedValue.displayName = 'proto.Argument.UndefinedValue';
|
||||
}
|
||||
/**
|
||||
* Generated by JsPbCodeGenerator.
|
||||
* @param {Array=} opt_data Optional initial data array, typically from a
|
||||
* server response, or constructed directly in Javascript. The array is used
|
||||
* in place and becomes part of the constructed object. It is not cloned.
|
||||
* If no data is provided, the constructed object will be empty, but still
|
||||
* valid.
|
||||
* @extends {jspb.Message}
|
||||
* @constructor
|
||||
*/
|
||||
proto.Argument.DateValue = function(opt_data) {
|
||||
jspb.Message.initialize(this, opt_data, 0, -1, null, null);
|
||||
};
|
||||
goog.inherits(proto.Argument.DateValue, jspb.Message);
|
||||
if (goog.DEBUG && !COMPILED) {
|
||||
/**
|
||||
* @public
|
||||
* @override
|
||||
*/
|
||||
proto.Argument.DateValue.displayName = 'proto.Argument.DateValue';
|
||||
}
|
||||
/**
|
||||
* Generated by JsPbCodeGenerator.
|
||||
* @param {Array=} opt_data Optional initial data array, typically from a
|
||||
@@ -505,7 +527,7 @@ if (goog.DEBUG && !COMPILED) {
|
||||
* @private {!Array<!Array<number>>}
|
||||
* @const
|
||||
*/
|
||||
proto.Argument.oneofGroups_ = [[1,2,3,4,5,6,7,8,9,10,11]];
|
||||
proto.Argument.oneofGroups_ = [[1,2,3,4,5,6,7,8,9,10,11,12]];
|
||||
|
||||
/**
|
||||
* @enum {number}
|
||||
@@ -522,7 +544,8 @@ proto.Argument.MsgCase = {
|
||||
UNDEFINED: 8,
|
||||
NUMBER: 9,
|
||||
STRING: 10,
|
||||
BOOLEAN: 11
|
||||
BOOLEAN: 11,
|
||||
DATE: 12
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -560,7 +583,7 @@ proto.Argument.prototype.toObject = function(opt_includeInstance) {
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.Argument.toObject = function(includeInstance, msg) {
|
||||
var obj = {
|
||||
var f, obj = {
|
||||
error: (f = msg.getError()) && proto.Argument.ErrorValue.toObject(includeInstance, f),
|
||||
buffer: (f = msg.getBuffer()) && proto.Argument.BufferValue.toObject(includeInstance, f),
|
||||
object: (f = msg.getObject()) && proto.Argument.ObjectValue.toObject(includeInstance, f),
|
||||
@@ -571,7 +594,8 @@ proto.Argument.toObject = function(includeInstance, msg) {
|
||||
undefined: (f = msg.getUndefined()) && proto.Argument.UndefinedValue.toObject(includeInstance, f),
|
||||
number: +jspb.Message.getFieldWithDefault(msg, 9, 0.0),
|
||||
string: jspb.Message.getFieldWithDefault(msg, 10, ""),
|
||||
pb_boolean: jspb.Message.getFieldWithDefault(msg, 11, false)
|
||||
pb_boolean: jspb.Message.getFieldWithDefault(msg, 11, false),
|
||||
date: (f = msg.getDate()) && proto.Argument.DateValue.toObject(includeInstance, f)
|
||||
};
|
||||
|
||||
if (includeInstance) {
|
||||
@@ -660,6 +684,11 @@ proto.Argument.deserializeBinaryFromReader = function(msg, reader) {
|
||||
var value = /** @type {boolean} */ (reader.readBool());
|
||||
msg.setBoolean(value);
|
||||
break;
|
||||
case 12:
|
||||
var value = new proto.Argument.DateValue;
|
||||
reader.readMessage(value,proto.Argument.DateValue.deserializeBinaryFromReader);
|
||||
msg.setDate(value);
|
||||
break;
|
||||
default:
|
||||
reader.skipField();
|
||||
break;
|
||||
@@ -774,6 +803,14 @@ proto.Argument.serializeBinaryToWriter = function(message, writer) {
|
||||
f
|
||||
);
|
||||
}
|
||||
f = message.getDate();
|
||||
if (f != null) {
|
||||
writer.writeMessage(
|
||||
12,
|
||||
f,
|
||||
proto.Argument.DateValue.serializeBinaryToWriter
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -806,7 +843,7 @@ proto.Argument.ErrorValue.prototype.toObject = function(opt_includeInstance) {
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.Argument.ErrorValue.toObject = function(includeInstance, msg) {
|
||||
var obj = {
|
||||
var f, obj = {
|
||||
message: jspb.Message.getFieldWithDefault(msg, 1, ""),
|
||||
stack: jspb.Message.getFieldWithDefault(msg, 2, ""),
|
||||
code: jspb.Message.getFieldWithDefault(msg, 3, "")
|
||||
@@ -985,7 +1022,7 @@ proto.Argument.BufferValue.prototype.toObject = function(opt_includeInstance) {
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.Argument.BufferValue.toObject = function(includeInstance, msg) {
|
||||
var obj = {
|
||||
var f, obj = {
|
||||
data: msg.getData_asB64()
|
||||
};
|
||||
|
||||
@@ -1134,7 +1171,7 @@ proto.Argument.ObjectValue.prototype.toObject = function(opt_includeInstance) {
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.Argument.ObjectValue.toObject = function(includeInstance, msg) {
|
||||
var obj = {
|
||||
var f, obj = {
|
||||
dataMap: (f = msg.getDataMap()) ? f.toObject(includeInstance, proto.Argument.toObject) : []
|
||||
};
|
||||
|
||||
@@ -1271,7 +1308,7 @@ proto.Argument.ArrayValue.prototype.toObject = function(opt_includeInstance) {
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.Argument.ArrayValue.toObject = function(includeInstance, msg) {
|
||||
var obj = {
|
||||
var f, obj = {
|
||||
dataList: jspb.Message.toObjectList(msg.getDataList(),
|
||||
proto.Argument.toObject, includeInstance)
|
||||
};
|
||||
@@ -1418,7 +1455,7 @@ proto.Argument.ProxyValue.prototype.toObject = function(opt_includeInstance) {
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.Argument.ProxyValue.toObject = function(includeInstance, msg) {
|
||||
var obj = {
|
||||
var f, obj = {
|
||||
id: jspb.Message.getFieldWithDefault(msg, 1, 0)
|
||||
};
|
||||
|
||||
@@ -1543,7 +1580,7 @@ proto.Argument.FunctionValue.prototype.toObject = function(opt_includeInstance)
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.Argument.FunctionValue.toObject = function(includeInstance, msg) {
|
||||
var obj = {
|
||||
var f, obj = {
|
||||
id: jspb.Message.getFieldWithDefault(msg, 1, 0)
|
||||
};
|
||||
|
||||
@@ -1668,7 +1705,7 @@ proto.Argument.NullValue.prototype.toObject = function(opt_includeInstance) {
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.Argument.NullValue.toObject = function(includeInstance, msg) {
|
||||
var obj = {
|
||||
var f, obj = {
|
||||
|
||||
};
|
||||
|
||||
@@ -1767,7 +1804,7 @@ proto.Argument.UndefinedValue.prototype.toObject = function(opt_includeInstance)
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.Argument.UndefinedValue.toObject = function(includeInstance, msg) {
|
||||
var obj = {
|
||||
var f, obj = {
|
||||
|
||||
};
|
||||
|
||||
@@ -1837,6 +1874,131 @@ proto.Argument.UndefinedValue.serializeBinaryToWriter = function(message, writer
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if (jspb.Message.GENERATE_TO_OBJECT) {
|
||||
/**
|
||||
* Creates an object representation of this proto suitable for use in Soy templates.
|
||||
* Field names that are reserved in JavaScript and will be renamed to pb_name.
|
||||
* To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
|
||||
* For the list of reserved names please see:
|
||||
* com.google.apps.jspb.JsClassTemplate.JS_RESERVED_WORDS.
|
||||
* @param {boolean=} opt_includeInstance Whether to include the JSPB instance
|
||||
* for transitional soy proto support: http://goto/soy-param-migration
|
||||
* @return {!Object}
|
||||
*/
|
||||
proto.Argument.DateValue.prototype.toObject = function(opt_includeInstance) {
|
||||
return proto.Argument.DateValue.toObject(opt_includeInstance, this);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Static version of the {@see toObject} method.
|
||||
* @param {boolean|undefined} includeInstance Whether to include the JSPB
|
||||
* instance for transitional soy proto support:
|
||||
* http://goto/soy-param-migration
|
||||
* @param {!proto.Argument.DateValue} msg The msg instance to transform.
|
||||
* @return {!Object}
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.Argument.DateValue.toObject = function(includeInstance, msg) {
|
||||
var f, obj = {
|
||||
date: jspb.Message.getFieldWithDefault(msg, 1, "")
|
||||
};
|
||||
|
||||
if (includeInstance) {
|
||||
obj.$jspbMessageInstance = msg;
|
||||
}
|
||||
return obj;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Deserializes binary data (in protobuf wire format).
|
||||
* @param {jspb.ByteSource} bytes The bytes to deserialize.
|
||||
* @return {!proto.Argument.DateValue}
|
||||
*/
|
||||
proto.Argument.DateValue.deserializeBinary = function(bytes) {
|
||||
var reader = new jspb.BinaryReader(bytes);
|
||||
var msg = new proto.Argument.DateValue;
|
||||
return proto.Argument.DateValue.deserializeBinaryFromReader(msg, reader);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Deserializes binary data (in protobuf wire format) from the
|
||||
* given reader into the given message object.
|
||||
* @param {!proto.Argument.DateValue} msg The message object to deserialize into.
|
||||
* @param {!jspb.BinaryReader} reader The BinaryReader to use.
|
||||
* @return {!proto.Argument.DateValue}
|
||||
*/
|
||||
proto.Argument.DateValue.deserializeBinaryFromReader = function(msg, reader) {
|
||||
while (reader.nextField()) {
|
||||
if (reader.isEndGroup()) {
|
||||
break;
|
||||
}
|
||||
var field = reader.getFieldNumber();
|
||||
switch (field) {
|
||||
case 1:
|
||||
var value = /** @type {string} */ (reader.readString());
|
||||
msg.setDate(value);
|
||||
break;
|
||||
default:
|
||||
reader.skipField();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return msg;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Serializes the message to binary data (in protobuf wire format).
|
||||
* @return {!Uint8Array}
|
||||
*/
|
||||
proto.Argument.DateValue.prototype.serializeBinary = function() {
|
||||
var writer = new jspb.BinaryWriter();
|
||||
proto.Argument.DateValue.serializeBinaryToWriter(this, writer);
|
||||
return writer.getResultBuffer();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Serializes the given message to binary data (in protobuf wire
|
||||
* format), writing to the given BinaryWriter.
|
||||
* @param {!proto.Argument.DateValue} message
|
||||
* @param {!jspb.BinaryWriter} writer
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.Argument.DateValue.serializeBinaryToWriter = function(message, writer) {
|
||||
var f = undefined;
|
||||
f = message.getDate();
|
||||
if (f.length > 0) {
|
||||
writer.writeString(
|
||||
1,
|
||||
f
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional string date = 1;
|
||||
* @return {string}
|
||||
*/
|
||||
proto.Argument.DateValue.prototype.getDate = function() {
|
||||
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, ""));
|
||||
};
|
||||
|
||||
|
||||
/** @param {string} value */
|
||||
proto.Argument.DateValue.prototype.setDate = function(value) {
|
||||
jspb.Message.setProto3StringField(this, 1, value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional ErrorValue error = 1;
|
||||
* @return {?proto.Argument.ErrorValue}
|
||||
@@ -2199,6 +2361,39 @@ proto.Argument.prototype.hasBoolean = function() {
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional DateValue date = 12;
|
||||
* @return {?proto.Argument.DateValue}
|
||||
*/
|
||||
proto.Argument.prototype.getDate = function() {
|
||||
return /** @type{?proto.Argument.DateValue} */ (
|
||||
jspb.Message.getWrapperField(this, proto.Argument.DateValue, 12));
|
||||
};
|
||||
|
||||
|
||||
/** @param {?proto.Argument.DateValue|undefined} value */
|
||||
proto.Argument.prototype.setDate = function(value) {
|
||||
jspb.Message.setOneofWrapperField(this, 12, proto.Argument.oneofGroups_[0], value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Clears the message field making it undefined.
|
||||
*/
|
||||
proto.Argument.prototype.clearDate = function() {
|
||||
this.setDate(undefined);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns whether this field is set.
|
||||
* @return {boolean}
|
||||
*/
|
||||
proto.Argument.prototype.hasDate = function() {
|
||||
return jspb.Message.getField(this, 12) != null;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Oneof group definitions for this message. Each group defines the field
|
||||
@@ -2254,7 +2449,7 @@ proto.Method.prototype.toObject = function(opt_includeInstance) {
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.Method.toObject = function(includeInstance, msg) {
|
||||
var obj = {
|
||||
var f, obj = {
|
||||
namedProxy: (f = msg.getNamedProxy()) && proto.Method.Named.toObject(includeInstance, f),
|
||||
numberedProxy: (f = msg.getNumberedProxy()) && proto.Method.Numbered.toObject(includeInstance, f)
|
||||
};
|
||||
@@ -2387,7 +2582,7 @@ proto.Method.Named.prototype.toObject = function(opt_includeInstance) {
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.Method.Named.toObject = function(includeInstance, msg) {
|
||||
var obj = {
|
||||
var f, obj = {
|
||||
id: jspb.Message.getFieldWithDefault(msg, 1, 0),
|
||||
module: jspb.Message.getFieldWithDefault(msg, 2, 0),
|
||||
method: jspb.Message.getFieldWithDefault(msg, 3, ""),
|
||||
@@ -2622,7 +2817,7 @@ proto.Method.Numbered.prototype.toObject = function(opt_includeInstance) {
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.Method.Numbered.toObject = function(includeInstance, msg) {
|
||||
var obj = {
|
||||
var f, obj = {
|
||||
id: jspb.Message.getFieldWithDefault(msg, 1, 0),
|
||||
proxyId: jspb.Message.getFieldWithDefault(msg, 2, 0),
|
||||
method: jspb.Message.getFieldWithDefault(msg, 3, ""),
|
||||
@@ -2850,7 +3045,7 @@ proto.Method.Fail.prototype.toObject = function(opt_includeInstance) {
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.Method.Fail.toObject = function(includeInstance, msg) {
|
||||
var obj = {
|
||||
var f, obj = {
|
||||
id: jspb.Message.getFieldWithDefault(msg, 1, 0),
|
||||
response: (f = msg.getResponse()) && proto.Argument.toObject(includeInstance, f)
|
||||
};
|
||||
@@ -3022,7 +3217,7 @@ proto.Method.Success.prototype.toObject = function(opt_includeInstance) {
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.Method.Success.toObject = function(includeInstance, msg) {
|
||||
var obj = {
|
||||
var f, obj = {
|
||||
id: jspb.Message.getFieldWithDefault(msg, 1, 0),
|
||||
response: (f = msg.getResponse()) && proto.Argument.toObject(includeInstance, f)
|
||||
};
|
||||
@@ -3286,7 +3481,7 @@ proto.Callback.prototype.toObject = function(opt_includeInstance) {
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.Callback.toObject = function(includeInstance, msg) {
|
||||
var obj = {
|
||||
var f, obj = {
|
||||
namedCallback: (f = msg.getNamedCallback()) && proto.Callback.Named.toObject(includeInstance, f),
|
||||
numberedCallback: (f = msg.getNumberedCallback()) && proto.Callback.Numbered.toObject(includeInstance, f)
|
||||
};
|
||||
@@ -3419,7 +3614,7 @@ proto.Callback.Named.prototype.toObject = function(opt_includeInstance) {
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.Callback.Named.toObject = function(includeInstance, msg) {
|
||||
var obj = {
|
||||
var f, obj = {
|
||||
module: jspb.Message.getFieldWithDefault(msg, 1, 0),
|
||||
callbackId: jspb.Message.getFieldWithDefault(msg, 2, 0),
|
||||
argsList: jspb.Message.toObjectList(msg.getArgsList(),
|
||||
@@ -3627,7 +3822,7 @@ proto.Callback.Numbered.prototype.toObject = function(opt_includeInstance) {
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.Callback.Numbered.toObject = function(includeInstance, msg) {
|
||||
var obj = {
|
||||
var f, obj = {
|
||||
proxyId: jspb.Message.getFieldWithDefault(msg, 1, 0),
|
||||
callbackId: jspb.Message.getFieldWithDefault(msg, 2, 0),
|
||||
argsList: jspb.Message.toObjectList(msg.getArgsList(),
|
||||
@@ -3920,7 +4115,7 @@ proto.Event.prototype.toObject = function(opt_includeInstance) {
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.Event.toObject = function(includeInstance, msg) {
|
||||
var obj = {
|
||||
var f, obj = {
|
||||
namedEvent: (f = msg.getNamedEvent()) && proto.Event.Named.toObject(includeInstance, f),
|
||||
numberedEvent: (f = msg.getNumberedEvent()) && proto.Event.Numbered.toObject(includeInstance, f)
|
||||
};
|
||||
@@ -4053,7 +4248,7 @@ proto.Event.Named.prototype.toObject = function(opt_includeInstance) {
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.Event.Named.toObject = function(includeInstance, msg) {
|
||||
var obj = {
|
||||
var f, obj = {
|
||||
module: jspb.Message.getFieldWithDefault(msg, 1, 0),
|
||||
event: jspb.Message.getFieldWithDefault(msg, 2, ""),
|
||||
argsList: jspb.Message.toObjectList(msg.getArgsList(),
|
||||
@@ -4261,7 +4456,7 @@ proto.Event.Numbered.prototype.toObject = function(opt_includeInstance) {
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.Event.Numbered.toObject = function(includeInstance, msg) {
|
||||
var obj = {
|
||||
var f, obj = {
|
||||
proxyId: jspb.Message.getFieldWithDefault(msg, 1, 0),
|
||||
event: jspb.Message.getFieldWithDefault(msg, 2, ""),
|
||||
argsList: jspb.Message.toObjectList(msg.getArgsList(),
|
||||
@@ -4528,7 +4723,7 @@ proto.Ping.prototype.toObject = function(opt_includeInstance) {
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.Ping.toObject = function(includeInstance, msg) {
|
||||
var obj = {
|
||||
var f, obj = {
|
||||
|
||||
};
|
||||
|
||||
@@ -4627,7 +4822,7 @@ proto.Pong.prototype.toObject = function(opt_includeInstance) {
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.Pong.toObject = function(includeInstance, msg) {
|
||||
var obj = {
|
||||
var f, obj = {
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ proto.SharedProcessActive.prototype.toObject = function(opt_includeInstance) {
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.SharedProcessActive.toObject = function(includeInstance, msg) {
|
||||
var obj = {
|
||||
var f, obj = {
|
||||
socketPath: jspb.Message.getFieldWithDefault(msg, 1, ""),
|
||||
logPath: jspb.Message.getFieldWithDefault(msg, 2, "")
|
||||
};
|
||||
|
||||
@@ -10,7 +10,7 @@ describe("child_process", () => {
|
||||
const cp = client.modules[Module.ChildProcess];
|
||||
|
||||
const getStdout = async (proc: ChildProcess): Promise<string> => {
|
||||
return new Promise((r): Readable => proc.stdout!.on("data", r))
|
||||
return new Promise((r): Readable => proc.stdout!.once("data", r))
|
||||
.then((s) => s.toString());
|
||||
};
|
||||
|
||||
@@ -53,6 +53,11 @@ describe("child_process", () => {
|
||||
|
||||
await expect(getStdout(proc)).resolves.toContain("hi=donkey\n");
|
||||
});
|
||||
|
||||
it("should eval", async () => {
|
||||
const proc = cp.spawn("node", ["-e", "console.log('foo')"]);
|
||||
await expect(getStdout(proc)).resolves.toContain("foo");
|
||||
});
|
||||
});
|
||||
|
||||
describe("fork", () => {
|
||||
|
||||
@@ -4,6 +4,8 @@ import * as util from "util";
|
||||
import { Module } from "../src/common/proxy";
|
||||
import { createClient, Helper } from "./helpers";
|
||||
|
||||
// tslint:disable deprecation to use fs.exists
|
||||
|
||||
describe("fs", () => {
|
||||
const client = createClient();
|
||||
// tslint:disable-next-line no-any
|
||||
@@ -68,12 +70,12 @@ describe("fs", () => {
|
||||
describe("chown", () => {
|
||||
it("should chown existing file", async () => {
|
||||
const file = await helper.createTmpFile();
|
||||
await expect(util.promisify(fs.chown)(file, 1, 1))
|
||||
await expect(util.promisify(nativeFs.chown)(file, 1000, 1000))
|
||||
.resolves.toBeUndefined();
|
||||
});
|
||||
|
||||
it("should fail to chown nonexistent file", async () => {
|
||||
await expect(util.promisify(fs.chown)(helper.tmpFile(), 1, 1))
|
||||
await expect(util.promisify(fs.chown)(helper.tmpFile(), 1000, 1000))
|
||||
.rejects.toThrow("ENOENT");
|
||||
});
|
||||
});
|
||||
@@ -129,6 +131,42 @@ describe("fs", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("createReadStream", () => {
|
||||
it("should read a file", async () => {
|
||||
const file = helper.tmpFile();
|
||||
const content = "foobar";
|
||||
await util.promisify(nativeFs.writeFile)(file, content);
|
||||
|
||||
const reader = fs.createReadStream(file);
|
||||
|
||||
await expect(new Promise((resolve, reject): void => {
|
||||
let data = "";
|
||||
reader.once("error", reject);
|
||||
reader.once("end", () => resolve(data));
|
||||
reader.on("data", (d) => data += d.toString());
|
||||
})).resolves.toBe(content);
|
||||
});
|
||||
|
||||
it("should pipe to a writable stream", async () => {
|
||||
const source = helper.tmpFile();
|
||||
const content = "foo";
|
||||
await util.promisify(nativeFs.writeFile)(source, content);
|
||||
|
||||
const destination = helper.tmpFile();
|
||||
const reader = fs.createReadStream(source);
|
||||
const writer = fs.createWriteStream(destination);
|
||||
|
||||
await new Promise((resolve, reject): void => {
|
||||
reader.once("error", reject);
|
||||
writer.once("error", reject);
|
||||
writer.once("close", resolve);
|
||||
reader.pipe(writer);
|
||||
});
|
||||
|
||||
await expect(util.promisify(nativeFs.readFile)(destination, "utf8")).resolves.toBe(content);
|
||||
});
|
||||
});
|
||||
|
||||
describe("exists", () => {
|
||||
it("should output file exists", async () => {
|
||||
await expect(util.promisify(fs.exists)(__filename))
|
||||
@@ -160,13 +198,13 @@ describe("fs", () => {
|
||||
it("should fchown existing file", async () => {
|
||||
const file = await helper.createTmpFile();
|
||||
const fd = await util.promisify(nativeFs.open)(file, "r");
|
||||
await expect(util.promisify(fs.fchown)(fd, 1, 1))
|
||||
await expect(util.promisify(fs.fchown)(fd, 1000, 1000))
|
||||
.resolves.toBeUndefined();
|
||||
await util.promisify(nativeFs.close)(fd);
|
||||
});
|
||||
|
||||
it("should fail to fchown nonexistent file", async () => {
|
||||
await expect(util.promisify(fs.fchown)(99999, 1, 1))
|
||||
await expect(util.promisify(fs.fchown)(99999, 1000, 1000))
|
||||
.rejects.toThrow("EBADF");
|
||||
});
|
||||
});
|
||||
@@ -237,7 +275,15 @@ describe("fs", () => {
|
||||
it("should futimes existing file", async () => {
|
||||
const file = await helper.createTmpFile();
|
||||
const fd = await util.promisify(nativeFs.open)(file, "w");
|
||||
await expect(util.promisify(fs.futimes)(fd, 1, 1))
|
||||
await expect(util.promisify(fs.futimes)(fd, 1000, 1000))
|
||||
.resolves.toBeUndefined();
|
||||
await util.promisify(nativeFs.close)(fd);
|
||||
});
|
||||
|
||||
it("should futimes existing file with date", async () => {
|
||||
const file = await helper.createTmpFile();
|
||||
const fd = await util.promisify(nativeFs.open)(file, "w");
|
||||
await expect(util.promisify(fs.futimes)(fd, new Date(), new Date()))
|
||||
.resolves.toBeUndefined();
|
||||
await util.promisify(nativeFs.close)(fd);
|
||||
});
|
||||
@@ -265,14 +311,13 @@ describe("fs", () => {
|
||||
describe("lchown", () => {
|
||||
it("should lchown existing file", async () => {
|
||||
const file = await helper.createTmpFile();
|
||||
await expect(util.promisify(fs.lchown)(file, 1, 1))
|
||||
await expect(util.promisify(fs.lchown)(file, 1000, 1000))
|
||||
.resolves.toBeUndefined();
|
||||
});
|
||||
|
||||
// TODO: Doesn't fail on my system?
|
||||
it("should fail to lchown nonexistent file", async () => {
|
||||
await expect(util.promisify(fs.lchown)(helper.tmpFile(), 1, 1))
|
||||
.resolves.toBeUndefined();
|
||||
await expect(util.promisify(fs.lchown)(helper.tmpFile(), 1000, 1000))
|
||||
.rejects.toThrow("ENOENT");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -346,7 +391,7 @@ describe("fs", () => {
|
||||
it("should read existing file", async () => {
|
||||
const fd = await util.promisify(nativeFs.open)(__filename, "r");
|
||||
const stat = await util.promisify(nativeFs.fstat)(fd);
|
||||
const buffer = new Buffer(stat.size);
|
||||
const buffer = Buffer.alloc(stat.size);
|
||||
let bytesRead = 0;
|
||||
let chunkSize = 2048;
|
||||
while (bytesRead < stat.size) {
|
||||
@@ -364,7 +409,7 @@ describe("fs", () => {
|
||||
});
|
||||
|
||||
it("should fail to read nonexistent file", async () => {
|
||||
await expect(util.promisify(fs.read)(99999, new Buffer(10), 9999, 999, 999))
|
||||
await expect(util.promisify(fs.read)(99999, Buffer.alloc(10), 9999, 999, 999))
|
||||
.rejects.toThrow("EBADF");
|
||||
});
|
||||
});
|
||||
@@ -466,6 +511,7 @@ describe("fs", () => {
|
||||
expect(stat).toMatchObject({
|
||||
size: nativeStat.size,
|
||||
});
|
||||
expect(typeof stat.mtime.getTime()).toBe("number");
|
||||
expect(stat.isFile()).toBe(true);
|
||||
});
|
||||
|
||||
@@ -493,7 +539,7 @@ describe("fs", () => {
|
||||
const destination = helper.tmpFile();
|
||||
await expect(util.promisify(fs.symlink)(source, destination))
|
||||
.resolves.toBeUndefined();
|
||||
expect(util.promisify(nativeFs.exists)(source))
|
||||
await expect(util.promisify(nativeFs.exists)(source))
|
||||
.resolves.toBe(true);
|
||||
});
|
||||
|
||||
@@ -525,7 +571,7 @@ describe("fs", () => {
|
||||
const file = await helper.createTmpFile();
|
||||
await expect(util.promisify(fs.unlink)(file))
|
||||
.resolves.toBeUndefined();
|
||||
expect(util.promisify(nativeFs.exists)(file))
|
||||
await expect(util.promisify(nativeFs.exists)(file))
|
||||
.resolves.toBe(false);
|
||||
});
|
||||
|
||||
@@ -575,7 +621,10 @@ describe("fs", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("should dispose", () => {
|
||||
it("should dispose", (done) => {
|
||||
setTimeout(() => {
|
||||
client.dispose();
|
||||
done();
|
||||
}, 100);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -38,6 +38,23 @@ describe("net", () => {
|
||||
expect(fn).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("should remove event listener", async () => {
|
||||
const socket = new net.Socket();
|
||||
|
||||
const fn1 = jest.fn();
|
||||
const fn2 = jest.fn();
|
||||
|
||||
socket.on("error", fn1);
|
||||
socket.on("error", fn2);
|
||||
socket.off("error", fn1);
|
||||
|
||||
socket.connect("/tmp/t/e/s/t/d/o/e/s/n/o/t/e/x/i/s/t");
|
||||
|
||||
await new Promise((r): nativeNet.Socket => socket.on("close", r));
|
||||
expect(fn1).toHaveBeenCalledTimes(0);
|
||||
expect(fn2).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("should connect", async () => {
|
||||
await new Promise((resolve): void => {
|
||||
const socket = net.createConnection(socketPath, () => {
|
||||
|
||||
@@ -3,9 +3,11 @@ import { createClient } from "./helpers";
|
||||
describe("Server", () => {
|
||||
const dataDirectory = "/tmp/example";
|
||||
const workingDirectory = "/working/dir";
|
||||
const extensionsDirectory = "/tmp/example";
|
||||
const builtInExtensionsDirectory = "/tmp/example";
|
||||
const cacheDirectory = "/tmp/cache";
|
||||
const client = createClient({
|
||||
extensionsDirectory,
|
||||
builtInExtensionsDirectory,
|
||||
cacheDirectory,
|
||||
dataDirectory,
|
||||
|
||||
@@ -27,9 +27,10 @@ describe("spdlog", () => {
|
||||
.toContain("critical");
|
||||
});
|
||||
|
||||
it("should dispose", () => {
|
||||
it("should dispose", (done) => {
|
||||
setTimeout(() => {
|
||||
client.dispose();
|
||||
done();
|
||||
}, 100);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,6 +3,8 @@ import * as util from "util";
|
||||
import { Module } from "../src/common/proxy";
|
||||
import { createClient, Helper } from "./helpers";
|
||||
|
||||
// tslint:disable deprecation to use fs.exists
|
||||
|
||||
describe("trash", () => {
|
||||
const client = createClient();
|
||||
const trash = client.modules[Module.Trash];
|
||||
@@ -18,9 +20,10 @@ describe("trash", () => {
|
||||
expect(await util.promisify(fs.exists)(file)).toBeFalsy();
|
||||
});
|
||||
|
||||
it("should dispose", () => {
|
||||
it("should dispose", (done) => {
|
||||
setTimeout(() => {
|
||||
client.dispose();
|
||||
done();
|
||||
}, 100);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -64,29 +64,6 @@ accepts@~1.3.5:
|
||||
mime-types "~2.1.18"
|
||||
negotiator "0.6.1"
|
||||
|
||||
ansi-regex@^2.0.0:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
|
||||
integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8=
|
||||
|
||||
ansi-regex@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998"
|
||||
integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=
|
||||
|
||||
aproba@^1.0.3:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a"
|
||||
integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==
|
||||
|
||||
are-we-there-yet@~1.1.2:
|
||||
version "1.1.5"
|
||||
resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21"
|
||||
integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==
|
||||
dependencies:
|
||||
delegates "^1.0.0"
|
||||
readable-stream "^2.0.6"
|
||||
|
||||
array-flatten@1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2"
|
||||
@@ -114,21 +91,6 @@ balanced-match@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
|
||||
integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
|
||||
|
||||
bindings@^1.3.0:
|
||||
version "1.5.0"
|
||||
resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df"
|
||||
integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==
|
||||
dependencies:
|
||||
file-uri-to-path "1.0.0"
|
||||
|
||||
bl@^1.0.0:
|
||||
version "1.2.2"
|
||||
resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.2.tgz#a160911717103c07410cef63ef51b397c025af9c"
|
||||
integrity sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==
|
||||
dependencies:
|
||||
readable-stream "^2.3.5"
|
||||
safe-buffer "^5.1.1"
|
||||
|
||||
body-parser@1.18.3:
|
||||
version "1.18.3"
|
||||
resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.18.3.tgz#5b292198ffdd553b3a0f20ded0592b956955c8b4"
|
||||
@@ -153,49 +115,16 @@ brace-expansion@^1.1.7:
|
||||
balanced-match "^1.0.0"
|
||||
concat-map "0.0.1"
|
||||
|
||||
buffer-alloc-unsafe@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0"
|
||||
integrity sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==
|
||||
|
||||
buffer-alloc@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec"
|
||||
integrity sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==
|
||||
dependencies:
|
||||
buffer-alloc-unsafe "^1.1.0"
|
||||
buffer-fill "^1.0.0"
|
||||
|
||||
buffer-fill@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c"
|
||||
integrity sha1-+PeLdniYiO858gXNY39o5wISKyw=
|
||||
|
||||
bytes@3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048"
|
||||
integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=
|
||||
|
||||
chownr@^1.0.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.1.tgz#54726b8b8fff4df053c42187e801fb4412df1494"
|
||||
integrity sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==
|
||||
|
||||
code-point-at@^1.0.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
|
||||
integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=
|
||||
|
||||
concat-map@0.0.1:
|
||||
version "0.0.1"
|
||||
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
|
||||
integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
|
||||
|
||||
console-control-strings@^1.0.0, console-control-strings@~1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
|
||||
integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=
|
||||
|
||||
content-disposition@0.5.2:
|
||||
version "0.5.2"
|
||||
resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4"
|
||||
@@ -216,11 +145,6 @@ cookie@0.3.1:
|
||||
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb"
|
||||
integrity sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=
|
||||
|
||||
core-util-is@~1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
|
||||
integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
|
||||
|
||||
cross-spawn-async@^2.1.1:
|
||||
version "2.2.5"
|
||||
resolved "https://registry.yarnpkg.com/cross-spawn-async/-/cross-spawn-async-2.2.5.tgz#845ff0c0834a3ded9d160daca6d390906bb288cc"
|
||||
@@ -247,23 +171,6 @@ debug@2.6.9:
|
||||
dependencies:
|
||||
ms "2.0.0"
|
||||
|
||||
decompress-response@^3.3.0:
|
||||
version "3.3.0"
|
||||
resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3"
|
||||
integrity sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=
|
||||
dependencies:
|
||||
mimic-response "^1.0.0"
|
||||
|
||||
deep-extend@^0.6.0:
|
||||
version "0.6.0"
|
||||
resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac"
|
||||
integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==
|
||||
|
||||
delegates@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
|
||||
integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=
|
||||
|
||||
depd@~1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
|
||||
@@ -274,11 +181,6 @@ destroy@~1.0.4:
|
||||
resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80"
|
||||
integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=
|
||||
|
||||
detect-libc@^1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b"
|
||||
integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=
|
||||
|
||||
dir-glob@^2.0.0:
|
||||
version "2.2.2"
|
||||
resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-2.2.2.tgz#fa09f0694153c8918b18ba0deafae94769fc50c4"
|
||||
@@ -296,13 +198,6 @@ encodeurl@~1.0.2:
|
||||
resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
|
||||
integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=
|
||||
|
||||
end-of-stream@^1.0.0, end-of-stream@^1.1.0:
|
||||
version "1.4.1"
|
||||
resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43"
|
||||
integrity sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==
|
||||
dependencies:
|
||||
once "^1.4.0"
|
||||
|
||||
escape-html@~1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
|
||||
@@ -342,11 +237,6 @@ execa@^0.2.2:
|
||||
path-key "^1.0.0"
|
||||
strip-eof "^1.0.0"
|
||||
|
||||
expand-template@^2.0.3:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c"
|
||||
integrity sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==
|
||||
|
||||
express@^4.16.4:
|
||||
version "4.16.4"
|
||||
resolved "https://registry.yarnpkg.com/express/-/express-4.16.4.tgz#fddef61926109e24c515ea97fd2f1bdbf62df12e"
|
||||
@@ -383,11 +273,6 @@ express@^4.16.4:
|
||||
utils-merge "1.0.1"
|
||||
vary "~1.1.2"
|
||||
|
||||
file-uri-to-path@1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd"
|
||||
integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==
|
||||
|
||||
finalhandler@1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.1.tgz#eebf4ed840079c83f4249038c9d703008301b105"
|
||||
@@ -411,11 +296,6 @@ fresh@0.5.2:
|
||||
resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
|
||||
integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=
|
||||
|
||||
fs-constants@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad"
|
||||
integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==
|
||||
|
||||
fs-extra@^0.30.0:
|
||||
version "0.30.0"
|
||||
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.30.0.tgz#f233ffcc08d4da7d432daa449776989db1df93f0"
|
||||
@@ -432,30 +312,11 @@ fs.realpath@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
|
||||
integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
|
||||
|
||||
gauge@~2.7.3:
|
||||
version "2.7.4"
|
||||
resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7"
|
||||
integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=
|
||||
dependencies:
|
||||
aproba "^1.0.3"
|
||||
console-control-strings "^1.0.0"
|
||||
has-unicode "^2.0.0"
|
||||
object-assign "^4.1.0"
|
||||
signal-exit "^3.0.0"
|
||||
string-width "^1.0.1"
|
||||
strip-ansi "^3.0.1"
|
||||
wide-align "^1.1.0"
|
||||
|
||||
get-stream@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14"
|
||||
integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=
|
||||
|
||||
github-from-package@0.0.0:
|
||||
version "0.0.0"
|
||||
resolved "https://registry.yarnpkg.com/github-from-package/-/github-from-package-0.0.0.tgz#97fb5d96bfde8973313f20e8288ef9a167fa64ce"
|
||||
integrity sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4=
|
||||
|
||||
glob@^7.1.2, glob@^7.1.3:
|
||||
version "7.1.3"
|
||||
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1"
|
||||
@@ -490,11 +351,6 @@ graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9:
|
||||
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00"
|
||||
integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==
|
||||
|
||||
has-unicode@^2.0.0:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
|
||||
integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=
|
||||
|
||||
http-errors@1.6.3, http-errors@~1.6.2, http-errors@~1.6.3:
|
||||
version "1.6.3"
|
||||
resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d"
|
||||
@@ -525,43 +381,21 @@ inflight@^1.0.4:
|
||||
once "^1.3.0"
|
||||
wrappy "1"
|
||||
|
||||
inherits@2, inherits@2.0.3, inherits@~2.0.3:
|
||||
inherits@2, inherits@2.0.3:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
|
||||
integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
|
||||
|
||||
ini@~1.3.0:
|
||||
version "1.3.5"
|
||||
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927"
|
||||
integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==
|
||||
|
||||
ipaddr.js@1.8.0:
|
||||
version "1.8.0"
|
||||
resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.8.0.tgz#eaa33d6ddd7ace8f7f6fe0c9ca0440e706738b1e"
|
||||
integrity sha1-6qM9bd16zo9/b+DJygRA5wZzix4=
|
||||
|
||||
is-fullwidth-code-point@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb"
|
||||
integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs=
|
||||
dependencies:
|
||||
number-is-nan "^1.0.0"
|
||||
|
||||
is-fullwidth-code-point@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f"
|
||||
integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=
|
||||
|
||||
is-stream@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
|
||||
integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ=
|
||||
|
||||
isarray@~1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
|
||||
integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
|
||||
|
||||
isexe@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
|
||||
@@ -621,11 +455,6 @@ mime@1.4.1:
|
||||
resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6"
|
||||
integrity sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==
|
||||
|
||||
mimic-response@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b"
|
||||
integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==
|
||||
|
||||
minimatch@^3.0.4:
|
||||
version "3.0.4"
|
||||
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
|
||||
@@ -633,23 +462,6 @@ minimatch@^3.0.4:
|
||||
dependencies:
|
||||
brace-expansion "^1.1.7"
|
||||
|
||||
minimist@0.0.8:
|
||||
version "0.0.8"
|
||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
|
||||
integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=
|
||||
|
||||
minimist@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
|
||||
integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=
|
||||
|
||||
mkdirp@^0.5.1:
|
||||
version "0.5.1"
|
||||
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
|
||||
integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=
|
||||
dependencies:
|
||||
minimist "0.0.8"
|
||||
|
||||
mount-point@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/mount-point/-/mount-point-3.0.0.tgz#665cb9edebe80d110e658db56c31d0aef51a8f97"
|
||||
@@ -664,21 +476,6 @@ ms@2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
|
||||
integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
|
||||
|
||||
nan@2.10.0:
|
||||
version "2.10.0"
|
||||
resolved "https://registry.yarnpkg.com/nan/-/nan-2.10.0.tgz#96d0cd610ebd58d4b4de9cc0c6828cda99c7548f"
|
||||
integrity sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==
|
||||
|
||||
nan@^2.8.0:
|
||||
version "2.12.1"
|
||||
resolved "https://registry.yarnpkg.com/nan/-/nan-2.12.1.tgz#7b1aa193e9aa86057e3c7bbd0ac448e770925552"
|
||||
integrity sha512-JY7V6lRkStKcKTvHO5NVSQRv+RV+FIL5pvDoLiAtSL9pKlC5x9PKQcZDsq7m4FO4d57mkhC6Z+QhAh3Jdk5JFw==
|
||||
|
||||
napi-build-utils@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/napi-build-utils/-/napi-build-utils-1.0.1.tgz#1381a0f92c39d66bf19852e7873432fc2123e508"
|
||||
integrity sha512-boQj1WFgQH3v4clhu3mTNfP+vOBxorDlE8EKiMjUlLG3C4qAESnn9AxIOkFgTR2c9LtzNjPrjS60cT27ZKBhaA==
|
||||
|
||||
negotiator@0.6.1:
|
||||
version "0.6.1"
|
||||
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9"
|
||||
@@ -689,26 +486,6 @@ nice-try@^1.0.4:
|
||||
resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366"
|
||||
integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==
|
||||
|
||||
node-abi@^2.7.0:
|
||||
version "2.7.1"
|
||||
resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.7.1.tgz#a8997ae91176a5fbaa455b194976e32683cda643"
|
||||
integrity sha512-OV8Bq1OrPh6z+Y4dqwo05HqrRL9YNF7QVMRfq1/pguwKLG+q9UB/Lk0x5qXjO23JjJg+/jqCHSTaG1P3tfKfuw==
|
||||
dependencies:
|
||||
semver "^5.4.1"
|
||||
|
||||
node-pty-prebuilt@^0.7.6:
|
||||
version "0.7.6"
|
||||
resolved "https://registry.yarnpkg.com/node-pty-prebuilt/-/node-pty-prebuilt-0.7.6.tgz#c04c41e40a527ed894bf0ee801f40e5fd6f5faf6"
|
||||
integrity sha512-aD/77N6WmohtWMhdHaBMunOihpZzDcp5Ig1cHsmtYNxl5NU8+3r9aGkfbKWUDYrPQaFgbJEAWfGeb3NFYd1+0g==
|
||||
dependencies:
|
||||
nan "2.10.0"
|
||||
prebuild-install "^5.0.0"
|
||||
|
||||
noop-logger@^0.1.1:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/noop-logger/-/noop-logger-0.1.1.tgz#94a2b1633c4f1317553007d8966fd0e841b6a4c2"
|
||||
integrity sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI=
|
||||
|
||||
npm-run-path@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-1.0.0.tgz#f5c32bf595fe81ae927daec52e82f8b000ac3c8f"
|
||||
@@ -723,22 +500,7 @@ npm-run-path@^2.0.0:
|
||||
dependencies:
|
||||
path-key "^2.0.0"
|
||||
|
||||
npmlog@^4.0.1:
|
||||
version "4.1.2"
|
||||
resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b"
|
||||
integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==
|
||||
dependencies:
|
||||
are-we-there-yet "~1.1.2"
|
||||
console-control-strings "~1.1.0"
|
||||
gauge "~2.7.3"
|
||||
set-blocking "~2.0.0"
|
||||
|
||||
number-is-nan@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
|
||||
integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=
|
||||
|
||||
object-assign@^4.0.1, object-assign@^4.1.0:
|
||||
object-assign@^4.0.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
||||
integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
|
||||
@@ -750,14 +512,14 @@ on-finished@~2.3.0:
|
||||
dependencies:
|
||||
ee-first "1.1.1"
|
||||
|
||||
once@^1.3.0, once@^1.3.1, once@^1.4.0:
|
||||
once@^1.3.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
|
||||
integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
|
||||
dependencies:
|
||||
wrappy "1"
|
||||
|
||||
os-homedir@^1.0.0, os-homedir@^1.0.1:
|
||||
os-homedir@^1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3"
|
||||
integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M=
|
||||
@@ -831,33 +593,6 @@ pinkie@^2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870"
|
||||
integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA=
|
||||
|
||||
prebuild-install@^5.0.0:
|
||||
version "5.2.5"
|
||||
resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-5.2.5.tgz#c7485911fe98950b7f7cd15bb9daee11b875cc44"
|
||||
integrity sha512-6uZgMVg7yDfqlP5CPurVhtq3hUKBFNufiar4J5hZrlHTo59DDBEtyxw01xCdFss9j0Zb9+qzFVf/s4niayba3w==
|
||||
dependencies:
|
||||
detect-libc "^1.0.3"
|
||||
expand-template "^2.0.3"
|
||||
github-from-package "0.0.0"
|
||||
minimist "^1.2.0"
|
||||
mkdirp "^0.5.1"
|
||||
napi-build-utils "^1.0.1"
|
||||
node-abi "^2.7.0"
|
||||
noop-logger "^0.1.1"
|
||||
npmlog "^4.0.1"
|
||||
os-homedir "^1.0.1"
|
||||
pump "^2.0.1"
|
||||
rc "^1.2.7"
|
||||
simple-get "^2.7.0"
|
||||
tar-fs "^1.13.0"
|
||||
tunnel-agent "^0.6.0"
|
||||
which-pm-runs "^1.0.0"
|
||||
|
||||
process-nextick-args@~2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa"
|
||||
integrity sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==
|
||||
|
||||
proxy-addr@~2.0.4:
|
||||
version "2.0.4"
|
||||
resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.4.tgz#ecfc733bf22ff8c6f407fa275327b9ab67e48b93"
|
||||
@@ -871,22 +606,6 @@ pseudomap@^1.0.2:
|
||||
resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3"
|
||||
integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM=
|
||||
|
||||
pump@^1.0.0:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/pump/-/pump-1.0.3.tgz#5dfe8311c33bbf6fc18261f9f34702c47c08a954"
|
||||
integrity sha512-8k0JupWme55+9tCVE+FS5ULT3K6AbgqrGa58lTT49RpyfwwcGedHqaC5LlQNdEAumn/wFsu6aPwkuPMioy8kqw==
|
||||
dependencies:
|
||||
end-of-stream "^1.1.0"
|
||||
once "^1.3.1"
|
||||
|
||||
pump@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909"
|
||||
integrity sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==
|
||||
dependencies:
|
||||
end-of-stream "^1.1.0"
|
||||
once "^1.3.1"
|
||||
|
||||
qs@6.5.2:
|
||||
version "6.5.2"
|
||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
|
||||
@@ -907,29 +626,6 @@ raw-body@2.3.3:
|
||||
iconv-lite "0.4.23"
|
||||
unpipe "1.0.0"
|
||||
|
||||
rc@^1.2.7:
|
||||
version "1.2.8"
|
||||
resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed"
|
||||
integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==
|
||||
dependencies:
|
||||
deep-extend "^0.6.0"
|
||||
ini "~1.3.0"
|
||||
minimist "^1.2.0"
|
||||
strip-json-comments "~2.0.1"
|
||||
|
||||
readable-stream@^2.0.6, readable-stream@^2.3.0, readable-stream@^2.3.5:
|
||||
version "2.3.6"
|
||||
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf"
|
||||
integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==
|
||||
dependencies:
|
||||
core-util-is "~1.0.0"
|
||||
inherits "~2.0.3"
|
||||
isarray "~1.0.0"
|
||||
process-nextick-args "~2.0.0"
|
||||
safe-buffer "~5.1.1"
|
||||
string_decoder "~1.1.1"
|
||||
util-deprecate "~1.0.1"
|
||||
|
||||
rimraf@^2.2.8, rimraf@^2.6.3:
|
||||
version "2.6.3"
|
||||
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab"
|
||||
@@ -944,7 +640,7 @@ run-applescript@^3.0.0:
|
||||
dependencies:
|
||||
execa "^0.10.0"
|
||||
|
||||
safe-buffer@5.1.2, safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
|
||||
safe-buffer@5.1.2:
|
||||
version "5.1.2"
|
||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
|
||||
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
|
||||
@@ -954,7 +650,7 @@ safe-buffer@5.1.2, safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@~5.1.0, s
|
||||
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
|
||||
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
|
||||
|
||||
semver@^5.4.1, semver@^5.5.0:
|
||||
semver@^5.5.0:
|
||||
version "5.6.0"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004"
|
||||
integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==
|
||||
@@ -988,11 +684,6 @@ serve-static@1.13.2:
|
||||
parseurl "~1.3.2"
|
||||
send "0.16.2"
|
||||
|
||||
set-blocking@~2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
|
||||
integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc=
|
||||
|
||||
setprototypeof@1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656"
|
||||
@@ -1015,34 +706,11 @@ signal-exit@^3.0.0:
|
||||
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
|
||||
integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=
|
||||
|
||||
simple-concat@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.0.tgz#7344cbb8b6e26fb27d66b2fc86f9f6d5997521c6"
|
||||
integrity sha1-c0TLuLbib7J9ZrL8hvn21Zl1IcY=
|
||||
|
||||
simple-get@^2.7.0:
|
||||
version "2.8.1"
|
||||
resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-2.8.1.tgz#0e22e91d4575d87620620bc91308d57a77f44b5d"
|
||||
integrity sha512-lSSHRSw3mQNUGPAYRqo7xy9dhKmxFXIjLjp4KHpf99GEH2VH7C3AM+Qfx6du6jhfUi6Vm7XnbEVEf7Wb6N8jRw==
|
||||
dependencies:
|
||||
decompress-response "^3.3.0"
|
||||
once "^1.3.1"
|
||||
simple-concat "^1.0.0"
|
||||
|
||||
slash@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55"
|
||||
integrity sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=
|
||||
|
||||
spdlog@^0.7.2:
|
||||
version "0.7.2"
|
||||
resolved "https://registry.yarnpkg.com/spdlog/-/spdlog-0.7.2.tgz#9298753d7694b9ee9bbfd7e01ea1e4c6ace1e64d"
|
||||
integrity sha512-rHfWCaWMD4NindDnql6rc6kn7Bs8JR92jhiUpCl3D6v+jYcQ6GozMLig0RliOOR8st5mU+IHLZnr15fBys5x/Q==
|
||||
dependencies:
|
||||
bindings "^1.3.0"
|
||||
mkdirp "^0.5.1"
|
||||
nan "^2.8.0"
|
||||
|
||||
"statuses@>= 1.4.0 < 2":
|
||||
version "1.5.0"
|
||||
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
|
||||
@@ -1053,87 +721,16 @@ statuses@~1.4.0:
|
||||
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087"
|
||||
integrity sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==
|
||||
|
||||
string-width@^1.0.1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"
|
||||
integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=
|
||||
dependencies:
|
||||
code-point-at "^1.0.0"
|
||||
is-fullwidth-code-point "^1.0.0"
|
||||
strip-ansi "^3.0.0"
|
||||
|
||||
"string-width@^1.0.2 || 2":
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e"
|
||||
integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==
|
||||
dependencies:
|
||||
is-fullwidth-code-point "^2.0.0"
|
||||
strip-ansi "^4.0.0"
|
||||
|
||||
string_decoder@~1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
|
||||
integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==
|
||||
dependencies:
|
||||
safe-buffer "~5.1.0"
|
||||
|
||||
strip-ansi@^3.0.0, strip-ansi@^3.0.1:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
|
||||
integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=
|
||||
dependencies:
|
||||
ansi-regex "^2.0.0"
|
||||
|
||||
strip-ansi@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f"
|
||||
integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8=
|
||||
dependencies:
|
||||
ansi-regex "^3.0.0"
|
||||
|
||||
strip-eof@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf"
|
||||
integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=
|
||||
|
||||
strip-json-comments@~2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
|
||||
integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo=
|
||||
|
||||
tar-fs@^1.13.0:
|
||||
version "1.16.3"
|
||||
resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-1.16.3.tgz#966a628841da2c4010406a82167cbd5e0c72d509"
|
||||
integrity sha512-NvCeXpYx7OsmOh8zIOP/ebG55zZmxLE0etfWRbWok+q2Qo8x/vOR/IJT1taADXPe+jsiu9axDb3X4B+iIgNlKw==
|
||||
dependencies:
|
||||
chownr "^1.0.1"
|
||||
mkdirp "^0.5.1"
|
||||
pump "^1.0.0"
|
||||
tar-stream "^1.1.2"
|
||||
|
||||
tar-stream@^1.1.2:
|
||||
version "1.6.2"
|
||||
resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.6.2.tgz#8ea55dab37972253d9a9af90fdcd559ae435c555"
|
||||
integrity sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==
|
||||
dependencies:
|
||||
bl "^1.0.0"
|
||||
buffer-alloc "^1.2.0"
|
||||
end-of-stream "^1.0.0"
|
||||
fs-constants "^1.0.0"
|
||||
readable-stream "^2.3.0"
|
||||
to-buffer "^1.1.1"
|
||||
xtend "^4.0.0"
|
||||
|
||||
text-encoding@^0.7.0:
|
||||
version "0.7.0"
|
||||
resolved "https://registry.yarnpkg.com/text-encoding/-/text-encoding-0.7.0.tgz#f895e836e45990624086601798ea98e8f36ee643"
|
||||
integrity sha512-oJQ3f1hrOnbRLOcwKz0Liq2IcrvDeZRHXhd9RgLrsT+DjWY/nty1Hi7v3dtkaEYbPYe0mUoOfzRrMwfXXwgPUA==
|
||||
|
||||
to-buffer@^1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/to-buffer/-/to-buffer-1.1.1.tgz#493bd48f62d7c43fcded313a03dcadb2e1213a80"
|
||||
integrity sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==
|
||||
|
||||
trash@^4.3.0:
|
||||
version "4.3.0"
|
||||
resolved "https://registry.yarnpkg.com/trash/-/trash-4.3.0.tgz#6ebeecdea4d666b06e389b47d135ea88e1de5075"
|
||||
@@ -1156,13 +753,6 @@ ts-protoc-gen@^0.8.0:
|
||||
dependencies:
|
||||
google-protobuf "^3.6.1"
|
||||
|
||||
tunnel-agent@^0.6.0:
|
||||
version "0.6.0"
|
||||
resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd"
|
||||
integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=
|
||||
dependencies:
|
||||
safe-buffer "^5.0.1"
|
||||
|
||||
type-is@~1.6.16:
|
||||
version "1.6.16"
|
||||
resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.16.tgz#f89ce341541c672b25ee7ae3c73dee3b2be50194"
|
||||
@@ -1183,11 +773,6 @@ user-home@^2.0.0:
|
||||
dependencies:
|
||||
os-homedir "^1.0.0"
|
||||
|
||||
util-deprecate@~1.0.1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
|
||||
integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
|
||||
|
||||
utils-merge@1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
|
||||
@@ -1203,11 +788,6 @@ vary@~1.1.2:
|
||||
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
|
||||
integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=
|
||||
|
||||
which-pm-runs@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/which-pm-runs/-/which-pm-runs-1.0.0.tgz#670b3afbc552e0b55df6b7780ca74615f23ad1cb"
|
||||
integrity sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs=
|
||||
|
||||
which@^1.2.8, which@^1.2.9:
|
||||
version "1.3.1"
|
||||
resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
|
||||
@@ -1215,13 +795,6 @@ which@^1.2.8, which@^1.2.9:
|
||||
dependencies:
|
||||
isexe "^2.0.0"
|
||||
|
||||
wide-align@^1.1.0:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457"
|
||||
integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==
|
||||
dependencies:
|
||||
string-width "^1.0.2 || 2"
|
||||
|
||||
wrappy@1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
|
||||
@@ -1252,11 +825,6 @@ xdg-trashdir@^2.1.1:
|
||||
user-home "^2.0.0"
|
||||
xdg-basedir "^2.0.0"
|
||||
|
||||
xtend@^4.0.0:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
|
||||
integrity sha1-pcbVMr5lbiPbgg77lDofBJmNY68=
|
||||
|
||||
yallist@^2.1.2:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"build:binary": "ts-node scripts/nbin.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@coder/nbin": "^1.0.6",
|
||||
"@coder/nbin": "^1.1.2",
|
||||
"commander": "^2.19.0",
|
||||
"express": "^4.16.4",
|
||||
"express-static-gzip": "^1.1.3",
|
||||
|
||||
@@ -2,14 +2,26 @@ import { Binary } from "@coder/nbin";
|
||||
import * as fs from "fs";
|
||||
import * as os from "os";
|
||||
import * as path from "path";
|
||||
import { platform } from "../../../build/platform";
|
||||
|
||||
const target = `${os.platform()}-${os.arch()}`;
|
||||
const target = `${platform()}-${os.arch()}`;
|
||||
const rootDir = path.join(__dirname, "..");
|
||||
const bin = new Binary({
|
||||
mainFile: path.join(rootDir, "out", "cli.js"),
|
||||
target: platform() === "darwin" ? "darwin" : platform() === "musl" ? "alpine" : "linux",
|
||||
});
|
||||
bin.writeFiles(path.join(rootDir, "build", "**"));
|
||||
bin.writeFiles(path.join(rootDir, "out", "**"));
|
||||
[
|
||||
// Native modules. These are marked as externals in the webpack config.
|
||||
"spdlog",
|
||||
"node-pty",
|
||||
|
||||
// These are spdlog's dependencies.
|
||||
"mkdirp", "bindings",
|
||||
].forEach((name) => {
|
||||
bin.writeModule(path.join(__dirname, "../../../node_modules", name));
|
||||
});
|
||||
bin.build().then((binaryData) => {
|
||||
const outputPath = path.join(__dirname, "..", `cli-${target}`);
|
||||
fs.writeFileSync(outputPath, binaryData);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { field, logger } from "@coder/logger";
|
||||
import { ServerMessage, SharedProcessActive } from "@coder/protocol/src/proto";
|
||||
import { ChildProcess, fork, ForkOptions, spawn } from "child_process";
|
||||
import { withEnv } from "@coder/protocol";
|
||||
import { ChildProcess, fork, ForkOptions } from "child_process";
|
||||
import { randomFillSync } from "crypto";
|
||||
import * as fs from "fs";
|
||||
import * as fse from "fs-extra";
|
||||
@@ -8,30 +9,37 @@ import * as os from "os";
|
||||
import * as path from "path";
|
||||
import * as WebSocket from "ws";
|
||||
import { buildDir, cacheHome, dataHome, isCli, serveStatic } from "./constants";
|
||||
import { setup as setupNativeModules } from "./modules";
|
||||
import { createApp } from "./server";
|
||||
import { forkModule, requireFork, requireModule } from "./vscode/bootstrapFork";
|
||||
import { forkModule, requireModule } from "./vscode/bootstrapFork";
|
||||
import { SharedProcess, SharedProcessState } from "./vscode/sharedProcess";
|
||||
import opn = require("opn");
|
||||
|
||||
import * as commander from "commander";
|
||||
|
||||
const collect = <T>(value: T, previous: T[]): T[] => {
|
||||
return previous.concat(value);
|
||||
};
|
||||
|
||||
commander.version(process.env.VERSION || "development")
|
||||
.name("code-server")
|
||||
.description("Run VS Code on a remote server.")
|
||||
.option("--cert <value>")
|
||||
.option("--cert-key <value>")
|
||||
.option("-e, --extensions-dir <dir>", "Set the root path for extensions.")
|
||||
.option("-e, --extensions-dir <dir>", "Override the main default path for user extensions.")
|
||||
.option("--extra-extensions-dir [dir]", "Path to an extra user extension directory (repeatable).", collect, [])
|
||||
.option("--extra-builtin-extensions-dir [dir]", "Path to an extra built-in extension directory (repeatable).", collect, [])
|
||||
.option("-d --user-data-dir <dir>", "Specifies the directory that user data is kept in, useful when running as root.")
|
||||
.option("--data-dir <value>", "DEPRECATED: Use '--user-data-dir' instead. Customize where user-data is stored.")
|
||||
.option("-h, --host <value>", "Customize the hostname.", "0.0.0.0")
|
||||
.option("-o, --open", "Open in the browser on startup.", false)
|
||||
.option("-p, --port <number>", "Port to bind on.", 8443)
|
||||
.option("-N, --no-auth", "Start without requiring authentication.", undefined)
|
||||
.option("-p, --port <number>", "Port to bind on.", parseInt(process.env.PORT!, 10) || 8443)
|
||||
.option("-N, --no-auth", "Start without requiring authentication.", false)
|
||||
.option("-H, --allow-http", "Allow http connections.", false)
|
||||
.option("-P, --password <value>", "Specify a password for authentication.")
|
||||
.option("-P, --password <value>", "DEPRECATED: Use the PASSWORD environment variable instead. Specify a password for authentication.")
|
||||
.option("--disable-telemetry", "Disables ALL telemetry.", false)
|
||||
.option("--socket <value>", "Listen on a UNIX socket. Host and port will be ignored when set.")
|
||||
.option("--install-extension <value>", "Install an extension by its ID.")
|
||||
.option("--bootstrap-fork <name>", "Used for development. Never set.")
|
||||
.option("--fork <name>", "Used for development. Never set.")
|
||||
.option("--extra-args <args>", "Used for development. Never set.")
|
||||
.arguments("Specify working directory.")
|
||||
.parse(process.argv);
|
||||
@@ -39,6 +47,7 @@ commander.version(process.env.VERSION || "development")
|
||||
Error.stackTraceLimit = Infinity;
|
||||
if (isCli) {
|
||||
require("nbin").shimNativeFs(buildDir);
|
||||
require("nbin").shimNativeFs("/node_modules");
|
||||
}
|
||||
// Makes strings or numbers bold in stdout
|
||||
const bold = (text: string | number): string | number => {
|
||||
@@ -52,21 +61,30 @@ const bold = (text: string | number): string | number => {
|
||||
readonly allowHttp: boolean;
|
||||
readonly host: string;
|
||||
readonly port: number;
|
||||
readonly disableTelemetry: boolean;
|
||||
|
||||
readonly userDataDir?: string;
|
||||
readonly extensionsDir?: string;
|
||||
readonly extraExtensionsDir?: string[];
|
||||
readonly extraBuiltinExtensionsDir?: string[];
|
||||
|
||||
readonly dataDir?: string;
|
||||
readonly password?: string;
|
||||
readonly open?: boolean;
|
||||
readonly cert?: string;
|
||||
readonly certKey?: string;
|
||||
readonly socket?: string;
|
||||
|
||||
readonly installExtension?: string;
|
||||
|
||||
readonly bootstrapFork?: string;
|
||||
readonly fork?: string;
|
||||
readonly extraArgs?: string;
|
||||
};
|
||||
|
||||
if (options.disableTelemetry) {
|
||||
process.env.DISABLE_TELEMETRY = "true";
|
||||
}
|
||||
|
||||
// Commander has an exception for `--no` prefixes. Here we'll adjust that.
|
||||
// tslint:disable-next-line:no-any
|
||||
const noAuthValue = (commander as any).auth;
|
||||
@@ -74,7 +92,11 @@ const bold = (text: string | number): string | number => {
|
||||
|
||||
const dataDir = path.resolve(options.userDataDir || options.dataDir || path.join(dataHome, "code-server"));
|
||||
const extensionsDir = options.extensionsDir ? path.resolve(options.extensionsDir) : path.resolve(dataDir, "extensions");
|
||||
const builtInExtensionsDir = path.resolve(buildDir || path.join(__dirname, ".."), "build/extensions");
|
||||
const extraExtensionDirs = options.extraExtensionsDir ? options.extraExtensionsDir.map((p) => path.resolve(p)) : [];
|
||||
const extraBuiltinExtensionDirs = options.extraBuiltinExtensionsDir ? options.extraBuiltinExtensionsDir.map((p) => path.resolve(p)) : [];
|
||||
const workingDir = path.resolve(args[0] || process.cwd());
|
||||
const dependenciesDir = path.join(os.tmpdir(), "code-server/dependencies");
|
||||
|
||||
if (!fs.existsSync(dataDir)) {
|
||||
const oldDataDir = path.resolve(path.join(os.homedir(), ".code-server"));
|
||||
@@ -89,10 +111,24 @@ const bold = (text: string | number): string | number => {
|
||||
fse.mkdirp(dataDir),
|
||||
fse.mkdirp(extensionsDir),
|
||||
fse.mkdirp(workingDir),
|
||||
fse.mkdirp(dependenciesDir),
|
||||
...extraExtensionDirs.map((p) => fse.mkdirp(p)),
|
||||
...extraBuiltinExtensionDirs.map((p) => fse.mkdirp(p)),
|
||||
]);
|
||||
|
||||
setupNativeModules(dataDir);
|
||||
const builtInExtensionsDir = path.resolve(buildDir || path.join(__dirname, ".."), "build/extensions");
|
||||
const unpackExecutable = (binaryName: string): void => {
|
||||
const memFile = path.join(isCli ? buildDir! : path.join(__dirname, ".."), "build/dependencies", binaryName);
|
||||
const diskFile = path.join(dependenciesDir, binaryName);
|
||||
if (!fse.existsSync(diskFile)) {
|
||||
fse.writeFileSync(diskFile, fse.readFileSync(memFile));
|
||||
}
|
||||
fse.chmodSync(diskFile, "755");
|
||||
};
|
||||
|
||||
unpackExecutable("rg");
|
||||
// tslint:disable-next-line no-any
|
||||
(<any>global).RIPGREP_LOCATION = path.join(dependenciesDir, "rg");
|
||||
|
||||
if (options.bootstrapFork) {
|
||||
const modulePath = options.bootstrapFork;
|
||||
if (!modulePath) {
|
||||
@@ -100,19 +136,13 @@ const bold = (text: string | number): string | number => {
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
((options.extraArgs ? JSON.parse(options.extraArgs) : []) as string[]).forEach((arg, i) => {
|
||||
// [0] contains the binary running the script (`node` for example) and
|
||||
// [1] contains the script name, so the arguments come after that.
|
||||
process.argv[i + 2] = arg;
|
||||
});
|
||||
process.argv = [
|
||||
process.argv[0],
|
||||
process.argv[1],
|
||||
...(options.extraArgs ? JSON.parse(options.extraArgs) : []),
|
||||
];
|
||||
|
||||
return requireModule(modulePath, dataDir, builtInExtensionsDir);
|
||||
}
|
||||
|
||||
if (options.fork) {
|
||||
const modulePath = options.fork;
|
||||
|
||||
return requireFork(modulePath, JSON.parse(options.extraArgs!), builtInExtensionsDir);
|
||||
return requireModule(modulePath, builtInExtensionsDir);
|
||||
}
|
||||
|
||||
const logDir = path.join(cacheHome, "code-server/logs", new Date().toISOString().replace(/[-:.TZ]/g, ""));
|
||||
@@ -156,10 +186,25 @@ const bold = (text: string | number): string | number => {
|
||||
logger.warn('"--data-dir" is deprecated. Use "--user-data-dir" instead.');
|
||||
}
|
||||
|
||||
if (options.installExtension) {
|
||||
const fork = forkModule("vs/code/node/cli", [
|
||||
"--user-data-dir", dataDir,
|
||||
"--builtin-extensions-dir", builtInExtensionsDir,
|
||||
"--extensions-dir", extensionsDir,
|
||||
"--install-extension", options.installExtension,
|
||||
], withEnv({ env: { VSCODE_ALLOW_IO: "true" } }), dataDir);
|
||||
|
||||
fork.stdout.on("data", (d: Buffer) => d.toString().split("\n").forEach((l) => logger.info(l)));
|
||||
fork.stderr.on("data", (d: Buffer) => d.toString().split("\n").forEach((l) => logger.error(l)));
|
||||
fork.on("exit", () => process.exit());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: fill in appropriate doc url
|
||||
logger.info("Additional documentation: http://github.com/codercom/code-server");
|
||||
logger.info("Additional documentation: http://github.com/cdr/code-server");
|
||||
logger.info("Initializing", field("data-dir", dataDir), field("extensions-dir", extensionsDir), field("working-dir", workingDir), field("log-dir", logDir));
|
||||
const sharedProcess = new SharedProcess(dataDir, extensionsDir, builtInExtensionsDir);
|
||||
const sharedProcess = new SharedProcess(dataDir, extensionsDir, builtInExtensionsDir, extraExtensionDirs, extraBuiltinExtensionDirs);
|
||||
const sendSharedProcessReady = (socket: WebSocket): void => {
|
||||
const active = new SharedProcessActive();
|
||||
active.setSocketPath(sharedProcess.socketPath);
|
||||
@@ -174,7 +219,12 @@ const bold = (text: string | number): string | number => {
|
||||
}
|
||||
});
|
||||
|
||||
let password = options.password;
|
||||
if (options.password) {
|
||||
logger.warn('"--password" is deprecated. Use the PASSWORD environment variable instead.');
|
||||
}
|
||||
|
||||
let password = options.password || process.env.PASSWORD;
|
||||
const usingCustomPassword = !!password;
|
||||
if (!password) {
|
||||
// Generate a random password with a length of 24.
|
||||
const buffer = Buffer.alloc(12);
|
||||
@@ -187,20 +237,19 @@ const bold = (text: string | number): string | number => {
|
||||
allowHttp: options.allowHttp,
|
||||
bypassAuth: options.noAuth,
|
||||
registerMiddleware: (app): void => {
|
||||
app.use((req, res, next) => {
|
||||
res.on("finish", () => {
|
||||
logger.trace(`\u001B[1m${req.method} ${res.statusCode} \u001B[0m${req.url}`, field("host", req.hostname), field("ip", req.ip));
|
||||
});
|
||||
|
||||
next();
|
||||
});
|
||||
// If we're not running from the binary and we aren't serving the static
|
||||
// pre-built version, use webpack to serve the web files.
|
||||
if (!isCli && !serveStatic) {
|
||||
const webpackConfig = require(path.resolve(__dirname, "..", "..", "web", "webpack.config.js"));
|
||||
const compiler = require("webpack")(webpackConfig);
|
||||
app.use(require("webpack-dev-middleware")(compiler, {
|
||||
logger,
|
||||
logger: {
|
||||
trace: (m: string): void => logger.trace("webpack", field("message", m)),
|
||||
debug: (m: string): void => logger.debug("webpack", field("message", m)),
|
||||
info: (m: string): void => logger.info("webpack", field("message", m)),
|
||||
warn: (m: string): void => logger.warn("webpack", field("message", m)),
|
||||
error: (m: string): void => logger.error("webpack", field("message", m)),
|
||||
},
|
||||
publicPath: webpackConfig.output.publicPath,
|
||||
stats: webpackConfig.stats,
|
||||
}));
|
||||
@@ -210,6 +259,8 @@ const bold = (text: string | number): string | number => {
|
||||
serverOptions: {
|
||||
extensionsDirectory: extensionsDir,
|
||||
builtInExtensionsDirectory: builtInExtensionsDir,
|
||||
extraExtensionDirectories: extraExtensionDirs,
|
||||
extraBuiltinExtensionDirectories: extraBuiltinExtensionDirs,
|
||||
dataDirectory: dataDir,
|
||||
workingDirectory: workingDir,
|
||||
cacheDirectory: cacheHome,
|
||||
@@ -218,14 +269,7 @@ const bold = (text: string | number): string | number => {
|
||||
return forkModule(options.env.AMD_ENTRYPOINT, args, options, dataDir);
|
||||
}
|
||||
|
||||
if (isCli) {
|
||||
return spawn(process.execPath, [path.join(buildDir, "out", "cli.js"), "--fork", modulePath, "--extra-args", JSON.stringify(args), "--data-dir", dataDir], {
|
||||
...options,
|
||||
stdio: [null, null, null, "ipc"],
|
||||
});
|
||||
} else {
|
||||
return fork(modulePath, args, options);
|
||||
}
|
||||
},
|
||||
},
|
||||
password,
|
||||
@@ -236,7 +280,11 @@ const bold = (text: string | number): string | number => {
|
||||
});
|
||||
|
||||
logger.info("Starting webserver...", field("host", options.host), field("port", options.port));
|
||||
if (options.socket) {
|
||||
app.server.listen(options.socket);
|
||||
} else {
|
||||
app.server.listen(options.port, options.host);
|
||||
}
|
||||
let clientId = 1;
|
||||
app.wss.on("connection", (ws, req) => {
|
||||
const id = clientId++;
|
||||
@@ -253,24 +301,33 @@ const bold = (text: string | number): string | number => {
|
||||
});
|
||||
app.wss.on("error", (err: NodeJS.ErrnoException) => {
|
||||
if (err.code === "EADDRINUSE") {
|
||||
if (options.socket) {
|
||||
logger.error(`Socket ${bold(options.socket)} is in use. Please specify a different socket.`);
|
||||
} else {
|
||||
logger.error(`Port ${bold(options.port)} is in use. Please free up port ${options.port} or specify a different port with the -p flag`);
|
||||
}
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
if (!options.certKey && !options.cert) {
|
||||
logger.warn("No certificate specified. \u001B[1mThis could be insecure.");
|
||||
// TODO: fill in appropriate doc url
|
||||
logger.warn("Documentation on securing your setup: https://github.com/codercom/code-server/blob/master/doc/security/ssl.md");
|
||||
logger.warn("Documentation on securing your setup: https://github.com/cdr/code-server/blob/master/doc/security/ssl.md");
|
||||
}
|
||||
|
||||
if (!options.noAuth) {
|
||||
logger.info(" ");
|
||||
logger.info(`Password:\u001B[1m ${password}`);
|
||||
logger.info(usingCustomPassword ? "Using custom password." : `Password:\u001B[1m ${password}`);
|
||||
} else {
|
||||
logger.warn(" ");
|
||||
logger.warn("Launched without authentication.");
|
||||
}
|
||||
if (options.disableTelemetry) {
|
||||
logger.info("Telemetry is disabled");
|
||||
}
|
||||
|
||||
const url = `http://localhost:${options.port}/`;
|
||||
const protocol = options.allowHttp ? "http" : "https";
|
||||
const url = `${protocol}://localhost:${options.port}/`;
|
||||
logger.info(" ");
|
||||
logger.info("Started (click the link below to open):");
|
||||
logger.info(url);
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
import * as os from "os";
|
||||
import { isCli, buildDir } from "./constants";
|
||||
|
||||
/**
|
||||
* Handling of native modules within the CLI
|
||||
*/
|
||||
export const setup = (dataDirectory: string): void => {
|
||||
path.resolve(dataDirectory, "dependencies").split(path.sep).reduce((parentDir, childDir) => {
|
||||
const currentDir = path.join(parentDir, childDir);
|
||||
try {
|
||||
fs.mkdirSync(currentDir);
|
||||
} catch (ex) {
|
||||
if (ex.code !== "EEXIST" && ex.code !== "EISDIR" && ex.code !== "ENOENT") {
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
return currentDir;
|
||||
}, os.platform() === "win32" ? undefined! : path.sep); // Might need path.sep here for linux. Having it for windows causes an error because \C:\Users ...
|
||||
|
||||
const unpackModule = (moduleName: string, markExecutable: boolean = false): void => {
|
||||
const memFile = path.join(isCli ? buildDir! : path.join(__dirname, ".."), "build/dependencies", moduleName);
|
||||
const diskFile = path.join(dataDirectory, "dependencies", moduleName);
|
||||
if (!fs.existsSync(diskFile)) {
|
||||
fs.writeFileSync(diskFile, fs.readFileSync(memFile));
|
||||
}
|
||||
if (markExecutable) {
|
||||
fs.chmodSync(diskFile, "755");
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* We need to unpack node-pty and patch its `loadNative` function to require our unpacked pty.node
|
||||
* If pty.node isn't unpacked a SIGSEGV is thrown and the application exits. The exact reasoning
|
||||
* for this is unknown ATM, but this patch works around it.
|
||||
*/
|
||||
unpackModule("pty.node");
|
||||
unpackModule("spdlog.node");
|
||||
unpackModule("rg", true);
|
||||
// const nodePtyUtils = require("../../protocol/node_modules/node-pty-prebuilt/lib/utils") as typeof import("../../protocol/node_modules/node-pty-prebuilt/src/utils");
|
||||
// tslint:disable-next-line:no-any
|
||||
// nodePtyUtils.loadNative = (modName: string): any => {
|
||||
// return (typeof __non_webpack_require__ !== "undefined" ? __non_webpack_require__ : require)(path.join(dataDirectory, "dependencies", modName + ".node"));
|
||||
// };
|
||||
(<any>global).RIPGREP_LOCATION = path.join(dataDirectory, "dependencies", "rg");
|
||||
(<any>global).NODEPTY_LOCATION = path.join(dataDirectory, "dependencies", "pty.node");
|
||||
// tslint:disable-next-line:no-any
|
||||
(<any>global).SPDLOG_LOCATION = path.join(dataDirectory, "dependencies", "spdlog.node");
|
||||
// tslint:disable-next-line:no-unused-expression
|
||||
require("../../protocol/node_modules/node-pty-prebuilt/lib/index") as typeof import("../../protocol/node_modules/node-pty-prebuilt/src/index");
|
||||
};
|
||||
@@ -79,7 +79,11 @@ export const createPortScanner = (scanInterval: number = 5000): PortScanner => {
|
||||
logger.trace("scanning ports");
|
||||
scan((error) => {
|
||||
if (error) {
|
||||
logger.error(`Port scanning will not be available: ${error.message}.`);
|
||||
if ((error as NodeJS.ErrnoException).code === "ENOENT") {
|
||||
logger.warn("Port scanning will not be available because netstat is not installed");
|
||||
} else {
|
||||
logger.warn(`Port scanning will not be available: ${error.message}`);
|
||||
}
|
||||
disposed = true;
|
||||
} else if (!disposed) {
|
||||
lastTimeout = setTimeout(doInterval, scanInterval);
|
||||
|
||||
@@ -18,6 +18,7 @@ import * as os from "os";
|
||||
import * as path from "path";
|
||||
import * as pem from "pem";
|
||||
import * as util from "util";
|
||||
import * as url from "url";
|
||||
import * as ws from "ws";
|
||||
import { buildDir } from "./constants";
|
||||
import { createPortScanner } from "./portScanner";
|
||||
@@ -132,7 +133,7 @@ export const createApp = async (options: CreateAppOptions): Promise<{
|
||||
});
|
||||
});
|
||||
|
||||
const server = httpolyglot.createServer(options.bypassAuth ? {} : options.httpsOptions || certs, app) as http.Server;
|
||||
const server = httpolyglot.createServer(options.allowHttp ? {} : options.httpsOptions || certs, app) as http.Server;
|
||||
const wss = new ws.Server({ server });
|
||||
|
||||
wss.shouldHandle = (req): boolean => {
|
||||
@@ -140,13 +141,13 @@ export const createApp = async (options: CreateAppOptions): Promise<{
|
||||
};
|
||||
|
||||
const portScanner = createPortScanner();
|
||||
wss.on("connection", (ws, req) => {
|
||||
wss.on("connection", async (ws, req) => {
|
||||
if (req.url && req.url.startsWith("/tunnel")) {
|
||||
try {
|
||||
const rawPort = req.url.split("/").pop();
|
||||
const port = Number.parseInt(rawPort!, 10);
|
||||
|
||||
handleTunnel(ws, port);
|
||||
await handleTunnel(ws, port);
|
||||
} catch (ex) {
|
||||
ws.close(TunnelCloseCode.Error, ex.toString());
|
||||
}
|
||||
@@ -189,31 +190,70 @@ export const createApp = async (options: CreateAppOptions): Promise<{
|
||||
new Server(connection, options.serverOptions);
|
||||
});
|
||||
|
||||
const redirect = (
|
||||
req: express.Request, res: express.Response,
|
||||
to: string = "", from: string = "",
|
||||
code: number = 302, protocol: string = req.protocol,
|
||||
): void => {
|
||||
const currentUrl = `${protocol}://${req.headers.host}${req.originalUrl}`;
|
||||
const newUrl = url.parse(currentUrl);
|
||||
if (from && newUrl.pathname) {
|
||||
newUrl.pathname = newUrl.pathname.replace(new RegExp(`\/${from}\/?$`), "/");
|
||||
}
|
||||
if (to) {
|
||||
newUrl.pathname = (newUrl.pathname || "").replace(/\/$/, "") + `/${to}`;
|
||||
}
|
||||
newUrl.path = undefined; // Path is not necessary for format().
|
||||
const newUrlString = url.format(newUrl);
|
||||
logger.trace(`Redirecting from ${currentUrl} to ${newUrlString}`);
|
||||
|
||||
return res.redirect(code, newUrlString);
|
||||
};
|
||||
|
||||
const baseDir = buildDir || path.join(__dirname, "..");
|
||||
const authStaticFunc = expressStaticGzip(path.join(baseDir, "build/web/auth"));
|
||||
const unauthStaticFunc = expressStaticGzip(path.join(baseDir, "build/web/unauth"));
|
||||
const staticGzip = expressStaticGzip(path.join(baseDir, "build/web"));
|
||||
|
||||
app.use((req, res, next) => {
|
||||
logger.trace(`\u001B[1m${req.method} ${res.statusCode} \u001B[0m${req.originalUrl}`, field("host", req.hostname), field("ip", req.ip));
|
||||
|
||||
// Force HTTPS unless allowing HTTP.
|
||||
if (!isEncrypted(req.socket) && !options.allowHttp) {
|
||||
return res.redirect(301, `https://${req.headers.host!}${req.path}`);
|
||||
return redirect(req, res, "", "", 301, "https");
|
||||
}
|
||||
|
||||
if (isAuthed(req)) {
|
||||
// We can serve the actual VSCode bin
|
||||
authStaticFunc(req, res, next);
|
||||
} else {
|
||||
// Serve only the unauthed version
|
||||
unauthStaticFunc(req, res, next);
|
||||
}
|
||||
});
|
||||
// @ts-ignore
|
||||
app.use((err, req, res, next) => {
|
||||
next();
|
||||
});
|
||||
app.get("/ping", (req, res) => {
|
||||
|
||||
// @ts-ignore
|
||||
app.use((err, _req, _res, next) => {
|
||||
logger.error(err.message);
|
||||
next();
|
||||
});
|
||||
|
||||
// If not authenticated, redirect to the login page.
|
||||
app.get("/", (req, res, next) => {
|
||||
if (!isAuthed(req)) {
|
||||
return redirect(req, res, "login");
|
||||
}
|
||||
next();
|
||||
});
|
||||
|
||||
// If already authenticated, redirect back to the root.
|
||||
app.get("/login", (req, res, next) => {
|
||||
if (isAuthed(req)) {
|
||||
return redirect(req, res, "", "login");
|
||||
}
|
||||
next();
|
||||
});
|
||||
|
||||
// For getting general server data.
|
||||
app.get("/ping", (_req, res) => {
|
||||
res.json({
|
||||
hostname: os.hostname(),
|
||||
});
|
||||
});
|
||||
|
||||
// For getting a resource on disk.
|
||||
app.get("/resource/:url(*)", async (req, res) => {
|
||||
if (!ensureAuthed(req, res)) {
|
||||
return;
|
||||
@@ -254,6 +294,8 @@ export const createApp = async (options: CreateAppOptions): Promise<{
|
||||
res.end();
|
||||
}
|
||||
});
|
||||
|
||||
// For writing a resource to disk.
|
||||
app.post("/resource/:url(*)", async (req, res) => {
|
||||
if (!ensureAuthed(req, res)) {
|
||||
return;
|
||||
@@ -271,7 +313,7 @@ export const createApp = async (options: CreateAppOptions): Promise<{
|
||||
const body = data.join("");
|
||||
await mkdirp(path.dirname(fullPath));
|
||||
fs.writeFileSync(fullPath, body);
|
||||
logger.debug("Wrote resource", field("path", fullPath), field("content-length", body.length));
|
||||
logger.info("Wrote resource", field("path", fullPath), field("content-length", body.length));
|
||||
res.status(200);
|
||||
res.end();
|
||||
});
|
||||
@@ -282,6 +324,9 @@ export const createApp = async (options: CreateAppOptions): Promise<{
|
||||
}
|
||||
});
|
||||
|
||||
// Everything else just pulls from the static build directory.
|
||||
app.use(staticGzip);
|
||||
|
||||
return {
|
||||
express: app,
|
||||
server,
|
||||
|
||||
@@ -42,54 +42,13 @@ const requireFilesystemModule = (id: string, builtInExtensionsDir: string): any
|
||||
return customMod.require(id);
|
||||
};
|
||||
|
||||
/**
|
||||
* Called from forking a module
|
||||
*/
|
||||
export const requireFork = (modulePath: string, args: string[], builtInExtensionsDir: string): void => {
|
||||
const Module = require("module") as typeof import("module");
|
||||
const oldRequire = Module.prototype.require;
|
||||
// tslint:disable-next-line:no-any
|
||||
const oldLoad = (Module as any)._findPath;
|
||||
// @ts-ignore
|
||||
(Module as any)._findPath = function (request, parent, isMain): any {
|
||||
const lookupPaths = oldLoad.call(this, request, parent, isMain);
|
||||
|
||||
return lookupPaths;
|
||||
};
|
||||
// tslint:disable-next-line:no-any
|
||||
Module.prototype.require = function (id: string): any {
|
||||
if (id === "typescript") {
|
||||
return require("typescript");
|
||||
}
|
||||
|
||||
// tslint:disable-next-line:no-any
|
||||
return oldRequire.call(this, id as any);
|
||||
};
|
||||
|
||||
if (!process.send) {
|
||||
throw new Error("No IPC messaging initialized");
|
||||
}
|
||||
|
||||
process.argv = ["", "", ...args];
|
||||
requireFilesystemModule(modulePath, builtInExtensionsDir);
|
||||
|
||||
if (ipcMsgBuffer && ipcMsgListener) {
|
||||
process.removeListener("message", ipcMsgListener);
|
||||
// tslint:disable-next-line:no-any
|
||||
ipcMsgBuffer.forEach((i) => process.emit("message" as any, i as any));
|
||||
ipcMsgBuffer = undefined;
|
||||
ipcMsgListener = undefined;
|
||||
}
|
||||
};
|
||||
|
||||
export const requireModule = (modulePath: string, dataDir: string, builtInExtensionsDir: string): void => {
|
||||
export const requireModule = (modulePath: string, builtInExtensionsDir: string): void => {
|
||||
process.env.AMD_ENTRYPOINT = modulePath;
|
||||
const xml = require("xhr2");
|
||||
xml.XMLHttpRequest.prototype._restrictedHeaders["user-agent"] = false;
|
||||
// tslint:disable-next-line no-any this makes installing extensions work.
|
||||
(global as any).XMLHttpRequest = xml.XMLHttpRequest;
|
||||
|
||||
const mod = require("module") as typeof import("module");
|
||||
const promiseFinally = require("promise.prototype.finally") as { shim: () => void };
|
||||
promiseFinally.shim();
|
||||
/**
|
||||
@@ -102,16 +61,7 @@ export const requireModule = (modulePath: string, dataDir: string, builtInExtens
|
||||
};
|
||||
|
||||
if (isCli) {
|
||||
/**
|
||||
* Needed for properly forking external modules within the CLI
|
||||
*/
|
||||
// tslint:disable-next-line:no-any
|
||||
(<any>cp).fork = (modulePath: string, args: ReadonlyArray<string> = [], options?: cp.ForkOptions): cp.ChildProcess => {
|
||||
return cp.spawn(process.execPath, [path.join(buildDir, "out", "cli.js"), "--fork", modulePath, "--extra-args", JSON.stringify(args), "--data-dir", dataDir], {
|
||||
...options,
|
||||
stdio: [null, null, null, "ipc"],
|
||||
});
|
||||
};
|
||||
process.env.NBIN_BYPASS = "true";
|
||||
}
|
||||
|
||||
const baseDir = path.join(buildDir, "build");
|
||||
@@ -132,7 +82,6 @@ export const requireModule = (modulePath: string, dataDir: string, builtInExtens
|
||||
* @param modulePath Path of the VS Code module to load.
|
||||
*/
|
||||
export const forkModule = (modulePath: string, args?: string[], options?: cp.ForkOptions, dataDir?: string): cp.ChildProcess => {
|
||||
let proc: cp.ChildProcess;
|
||||
const forkOptions: cp.ForkOptions = {
|
||||
stdio: [null, null, null, "ipc"],
|
||||
};
|
||||
@@ -141,18 +90,27 @@ export const forkModule = (modulePath: string, args?: string[], options?: cp.For
|
||||
delete options.env.ELECTRON_RUN_AS_NODE;
|
||||
forkOptions.env = options.env;
|
||||
}
|
||||
|
||||
const forkArgs = ["--bootstrap-fork", modulePath];
|
||||
if (args) {
|
||||
forkArgs.push("--extra-args", JSON.stringify(args));
|
||||
}
|
||||
if (dataDir) {
|
||||
forkArgs.push("--data-dir", dataDir);
|
||||
forkArgs.push("--user-data-dir", dataDir);
|
||||
}
|
||||
|
||||
const nodeArgs = [];
|
||||
if (isCli) {
|
||||
proc = cp.spawn(process.execPath, [path.join(buildDir, "out", "cli.js"), ...forkArgs], forkOptions);
|
||||
nodeArgs.push(path.join(buildDir, "out", "cli.js"));
|
||||
} else {
|
||||
proc = cp.spawn(process.execPath, ["--require", "ts-node/register", "--require", "tsconfig-paths/register", process.argv[1], ...forkArgs], forkOptions);
|
||||
nodeArgs.push(
|
||||
"--require", "ts-node/register",
|
||||
"--require", "tsconfig-paths/register",
|
||||
process.argv[1],
|
||||
);
|
||||
}
|
||||
|
||||
const proc = cp.spawn(process.execPath, [...nodeArgs, ...forkArgs], forkOptions);
|
||||
if (args && args[0] === "--type=watcherService" && os.platform() === "linux") {
|
||||
cp.exec(`renice -n 19 -p ${proc.pid}`, (error) => {
|
||||
if (error) {
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import { ChildProcess } from "child_process";
|
||||
import * as fs from "fs";
|
||||
import * as fse from "fs-extra";
|
||||
import * as os from "os";
|
||||
import * as path from "path";
|
||||
import { forkModule } from "./bootstrapFork";
|
||||
@@ -8,7 +6,8 @@ import { StdioIpcHandler } from "../ipc";
|
||||
import { ParsedArgs } from "vs/platform/environment/common/environment";
|
||||
import { Emitter } from "@coder/events/src";
|
||||
import { retry } from "@coder/ide/src/retry";
|
||||
import { logger, Level } from "@coder/logger";
|
||||
import { logger, field, Level } from "@coder/logger";
|
||||
import { withEnv } from "@coder/protocol";
|
||||
|
||||
export enum SharedProcessState {
|
||||
Stopped,
|
||||
@@ -40,6 +39,8 @@ export class SharedProcess {
|
||||
private readonly userDataDir: string,
|
||||
private readonly extensionsDir: string,
|
||||
private readonly builtInExtensionsDir: string,
|
||||
private readonly extraExtensionDirs: string[],
|
||||
private readonly extraBuiltinExtensionDirs: string[],
|
||||
) {
|
||||
this.retry.run();
|
||||
}
|
||||
@@ -66,12 +67,6 @@ export class SharedProcess {
|
||||
this.setState({ state: SharedProcessState.Starting });
|
||||
const activeProcess = await this.restart();
|
||||
|
||||
activeProcess.stderr.on("data", (data) => {
|
||||
// Warn instead of error to prevent panic. It's unlikely stderr here is
|
||||
// about anything critical to the functioning of the editor.
|
||||
logger.warn(data.toString());
|
||||
});
|
||||
|
||||
activeProcess.on("exit", (exitCode) => {
|
||||
const error = new Error(`Exited with ${exitCode}`);
|
||||
this.setState({
|
||||
@@ -96,22 +91,10 @@ export class SharedProcess {
|
||||
this.activeProcess.kill();
|
||||
}
|
||||
|
||||
const backupsDir = path.join(this.userDataDir, "Backups");
|
||||
await Promise.all([
|
||||
fse.mkdirp(backupsDir),
|
||||
]);
|
||||
|
||||
const workspacesFile = path.join(backupsDir, "workspaces.json");
|
||||
if (!fs.existsSync(workspacesFile)) {
|
||||
fs.appendFileSync(workspacesFile, "");
|
||||
}
|
||||
|
||||
const activeProcess = forkModule("vs/code/electron-browser/sharedProcess/sharedProcessMain", [], {
|
||||
env: {
|
||||
VSCODE_ALLOW_IO: "true",
|
||||
VSCODE_LOGS: process.env.VSCODE_LOGS,
|
||||
},
|
||||
}, this.userDataDir);
|
||||
const activeProcess = forkModule(
|
||||
"vs/code/electron-browser/sharedProcess/sharedProcessMain", [],
|
||||
withEnv({ env: { VSCODE_ALLOW_IO: "true" } }), this.userDataDir,
|
||||
);
|
||||
this.activeProcess = activeProcess;
|
||||
|
||||
await new Promise((resolve, reject): void => {
|
||||
@@ -132,6 +115,16 @@ export class SharedProcess {
|
||||
activeProcess.on("error", doReject);
|
||||
activeProcess.on("exit", doReject);
|
||||
|
||||
activeProcess.stdout.on("data", (data) => {
|
||||
logger.trace("stdout", field("data", data.toString()));
|
||||
});
|
||||
|
||||
activeProcess.stderr.on("data", (data) => {
|
||||
// Warn instead of error to prevent panic. It's unlikely stderr here is
|
||||
// about anything critical to the functioning of the editor.
|
||||
logger.warn("stderr", field("data", data.toString()));
|
||||
});
|
||||
|
||||
this.ipcHandler = new StdioIpcHandler(activeProcess);
|
||||
this.ipcHandler.once("handshake:hello", () => {
|
||||
const data: {
|
||||
@@ -143,6 +136,8 @@ export class SharedProcess {
|
||||
"builtin-extensions-dir": this.builtInExtensionsDir,
|
||||
"user-data-dir": this.userDataDir,
|
||||
"extensions-dir": this.extensionsDir,
|
||||
"extra-extension-dirs": this.extraExtensionDirs,
|
||||
"extra-builtin-extension-dirs": this.extraBuiltinExtensionDirs,
|
||||
},
|
||||
logLevel: this.logger.level,
|
||||
sharedIPCHandle: this.socketPath,
|
||||
|
||||
@@ -6,14 +6,12 @@ const root = path.resolve(__dirname, "../..");
|
||||
|
||||
module.exports = merge(
|
||||
require(path.join(root, "scripts/webpack.node.config.js"))({
|
||||
// Config options.
|
||||
dirname: __dirname,
|
||||
}), {
|
||||
output: {
|
||||
filename: "cli.js",
|
||||
path: path.join(__dirname, "out"),
|
||||
libraryTarget: "commonjs",
|
||||
},
|
||||
mode: "production",
|
||||
node: {
|
||||
console: false,
|
||||
global: false,
|
||||
@@ -23,14 +21,8 @@ module.exports = merge(
|
||||
__dirname: false,
|
||||
setImmediate: false
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
"node-pty": "node-pty-prebuilt",
|
||||
},
|
||||
},
|
||||
externals: {
|
||||
"nbin": "commonjs nbin",
|
||||
"fsevents": "fsevents",
|
||||
},
|
||||
entry: "./packages/server/src/cli.ts",
|
||||
plugins: [
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
resolved "https://registry.yarnpkg.com/@coder/logger/-/logger-1.0.3.tgz#e0e1ae5496fde5a3c6ef3d748fdfb26a55add8b8"
|
||||
integrity sha512-1o5qDZX2VZUNnzgz5KfAdMnaqaX6FNeTs0dUdg73MRHfQW94tFTIryFC1xTTCuzxGDjVHOHkaUAI4uHA2bheOA==
|
||||
|
||||
"@coder/nbin@^1.0.6":
|
||||
version "1.0.6"
|
||||
resolved "https://registry.yarnpkg.com/@coder/nbin/-/nbin-1.0.6.tgz#6babfaad93b27eac66c1e6a3acb52135b00c5525"
|
||||
integrity sha512-61niwcPQhZj1mNMyYEt7h62i2a9sg+XP6DmxUF09cZa4HsXPlspHIfoe9Oe3xa7lg7aP9s2Pg9KaYlaYr70Dcg==
|
||||
"@coder/nbin@^1.1.2":
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@coder/nbin/-/nbin-1.1.2.tgz#3af9e4368f37532da446c7c291d476bb52de995d"
|
||||
integrity sha512-MkwKpmu1SU9wkBwQ+bZVU2nPzENWUa3Isut9osVq3LG+udovsk+k5c5rjfJ1q8cf4km5snjOSYiulug3n9sdgw==
|
||||
dependencies:
|
||||
"@coder/logger" "^1.0.3"
|
||||
fs-extra "^7.0.1"
|
||||
|
||||
@@ -6,12 +6,17 @@ import { IStatusbarService, StatusbarAlignment } from "vs/platform/statusbar/com
|
||||
import * as paths from "./fill/paths";
|
||||
import product from "./fill/product";
|
||||
import "./vscode.scss";
|
||||
import { MenuId, MenuRegistry } from "vs/platform/actions/common/actions";
|
||||
import { Action } from 'vs/base/common/actions';
|
||||
import { SyncActionDescriptor, MenuRegistry, MenuId } from 'vs/platform/actions/common/actions';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions';
|
||||
import { CommandsRegistry } from "vs/platform/commands/common/commands";
|
||||
import { IFileService, FileOperation } from "vs/platform/files/common/files";
|
||||
import { ITextFileService } from "vs/workbench/services/textfile/common/textfiles";
|
||||
import { IModelService } from "vs/editor/common/services/modelService";
|
||||
import { ITerminalService } from "vs/workbench/contrib/terminal/common/terminal";
|
||||
import { IStorageService } from "vs/platform/storage/common/storage";
|
||||
|
||||
// NOTE: shouldn't import anything from VS Code here or anything that will
|
||||
// depend on a synchronous fill like `os`.
|
||||
|
||||
@@ -32,12 +37,22 @@ class VSClient extends IdeClient {
|
||||
window.ide = {
|
||||
client: ideClientInstance,
|
||||
workbench: {
|
||||
action: Action,
|
||||
syncActionDescriptor: SyncActionDescriptor,
|
||||
commandRegistry: CommandsRegistry,
|
||||
// tslint:disable-next-line:no-any
|
||||
menuRegistry: MenuRegistry as any,
|
||||
// tslint:disable-next-line:no-any
|
||||
statusbarService: getService<IStatusbarService>(IStatusbarService) as any,
|
||||
actionsRegistry: Registry.as<IWorkbenchActionRegistry>(Extensions.WorkbenchActions),
|
||||
menuRegistry: MenuRegistry,
|
||||
statusbarService: getService<IStatusbarService>(IStatusbarService),
|
||||
notificationService: getService<INotificationService>(INotificationService),
|
||||
terminalService: getService<ITerminalService>(ITerminalService),
|
||||
storageService: {
|
||||
save: (): Promise<void> => {
|
||||
// tslint:disable-next-line:no-any
|
||||
const storageService = getService<IStorageService>(IStorageService) as any;
|
||||
|
||||
return storageService.close();
|
||||
},
|
||||
},
|
||||
|
||||
onFileCreate: (cb): void => {
|
||||
getService<IFileService>(IFileService).onAfterOperation((e) => {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
--primary: #2A2E37;
|
||||
--border: black;
|
||||
--faded: #a0a1a5;
|
||||
--disabled: #888;
|
||||
--header-background: #161616;
|
||||
--header-foreground: white;
|
||||
--list-active-selection-background: rgb(0, 120, 160);
|
||||
@@ -78,9 +79,7 @@
|
||||
.dialog-entry {
|
||||
cursor: pointer;
|
||||
font-size: 1.02em;
|
||||
padding: 0px;
|
||||
padding-left: 8px;
|
||||
padding-right: 8px;
|
||||
padding: 0px 8px;
|
||||
|
||||
.dialog-entry-info {
|
||||
display: flex;
|
||||
@@ -93,6 +92,14 @@
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.dialog-entry-size {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.dialog-entry-mtime {
|
||||
padding-left: 8px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: var(--list-hover-background);
|
||||
}
|
||||
@@ -101,6 +108,12 @@
|
||||
background-color: var(--list-active-selection-background);
|
||||
color: var(--list-active-selection-foreground);
|
||||
}
|
||||
|
||||
&.disabled, &.disabled:hover {
|
||||
background-color: var(--primary);
|
||||
color: var(--disabled);
|
||||
cursor: initial;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,6 +147,11 @@
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
button[disabled], button[disabled]:hover {
|
||||
color: var(--disabled);
|
||||
cursor: initial;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,9 @@ import { IThemeService } from "vs/platform/theme/common/themeService";
|
||||
import { workbench } from "./workbench";
|
||||
import "./dialog.scss";
|
||||
|
||||
/**
|
||||
* Describes the type of dialog to show.
|
||||
*/
|
||||
export enum DialogType {
|
||||
NewFolder,
|
||||
Save,
|
||||
@@ -49,7 +52,15 @@ export type DialogOptions = OpenDialogOptions | SaveDialogOptions;
|
||||
|
||||
export const showOpenDialog = (options: OpenDialogOptions): Promise<string> => {
|
||||
return new Promise<string>((resolve, reject): void => {
|
||||
const dialog = new Dialog(DialogType.Open, options);
|
||||
// Make the default to show hidden files and directories since there is no
|
||||
// other way to make them visible in the dialogs currently.
|
||||
const dialog = new Dialog(DialogType.Open, typeof options.properties.showHiddenFiles === "undefined" ? {
|
||||
...options,
|
||||
properties: {
|
||||
...options.properties,
|
||||
showHiddenFiles: true,
|
||||
},
|
||||
} : options);
|
||||
dialog.onSelect((e) => {
|
||||
dialog.dispose();
|
||||
resolve(e);
|
||||
@@ -68,8 +79,12 @@ interface DialogEntry {
|
||||
readonly isDirectory: boolean;
|
||||
readonly size: number;
|
||||
readonly lastModified: string;
|
||||
readonly isDisabled?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Open and save dialogs.
|
||||
*/
|
||||
class Dialog {
|
||||
private _path: string | undefined;
|
||||
|
||||
@@ -108,7 +123,7 @@ class Dialog {
|
||||
this.root.style.width = "850px";
|
||||
this.root.style.height = "600px";
|
||||
this.background.appendChild(this.root);
|
||||
(document.getElementById("workbench.main.container") || document.body).appendChild(this.background);
|
||||
(document.querySelector(".monaco-workbench") || document.body).appendChild(this.background);
|
||||
this.root.classList.add("dialog");
|
||||
|
||||
const setProperty = (vari: string, id: string): void => {
|
||||
@@ -263,10 +278,12 @@ class Dialog {
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// If it's a directory, we want to navigate to it. If it's a file, then we
|
||||
// only want to open it if opening files is supported.
|
||||
if (element.isDirectory) {
|
||||
this.path = element.fullPath;
|
||||
} else {
|
||||
// Open
|
||||
} else if ((this.options as OpenDialogOptions).properties.openFile) {
|
||||
this.selectEmitter.emit(element.fullPath);
|
||||
}
|
||||
});
|
||||
@@ -282,15 +299,22 @@ class Dialog {
|
||||
});
|
||||
buttonsNode.appendChild(cancelBtn);
|
||||
const confirmBtn = document.createElement("button");
|
||||
confirmBtn.innerText = "Confirm";
|
||||
const openDirectory = (this.options as OpenDialogOptions).properties.openDirectory;
|
||||
confirmBtn.innerText = this.options.buttonLabel || "Confirm";
|
||||
confirmBtn.addEventListener("click", () => {
|
||||
if (this._path) {
|
||||
if (this._path && openDirectory) {
|
||||
this.selectEmitter.emit(this._path);
|
||||
}
|
||||
});
|
||||
// Disable if we can't open directories, otherwise you can open a directory
|
||||
// as a file which won't work. This is because our button currently just
|
||||
// always opens whatever directory is opened and will not open selected
|
||||
// files. (A single click on a file is used to open it instead.)
|
||||
if (!openDirectory) {
|
||||
confirmBtn.disabled = true;
|
||||
}
|
||||
buttonsNode.appendChild(confirmBtn);
|
||||
this.root.appendChild(buttonsNode);
|
||||
this.entryList.layout();
|
||||
|
||||
this.path = options.defaultPath || "/";
|
||||
}
|
||||
@@ -303,6 +327,9 @@ class Dialog {
|
||||
return this.errorEmitter.event;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the dialog.
|
||||
*/
|
||||
public dispose(): void {
|
||||
this.selectEmitter.dispose();
|
||||
this.errorEmitter.dispose();
|
||||
@@ -310,6 +337,9 @@ class Dialog {
|
||||
this.background.remove();
|
||||
}
|
||||
|
||||
/**
|
||||
* Build and insert the path shown at the top of the dialog.
|
||||
*/
|
||||
private buildPath(): void {
|
||||
while (this.pathNode.lastChild) {
|
||||
this.pathNode.removeChild(this.pathNode.lastChild);
|
||||
@@ -360,6 +390,8 @@ class Dialog {
|
||||
return true;
|
||||
});
|
||||
|
||||
this.entryList.layout();
|
||||
|
||||
this.entryList.setChildren(null, items.map((i: DialogEntry): ITreeElement<DialogEntry> => ({ element: i })));
|
||||
this.entryList.domFocus();
|
||||
this.entryList.setFocus([null]);
|
||||
@@ -376,9 +408,12 @@ class Dialog {
|
||||
return (<any>this.entryList).typeFilterController.filter._pattern;
|
||||
}
|
||||
|
||||
/**
|
||||
* List the files and return dialog entries.
|
||||
*/
|
||||
private async list(directory: string): Promise<ReadonlyArray<DialogEntry>> {
|
||||
const paths = (await util.promisify(fs.readdir)(directory)).sort();
|
||||
const stats = await Promise.all(paths.map(p => util.promisify(fs.stat)(path.join(directory, p))));
|
||||
const stats = await Promise.all(paths.map(p => util.promisify(fs.lstat)(path.join(directory, p))));
|
||||
|
||||
return stats.map((stat, index): DialogEntry => ({
|
||||
fullPath: path.join(directory, paths[index]),
|
||||
@@ -386,6 +421,9 @@ class Dialog {
|
||||
isDirectory: stat.isDirectory(),
|
||||
lastModified: stat.mtime.toDateString(),
|
||||
size: stat.size,
|
||||
// If we can't open files, show them as disabled.
|
||||
isDisabled: !stat.isDirectory()
|
||||
&& !(this.options as OpenDialogOptions).properties.openFile,
|
||||
}));
|
||||
}
|
||||
}
|
||||
@@ -397,11 +435,17 @@ interface DialogEntryData {
|
||||
label: HighlightedLabel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rendering for the different parts of a dialog entry.
|
||||
*/
|
||||
class DialogEntryRenderer implements ITreeRenderer<DialogEntry, string, DialogEntryData> {
|
||||
public get templateId(): string {
|
||||
return "dialog-entry";
|
||||
}
|
||||
|
||||
/**
|
||||
* Append and return containers for each part of the dialog entry.
|
||||
*/
|
||||
public renderTemplate(container: HTMLElement): DialogEntryData {
|
||||
addClass(container, "dialog-entry");
|
||||
addClass(container, "dialog-grid");
|
||||
@@ -422,6 +466,9 @@ class DialogEntryRenderer implements ITreeRenderer<DialogEntry, string, DialogEn
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a dialog entry.
|
||||
*/
|
||||
public renderElement(node: ITreeNode<DialogEntry, string>, _index: number, templateData: DialogEntryData): void {
|
||||
templateData.icon.className = "dialog-entry-icon monaco-icon-label";
|
||||
const classes = getIconClasses(
|
||||
@@ -442,11 +489,33 @@ class DialogEntryRenderer implements ITreeRenderer<DialogEntry, string, DialogEn
|
||||
start: 0,
|
||||
end: node.filterData.length,
|
||||
}] : []);
|
||||
templateData.size.innerText = node.element.size.toString();
|
||||
templateData.size.innerText = !node.element.isDirectory ? this.humanReadableSize(node.element.size) : "";
|
||||
templateData.lastModified.innerText = node.element.lastModified;
|
||||
|
||||
// We know this exists because we created the template.
|
||||
const entryContainer = templateData.label.element.parentElement!.parentElement!.parentElement!;
|
||||
if (node.element.isDisabled) {
|
||||
entryContainer.classList.add("disabled");
|
||||
} else {
|
||||
entryContainer.classList.remove("disabled");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Does nothing (not implemented).
|
||||
*/
|
||||
public disposeTemplate(_templateData: DialogEntryData): void {
|
||||
// throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a positive size in bytes, return a string that is more readable for
|
||||
* humans.
|
||||
*/
|
||||
private humanReadableSize(bytes: number): string {
|
||||
const units = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
|
||||
const i = Math.min(Math.floor(bytes && Math.log(bytes) / Math.log(1000)), units.length - 1);
|
||||
|
||||
return (bytes / Math.pow(1000, i)).toFixed(2) + " " + units[i];
|
||||
}
|
||||
}
|
||||
|
||||
170
packages/vscode/src/fill/applicationInsights.ts
Normal file
170
packages/vscode/src/fill/applicationInsights.ts
Normal file
@@ -0,0 +1,170 @@
|
||||
/**
|
||||
* Used by node
|
||||
*/
|
||||
import * as https from "https";
|
||||
import * as os from "os";
|
||||
|
||||
export const defaultClient = "filler";
|
||||
|
||||
export class TelemetryClient {
|
||||
public channel = {
|
||||
setUseDiskRetryCaching: (): void => undefined,
|
||||
};
|
||||
|
||||
public constructor() {
|
||||
//
|
||||
}
|
||||
|
||||
public trackEvent(options: {
|
||||
name: string;
|
||||
properties: object;
|
||||
measurements: object;
|
||||
}): void {
|
||||
if (!options.properties) {
|
||||
options.properties = {};
|
||||
}
|
||||
if (!options.measurements) {
|
||||
options.measurements = {};
|
||||
}
|
||||
|
||||
try {
|
||||
const cpus = os.cpus();
|
||||
// tslint:disable-next-line:no-any
|
||||
(options.measurements as any).cpu = {
|
||||
model: cpus[0].model,
|
||||
cores: cpus.length,
|
||||
};
|
||||
} catch (ex) {
|
||||
// Nothin
|
||||
}
|
||||
|
||||
try {
|
||||
// tslint:disable-next-line:no-any
|
||||
(options.measurements as any).memory = {
|
||||
virtual_free: os.freemem(),
|
||||
virtual_used: os.totalmem(),
|
||||
};
|
||||
} catch (ex) {
|
||||
//
|
||||
}
|
||||
|
||||
try {
|
||||
// tslint:disable:no-any
|
||||
(options.properties as any)["common.shell"] = os.userInfo().shell;
|
||||
(options.properties as any)["common.release"] = os.release();
|
||||
(options.properties as any)["common.arch"] = os.arch();
|
||||
// tslint:enable:no-any
|
||||
} catch (ex) {
|
||||
//
|
||||
}
|
||||
|
||||
try {
|
||||
// tslint:disable-next-line:no-any
|
||||
(options.properties as any)["common.machineId"] = machineIdSync();
|
||||
} catch (ex) {
|
||||
//
|
||||
}
|
||||
|
||||
try {
|
||||
const request = https.request({
|
||||
host: "v1.telemetry.coder.com",
|
||||
port: 443,
|
||||
path: "/track",
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
request.on("error", () => {
|
||||
// Do nothing, we don"t really care
|
||||
});
|
||||
request.write(JSON.stringify(options));
|
||||
request.end();
|
||||
} catch (ex) {
|
||||
// Suppress all errs
|
||||
}
|
||||
}
|
||||
|
||||
public flush(options: {
|
||||
readonly callback: () => void;
|
||||
}): void {
|
||||
options.callback();
|
||||
}
|
||||
}
|
||||
|
||||
// Taken from https://github.com/automation-stack/node-machine-id
|
||||
import { exec, execSync } from "child_process";
|
||||
import { createHash } from "crypto";
|
||||
|
||||
const isWindowsProcessMixedOrNativeArchitecture = (): "" | "mixed" | "native" => {
|
||||
// detect if the node binary is the same arch as the Windows OS.
|
||||
// or if this is 32 bit node on 64 bit windows.
|
||||
if (process.platform !== "win32") {
|
||||
return "";
|
||||
}
|
||||
if (process.arch === "ia32" && process.env.hasOwnProperty("PROCESSOR_ARCHITEW6432")) {
|
||||
return "mixed";
|
||||
}
|
||||
|
||||
return "native";
|
||||
};
|
||||
|
||||
let { platform } = process,
|
||||
win32RegBinPath = {
|
||||
native: "%windir%\\System32",
|
||||
mixed: "%windir%\\sysnative\\cmd.exe /c %windir%\\System32",
|
||||
"": "",
|
||||
},
|
||||
guid = {
|
||||
darwin: "ioreg -rd1 -c IOPlatformExpertDevice",
|
||||
win32: `${win32RegBinPath[isWindowsProcessMixedOrNativeArchitecture()]}\\REG ` +
|
||||
"QUERY HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Cryptography " +
|
||||
"/v MachineGuid",
|
||||
linux: "( cat /var/lib/dbus/machine-id /etc/machine-id 2> /dev/null || hostname ) | head -n 1 || :",
|
||||
freebsd: "kenv -q smbios.system.uuid || sysctl -n kern.hostuuid",
|
||||
// tslint:disable-next-line:no-any
|
||||
} as any;
|
||||
|
||||
const hash = (guid: string): string => {
|
||||
return createHash("sha256").update(guid).digest("hex");
|
||||
};
|
||||
|
||||
const expose = (result: string): string => {
|
||||
switch (platform) {
|
||||
case "darwin":
|
||||
return result
|
||||
.split("IOPlatformUUID")[1]
|
||||
.split("\n")[0].replace(/\=|\s+|\"/ig, "")
|
||||
.toLowerCase();
|
||||
case "win32":
|
||||
return result
|
||||
.toString()
|
||||
.split("REG_SZ")[1]
|
||||
.replace(/\r+|\n+|\s+/ig, "")
|
||||
.toLowerCase();
|
||||
case "linux":
|
||||
return result
|
||||
.toString()
|
||||
.replace(/\r+|\n+|\s+/ig, "")
|
||||
.toLowerCase();
|
||||
case "freebsd":
|
||||
return result
|
||||
.toString()
|
||||
.replace(/\r+|\n+|\s+/ig, "")
|
||||
.toLowerCase();
|
||||
default:
|
||||
throw new Error(`Unsupported platform: ${process.platform}`);
|
||||
}
|
||||
};
|
||||
|
||||
let cachedMachineId: string | undefined;
|
||||
|
||||
const machineIdSync = (): string => {
|
||||
if (cachedMachineId) {
|
||||
return cachedMachineId;
|
||||
}
|
||||
let id: string = expose(execSync(guid[platform]).toString());
|
||||
cachedMachineId = hash(id);
|
||||
|
||||
return cachedMachineId;
|
||||
};
|
||||
@@ -1,7 +1,9 @@
|
||||
import * as path from "path";
|
||||
import * as paths from "./paths";
|
||||
import * as environment from "vs/platform/environment/node/environmentService";
|
||||
|
||||
/**
|
||||
* Customize paths using data received from the initialization message.
|
||||
*/
|
||||
export class EnvironmentService extends environment.EnvironmentService {
|
||||
public get sharedIPCHandle(): string {
|
||||
return paths.getSocketPath() || super.sharedIPCHandle;
|
||||
@@ -10,6 +12,18 @@ export class EnvironmentService extends environment.EnvironmentService {
|
||||
public get extensionsPath(): string {
|
||||
return paths.getExtensionsDirectory();
|
||||
}
|
||||
|
||||
public get builtinExtensionsPath(): string {
|
||||
return paths.getBuiltInExtensionsDirectory();
|
||||
}
|
||||
|
||||
public get extraExtensionPaths(): string[] {
|
||||
return paths.getExtraExtensionDirectories();
|
||||
}
|
||||
|
||||
public get extraBuiltinExtensionPaths(): string[] {
|
||||
return paths.getExtraBuiltinExtensionDirectories();
|
||||
}
|
||||
}
|
||||
|
||||
const target = environment as typeof environment;
|
||||
|
||||
@@ -1,16 +1,35 @@
|
||||
import { logger } from "@coder/logger";
|
||||
import { IDisposable } from "vs/base/common/lifecycle";
|
||||
import * as actions from "vs/platform/actions/common/actions";
|
||||
import { CloseWorkspaceAction } from "vs/workbench/browser/actions/workspaceActions";
|
||||
import { OpenProcessExplorer } from "vs/workbench/contrib/issue/electron-browser/issueActions";
|
||||
import { ToggleDevToolsAction } from "vs/workbench/electron-browser/actions/developerActions";
|
||||
import { OpenPrivacyStatementUrlAction, OpenRequestFeatureUrlAction, OpenTwitterUrlAction } from "vs/workbench/electron-browser/actions/helpActions";
|
||||
import { CloseCurrentWindowAction, NewWindowAction, ShowAboutDialogAction } from "vs/workbench/electron-browser/actions/windowActions";
|
||||
import { REVEAL_IN_OS_COMMAND_ID } from "vs/workbench/contrib/files/browser/fileCommands";
|
||||
|
||||
const toSkip = [
|
||||
ToggleDevToolsAction.ID,
|
||||
OpenTwitterUrlAction.ID,
|
||||
OpenPrivacyStatementUrlAction.ID,
|
||||
ShowAboutDialogAction.ID,
|
||||
OpenProcessExplorer.ID,
|
||||
OpenRequestFeatureUrlAction.ID,
|
||||
NewWindowAction.ID,
|
||||
CloseCurrentWindowAction.ID,
|
||||
CloseWorkspaceAction.ID,
|
||||
REVEAL_IN_OS_COMMAND_ID,
|
||||
|
||||
// Unfortunately referenced as a string
|
||||
"update.showCurrentReleaseNotes",
|
||||
"workbench.action.openIssueReporter",
|
||||
];
|
||||
|
||||
// Intercept appending menu items so we can skip items that won't work.
|
||||
const originalAppend = actions.MenuRegistry.appendMenuItem.bind(actions.MenuRegistry);
|
||||
actions.MenuRegistry.appendMenuItem = (id: actions.MenuId, item: actions.IMenuItem | actions.ISubmenuItem): IDisposable => {
|
||||
if (actions.isIMenuItem(item)) {
|
||||
switch (item.command.id) {
|
||||
case ToggleDevToolsAction.ID: // There appears to be no way to toggle this programmatically.
|
||||
logger.debug(`Skipping unsupported menu item ${item.command.id}`);
|
||||
|
||||
if (toSkip.indexOf(item.command.id) !== -1) {
|
||||
// Skip instantiation
|
||||
return {
|
||||
dispose: (): void => undefined,
|
||||
};
|
||||
|
||||
@@ -2,8 +2,8 @@ import * as nls from "vs/nls";
|
||||
import { Action } from "vs/base/common/actions";
|
||||
import { TERMINAL_COMMAND_ID } from "vs/workbench/contrib/terminal/common/terminalCommands";
|
||||
import { ITerminalService } from "vs/workbench/contrib/terminal/common/terminal";
|
||||
import * as actions from "vs/workbench/contrib/terminal/electron-browser/terminalActions";
|
||||
import * as instance from "vs/workbench/contrib/terminal/electron-browser/terminalInstance";
|
||||
import * as actions from "vs/workbench/contrib/terminal/browser/terminalActions";
|
||||
import * as instance from "vs/workbench/contrib/terminal/browser/terminalInstance";
|
||||
import { client } from "../client";
|
||||
|
||||
const getLabel = (key: string, enabled: boolean): string => {
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import { InitData, SharedProcessData } from "@coder/protocol";
|
||||
|
||||
/**
|
||||
* Provides paths.
|
||||
*/
|
||||
class Paths {
|
||||
private _appData: string | undefined;
|
||||
private _defaultUserData: string | undefined;
|
||||
@@ -7,6 +10,8 @@ class Paths {
|
||||
private _extensionsDirectory: string | undefined;
|
||||
private _builtInExtensionsDirectory: string | undefined;
|
||||
private _workingDirectory: string | undefined;
|
||||
private _extraExtensionDirectories: string[] | undefined;
|
||||
private _extraBuiltinExtensionDirectories: string[] | undefined;
|
||||
|
||||
public get appData(): string {
|
||||
if (typeof this._appData === "undefined") {
|
||||
@@ -48,6 +53,22 @@ class Paths {
|
||||
return this._builtInExtensionsDirectory;
|
||||
}
|
||||
|
||||
public get extraExtensionDirectories(): string[] {
|
||||
if (!this._extraExtensionDirectories) {
|
||||
throw new Error("trying to access extra extension directories before they have been set");
|
||||
}
|
||||
|
||||
return this._extraExtensionDirectories;
|
||||
}
|
||||
|
||||
public get extraBuiltinExtensionDirectories(): string[] {
|
||||
if (!this._extraBuiltinExtensionDirectories) {
|
||||
throw new Error("trying to access extra builtin extension directories before they have been set");
|
||||
}
|
||||
|
||||
return this._extraBuiltinExtensionDirectories;
|
||||
}
|
||||
|
||||
public get workingDirectory(): string {
|
||||
if (!this._workingDirectory) {
|
||||
throw new Error("trying to access working directory before it has been set");
|
||||
@@ -56,6 +77,9 @@ class Paths {
|
||||
return this._workingDirectory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize paths using the provided data.
|
||||
*/
|
||||
public initialize(data: InitData, sharedData: SharedProcessData): void {
|
||||
process.env.VSCODE_LOGS = sharedData.logPath;
|
||||
this._appData = data.dataDirectory;
|
||||
@@ -64,6 +88,8 @@ class Paths {
|
||||
this._extensionsDirectory = data.extensionsDirectory;
|
||||
this._builtInExtensionsDirectory = data.builtInExtensionsDirectory;
|
||||
this._workingDirectory = data.workingDirectory;
|
||||
this._extraExtensionDirectories = data.extraExtensionDirectories;
|
||||
this._extraBuiltinExtensionDirectories = data.extraBuiltinExtensionDirectories;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,4 +99,6 @@ export const getDefaultUserDataPath = (): string => _paths.defaultUserData;
|
||||
export const getWorkingDirectory = (): string => _paths.workingDirectory;
|
||||
export const getExtensionsDirectory = (): string => _paths.extensionsDirectory;
|
||||
export const getBuiltInExtensionsDirectory = (): string => _paths.builtInExtensionsDirectory;
|
||||
export const getExtraExtensionDirectories = (): string[] => _paths.extraExtensionDirectories;
|
||||
export const getExtraBuiltinExtensionDirectories = (): string[] => _paths.extraBuiltinExtensionDirectories;
|
||||
export const getSocketPath = (): string => _paths.socketPath;
|
||||
|
||||
@@ -4,6 +4,20 @@ import { IProductConfiguration } from "vs/platform/product/node/product";
|
||||
class Product implements IProductConfiguration {
|
||||
public nameShort = "code-server";
|
||||
public nameLong = "code-server";
|
||||
public documentationUrl = "https://code.visualstudio.com/docs";
|
||||
public keyboardShortcutsUrlMac = "https://code.visualstudio.com/shortcuts/keyboard-shortcuts-macos.pdf";
|
||||
public keyboardShortcutsUrlLinux = "https://code.visualstudio.com/shortcuts/keyboard-shortcuts-linux.pdf";
|
||||
public keyboardShortcutsUrlWin = "https://code.visualstudio.com/shortcuts/keyboard-shortcuts-windows.pdf";
|
||||
public introductoryVideosUrl = "https://code.visualstudio.com/docs/getstarted/introvideos";
|
||||
public tipsAndTricksUrl = "https://code.visualstudio.com/docs/getstarted/tips-and-tricks";
|
||||
public twitterUrl = "https://twitter.com/code";
|
||||
public licenseUrl = "https://github.com/cdr/code-server/blob/master/LICENSE";
|
||||
public aiConfig = process.env.DISABLE_TELEMETRY ? undefined! : {
|
||||
// Only needed so vscode can see that content exists for this value.
|
||||
// We override the application insights module.
|
||||
asimovKey: "content",
|
||||
};
|
||||
public enableTelemetry = process.env.DISABLE_TELEMETRY ? false : true;
|
||||
|
||||
private _dataFolderName: string | undefined;
|
||||
public get dataFolderName(): string {
|
||||
@@ -14,10 +28,16 @@ class Product implements IProductConfiguration {
|
||||
return this._dataFolderName;
|
||||
}
|
||||
|
||||
public extensionsGallery = {
|
||||
serviceUrl: global && global.process && global.process.env.SERVICE_URL
|
||||
|| process.env.SERVICE_URL
|
||||
|| "https://v1.extapi.coder.com",
|
||||
// tslint:disable-next-line:no-any
|
||||
public extensionsGallery: any = {
|
||||
get serviceUrl(): string {
|
||||
return process.env.SERVICE_URL || "https://v1.extapi.coder.com";
|
||||
},
|
||||
|
||||
get itemUrl(): string {
|
||||
return process.env.ITEM_URL || "";
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
public extensionExecutionEnvironments = {
|
||||
|
||||
@@ -11,6 +11,8 @@ import { IStorageService, WillSaveStateReason } from "vs/platform/storage/common
|
||||
import * as paths from "./paths";
|
||||
import { workbench } from "../workbench";
|
||||
|
||||
// tslint:disable completed-docs
|
||||
|
||||
class StorageDatabase implements workspaceStorage.IStorageDatabase {
|
||||
public readonly onDidChangeItemsExternal = Event.None;
|
||||
private readonly items = new Map<string, string>();
|
||||
@@ -26,7 +28,8 @@ class StorageDatabase implements workspaceStorage.IStorageDatabase {
|
||||
}
|
||||
|
||||
this.triggerFlush(WillSaveStateReason.SHUTDOWN);
|
||||
navigator.sendBeacon(`/resource${this.path}`, this.content);
|
||||
const resourceBaseUrl = location.pathname.replace(/\/$/, "") + "/resource";
|
||||
navigator.sendBeacon(`${resourceBaseUrl}/${this.path}`, this.content);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,17 @@ import * as vscodeTextmate from "../../../../lib/vscode/node_modules/vscode-text
|
||||
|
||||
const target = vscodeTextmate as typeof vscodeTextmate;
|
||||
|
||||
const ctx = (require as any).context("../../../../lib/extensions", true, /.*\.tmLanguage.json$/);
|
||||
// Maps grammar scope to loaded grammar
|
||||
const scopeToGrammar = {} as any;
|
||||
|
||||
ctx.keys().forEach((key: string) => {
|
||||
const value = ctx(key);
|
||||
if (value.scopeName) {
|
||||
scopeToGrammar[value.scopeName] = value;
|
||||
}
|
||||
});
|
||||
|
||||
target.Registry = class Registry extends vscodeTextmate.Registry {
|
||||
public constructor(opts: vscodeTextmate.RegistryOptions) {
|
||||
super({
|
||||
@@ -21,6 +32,13 @@ target.Registry = class Registry extends vscodeTextmate.Registry {
|
||||
}).catch(reason => rej(reason));
|
||||
});
|
||||
},
|
||||
loadGrammar: async (scopeName: string) => {
|
||||
if (scopeToGrammar[scopeName]) {
|
||||
return scopeToGrammar[scopeName];
|
||||
}
|
||||
|
||||
return opts.loadGrammar(scopeName);
|
||||
},
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,21 +1,32 @@
|
||||
import * as electron from "electron";
|
||||
import { Emitter } from "@coder/events";
|
||||
import * as windowsIpc from "vs/platform/windows/node/windowsIpc";
|
||||
import { IWindowsService, INativeOpenDialogOptions, MessageBoxOptions, SaveDialogOptions, OpenDialogOptions, IMessageBoxResult, IDevToolsOptions, IEnterWorkspaceResult, CrashReporterStartOptions, INewWindowOptions, IOpenFileRequest, IAddFoldersRequest } from "vs/platform/windows/common/windows";
|
||||
import { logger } from "@coder/logger";
|
||||
import { IWindowsService, INativeOpenDialogOptions, MessageBoxOptions, SaveDialogOptions, OpenDialogOptions, IMessageBoxResult, IDevToolsOptions, IEnterWorkspaceResult, CrashReporterStartOptions, INewWindowOptions, IOpenFileRequest, IAddFoldersRequest, IURIToOpen, IOpenSettings } from "vs/platform/windows/common/windows";
|
||||
import { ParsedArgs } from "vs/platform/environment/common/environment";
|
||||
import { IWorkspaceIdentifier, IWorkspaceFolderCreationData, ISingleFolderWorkspaceIdentifier } from "vs/platform/workspaces/common/workspaces";
|
||||
import { URI } from "vs/base/common/uri";
|
||||
import { IRecentlyOpened } from "vs/platform/history/common/history";
|
||||
import { IRecentlyOpened, IRecent } from "vs/platform/history/common/history";
|
||||
import { ISerializableCommandAction } from "vs/platform/actions/common/actions";
|
||||
import { client } from "../client";
|
||||
import { showOpenDialog } from "../dialog";
|
||||
import { workbench } from "../workbench";
|
||||
|
||||
// tslint:disable completed-docs
|
||||
|
||||
// VS Code overrides window.open to call openExternal, but we then call
|
||||
// window.open which results in an infinite loop. Store the function but also
|
||||
// make it unable to be set (doesn't work otherwise).
|
||||
const windowOpen = window.open;
|
||||
Object.defineProperty(window, "open", {
|
||||
set: (): void => { /* Not allowed. */ },
|
||||
get: (): Function => windowOpen,
|
||||
});
|
||||
|
||||
/**
|
||||
* Instead of going to the shared process, we'll directly run these methods on
|
||||
* the client. This setup means we can only control the current window.
|
||||
*/
|
||||
class WindowsService implements IWindowsService {
|
||||
export class WindowsService implements IWindowsService {
|
||||
// tslint:disable-next-line no-any
|
||||
public _serviceBrand: any;
|
||||
|
||||
@@ -36,9 +47,9 @@ class WindowsService implements IWindowsService {
|
||||
private readonly window = new electron.BrowserWindow();
|
||||
|
||||
// Dialogs
|
||||
public async pickFileFolderAndOpen(_options: INativeOpenDialogOptions): Promise<void> {
|
||||
public async pickFileFolderAndOpen(options: INativeOpenDialogOptions): Promise<void> {
|
||||
showOpenDialog({
|
||||
...(_options.dialogOptions || {}),
|
||||
...(options.dialogOptions || {}),
|
||||
properties: {
|
||||
openFile: true,
|
||||
openDirectory: true,
|
||||
@@ -51,13 +62,13 @@ class WindowsService implements IWindowsService {
|
||||
}],
|
||||
} as IOpenFileRequest);
|
||||
}).catch((ex) => {
|
||||
//
|
||||
logger.error(ex.message);
|
||||
});
|
||||
}
|
||||
|
||||
public async pickFileAndOpen(_options: INativeOpenDialogOptions): Promise<void> {
|
||||
public async pickFileAndOpen(options: INativeOpenDialogOptions): Promise<void> {
|
||||
showOpenDialog({
|
||||
...(_options.dialogOptions || {}),
|
||||
...(options.dialogOptions || {}),
|
||||
properties: {
|
||||
openFile: true,
|
||||
},
|
||||
@@ -69,26 +80,32 @@ class WindowsService implements IWindowsService {
|
||||
}],
|
||||
} as IOpenFileRequest);
|
||||
}).catch((ex) => {
|
||||
//
|
||||
logger.error(ex.message);
|
||||
});
|
||||
}
|
||||
|
||||
public async pickFolderAndOpen(_options: INativeOpenDialogOptions): Promise<void> {
|
||||
public async pickFolderAndOpen(options: INativeOpenDialogOptions): Promise<void> {
|
||||
if (!options.dialogOptions) {
|
||||
options.dialogOptions = {};
|
||||
}
|
||||
if (!options.dialogOptions.title) {
|
||||
options.dialogOptions.title = "Open Folder";
|
||||
}
|
||||
showOpenDialog({
|
||||
...(_options.dialogOptions || {}),
|
||||
...(options.dialogOptions || {}),
|
||||
properties: {
|
||||
openDirectory: true,
|
||||
},
|
||||
}).then((path) => {
|
||||
workbench.workspace = URI.file(path);
|
||||
}).catch((ex) => {
|
||||
//
|
||||
logger.error(ex.message);
|
||||
});
|
||||
}
|
||||
|
||||
public async pickWorkspaceAndOpen(_options: INativeOpenDialogOptions): Promise<void> {
|
||||
public async pickWorkspaceAndOpen(options: INativeOpenDialogOptions): Promise<void> {
|
||||
showOpenDialog({
|
||||
...(_options.dialogOptions || {}),
|
||||
...(options.dialogOptions || {}),
|
||||
properties: {
|
||||
openDirectory: true,
|
||||
},
|
||||
@@ -98,7 +115,7 @@ class WindowsService implements IWindowsService {
|
||||
foldersToAdd: [URI.file(path)],
|
||||
} as IAddFoldersRequest);
|
||||
}).catch((ex) => {
|
||||
//
|
||||
logger.error(ex.message);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -121,16 +138,14 @@ class WindowsService implements IWindowsService {
|
||||
});
|
||||
}
|
||||
|
||||
public showOpenDialog(windowId: number, options: OpenDialogOptions): Promise<string[]> {
|
||||
return showOpenDialog({
|
||||
public async showOpenDialog(_windowId: number, options: OpenDialogOptions): Promise<string[]> {
|
||||
return [await showOpenDialog({
|
||||
...(options || {}),
|
||||
properties: {
|
||||
openDirectory: true,
|
||||
openFile: true,
|
||||
openDirectory: options && options.properties && options.properties.includes("openDirectory") || false,
|
||||
openFile: options && options.properties && options.properties.includes("openFile") || false,
|
||||
},
|
||||
}).then((path) => {
|
||||
return [path];
|
||||
});
|
||||
})];
|
||||
}
|
||||
|
||||
public reloadWindow(windowId: number, _args?: ParsedArgs): Promise<void> {
|
||||
@@ -149,14 +164,14 @@ class WindowsService implements IWindowsService {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public enterWorkspace(_windowId: number, _path: URI): Promise<IEnterWorkspaceResult> {
|
||||
if (_path.path.endsWith(".json")) {
|
||||
public enterWorkspace(_windowId: number, uri: URI): Promise<IEnterWorkspaceResult> {
|
||||
if (uri.path.endsWith(".json")) {
|
||||
workbench.workspace = {
|
||||
id: "Untitled",
|
||||
configPath: _path.path,
|
||||
configPath: uri,
|
||||
};
|
||||
} else {
|
||||
workbench.workspace = _path;
|
||||
workbench.workspace = uri;
|
||||
}
|
||||
|
||||
return undefined!;
|
||||
@@ -180,7 +195,7 @@ class WindowsService implements IWindowsService {
|
||||
return Promise.resolve(this.getWindowById(windowId).setRepresentedFilename(fileName));
|
||||
}
|
||||
|
||||
public addRecentlyOpened(_files: URI[]): Promise<void> {
|
||||
public addRecentlyOpened(_files: IRecent[]): Promise<void> {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
@@ -284,7 +299,7 @@ class WindowsService implements IWindowsService {
|
||||
}
|
||||
|
||||
// Global methods
|
||||
public openWindow(_windowId: number, _paths: URI[], _options?: { forceNewWindow?: boolean, forceReuseWindow?: boolean, forceOpenWorkspaceAsFile?: boolean, args?: ParsedArgs }): Promise<void> {
|
||||
public openWindow(_windowId: number, _uris: IURIToOpen[], _options?: IOpenSettings): Promise<void> {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
@@ -308,8 +323,8 @@ class WindowsService implements IWindowsService {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public async showItemInFolder(_path: string): Promise<void> {
|
||||
workbench.workspace = URI.file(_path);
|
||||
public async showItemInFolder(uri: URI): Promise<void> {
|
||||
workbench.workspace = uri;
|
||||
}
|
||||
|
||||
public getActiveWindowId(): Promise<number | undefined> {
|
||||
@@ -343,7 +358,3 @@ class WindowsService implements IWindowsService {
|
||||
return this.window;
|
||||
}
|
||||
}
|
||||
|
||||
const target = windowsIpc as typeof windowsIpc;
|
||||
// @ts-ignore TODO: don't ignore it.
|
||||
target.WindowsChannelClient = WindowsService;
|
||||
|
||||
@@ -5,7 +5,7 @@ import { IWorkbenchActionRegistry, Extensions } from "vs/workbench/common/action
|
||||
import { SyncActionDescriptor } from "vs/platform/actions/common/actions";
|
||||
import { ContextKeyExpr } from "vs/platform/contextkey/common/contextkey";
|
||||
import { ToggleDevToolsAction } from "vs/workbench/electron-browser/actions/developerActions";
|
||||
import { TerminalPasteAction } from "vs/workbench/contrib/terminal/electron-browser/terminalActions";
|
||||
import { TerminalPasteAction } from "vs/workbench/contrib/terminal/browser/terminalActions";
|
||||
import { KEYBINDING_CONTEXT_TERMINAL_FOCUS } from "vs/workbench/contrib/terminal/common/terminal";
|
||||
import { KeyCode, KeyMod } from "vs/base/common/keyCodes";
|
||||
import { workbench } from "../workbench";
|
||||
|
||||
@@ -53,3 +53,7 @@
|
||||
width: 56px !important;
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
.window-controls-container {
|
||||
display: none !important;
|
||||
}
|
||||
@@ -29,8 +29,6 @@ import { LogLevel } from "vs/platform/log/common/log";
|
||||
import { RawContextKey, IContextKeyService } from "vs/platform/contextkey/common/contextkey";
|
||||
import { ServiceCollection } from "vs/platform/instantiation/common/serviceCollection";
|
||||
import { URI } from "vs/base/common/uri";
|
||||
import { BackupMainService } from "vs/platform/backup/electron-main/backupMainService";
|
||||
import { IInstantiationService } from "vs/platform/instantiation/common/instantiation";
|
||||
|
||||
/**
|
||||
* Initializes VS Code and provides a way to call into general client
|
||||
@@ -131,13 +129,12 @@ export class Workbench {
|
||||
public set serviceCollection(collection: ServiceCollection) {
|
||||
this._serviceCollection = collection;
|
||||
|
||||
// TODO: If possible it might be better to start the app from vs/code/electron-main/app.
|
||||
// For now, manually initialize services from there as needed.
|
||||
const inst = this._serviceCollection.get(IInstantiationService) as IInstantiationService;
|
||||
const backupMainService = inst.createInstance(BackupMainService) as BackupMainService;
|
||||
backupMainService.initialize().catch((error) => {
|
||||
logger.error(error.message);
|
||||
const contextKeys = this.serviceCollection.get(IContextKeyService) as IContextKeyService;
|
||||
const bounded = this.clipboardContextKey.bindTo(contextKeys);
|
||||
client.clipboard.onPermissionChange((enabled) => {
|
||||
bounded.set(enabled);
|
||||
});
|
||||
client.clipboard.initialize();
|
||||
|
||||
client.progressService = {
|
||||
start: <T>(title: string, task: (progress: IProgress) => Promise<T>, onCancel: () => void): Promise<T> => {
|
||||
@@ -237,12 +234,6 @@ export class Workbench {
|
||||
return;
|
||||
}
|
||||
}
|
||||
const contextKeys = this.serviceCollection.get(IContextKeyService) as IContextKeyService;
|
||||
const bounded = this.clipboardContextKey.bindTo(contextKeys);
|
||||
client.clipboard.onPermissionChange((enabled) => {
|
||||
bounded.set(enabled);
|
||||
});
|
||||
client.clipboard.initialize();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ const vsFills = path.join(root, "packages/vscode/src/fill");
|
||||
|
||||
module.exports = merge(
|
||||
require(path.join(root, "scripts/webpack.node.config.js"))({
|
||||
dirname: __dirname,
|
||||
typescriptCompilerOptions: {
|
||||
target: "es6",
|
||||
},
|
||||
@@ -15,7 +16,6 @@ module.exports = merge(
|
||||
mode: "development",
|
||||
output: {
|
||||
chunkFilename: "[name].bundle.js",
|
||||
path: path.resolve(__dirname, "out"),
|
||||
publicPath: "/",
|
||||
filename: "bootstrap-fork.js",
|
||||
libraryTarget: "commonjs",
|
||||
@@ -36,7 +36,8 @@ module.exports = merge(
|
||||
loader: "ignore-loader",
|
||||
}],
|
||||
}, {
|
||||
test: /((\\|\/)vs(\\|\/)code(\\|\/)electron-main(\\|\/))|((\\|\/)test(\\|\/))|(OSSREADME\.json$)|\/browser\//,
|
||||
// The only thing we need in electron-browser is the shared process (including contrib).
|
||||
test: /((\\|\/)vs(\\|\/)code(\\|\/)electron-main(\\|\/))|((\\|\/)test(\\|\/))|(OSSREADME\.json$)|\/browser\/|\/electron-browser\/(?!sharedProcess\/).+\//,
|
||||
use: [{
|
||||
loader: "ignore-loader",
|
||||
}],
|
||||
@@ -50,15 +51,17 @@ module.exports = merge(
|
||||
"windows-mutex": path.resolve(fills, "empty.ts"),
|
||||
"windows-process-tree": path.resolve(fills, "empty.ts"),
|
||||
"vscode-windows-registry": path.resolve(fills, "empty.ts"),
|
||||
"vscode-windows-ca-certs": path.resolve(fills, "empty.ts"),
|
||||
"vscode-sqlite3": path.resolve(fills, "empty.ts"),
|
||||
"vs/base/browser/browser": path.resolve(fills, "empty.ts"),
|
||||
|
||||
"applicationinsights": path.join(vsFills, "applicationInsights.ts"),
|
||||
"electron": path.join(vsFills, "stdioElectron.ts"),
|
||||
"vscode-ripgrep": path.join(vsFills, "ripgrep.ts"),
|
||||
"native-keymap": path.join(vsFills, "native-keymap.ts"),
|
||||
"native-watchdog": path.join(vsFills, "native-watchdog.ts"),
|
||||
"vs/base/common/amd": path.resolve(vsFills, "amd.ts"),
|
||||
"vs/base/node/paths": path.resolve(vsFills, "paths.ts"),
|
||||
"vs/base/node/paths": path.join(vsFills, "paths.ts"),
|
||||
"vs/platform/product/node/package": path.resolve(vsFills, "package.ts"),
|
||||
"vs/platform/product/node/product": path.resolve(vsFills, "product.ts"),
|
||||
"vs/base/node/zip": path.resolve(vsFills, "zip.ts"),
|
||||
|
||||
BIN
packages/web/assets/logo.png
Normal file
BIN
packages/web/assets/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 28 KiB |
@@ -24,7 +24,14 @@
|
||||
}
|
||||
document.body.style.background = bg;
|
||||
})();
|
||||
|
||||
// Check that service workers are registered
|
||||
if ("serviceWorker" in navigator) {
|
||||
// Use the window load event to keep the page load performant
|
||||
window.addEventListener("load", () => {
|
||||
navigator.serviceWorker.register("/service-worker.js");
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -7,7 +7,9 @@ const vsFills = path.join(root, "packages/vscode/src/fill");
|
||||
|
||||
module.exports = merge(
|
||||
require(path.join(root, "scripts/webpack.client.config.js"))({
|
||||
dirname: __dirname,
|
||||
entry: path.join(root, "packages/web/src/index.ts"),
|
||||
name: "ide",
|
||||
template: path.join(root, "packages/web/src/index.html"),
|
||||
typescriptCompilerOptions: {
|
||||
"target": "es5",
|
||||
@@ -15,11 +17,6 @@ module.exports = merge(
|
||||
},
|
||||
},
|
||||
), {
|
||||
output: {
|
||||
chunkFilename: "[name]-[hash:6].bundle.js",
|
||||
path: path.join(__dirname, "out"),
|
||||
filename: "[hash:6].bundle.js",
|
||||
},
|
||||
node: {
|
||||
module: "empty",
|
||||
crypto: "empty",
|
||||
@@ -70,6 +67,7 @@ module.exports = merge(
|
||||
// This seems to be in the wrong place?
|
||||
"vs/workbench/contrib/codeEditor/electron-browser/media/WordWrap_16x.svg": "vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/WordWrap_16x.svg",
|
||||
|
||||
"vs/platform/windows/electron-browser/windowsService": path.join(vsFills, "windowsService.ts"),
|
||||
"vs/base/node/paths": path.join(vsFills, "paths.ts"),
|
||||
"vs/base/common/amd": path.join(vsFills, "amd.ts"),
|
||||
"vs/platform/product/node/package": path.resolve(vsFills, "package.ts"),
|
||||
|
||||
@@ -1,4 +1,51 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
set -euxo pipefail
|
||||
|
||||
yarn task build:server:binary
|
||||
# Build using a Docker container using the specified image and version.
|
||||
function docker_build() {
|
||||
local image="${1}" ; shift
|
||||
local version="${1}" ; shift
|
||||
|
||||
local containerId
|
||||
containerId=$(docker create --network=host --rm -it -v "$(pwd)"/.cache:/src/.cache "${image}")
|
||||
docker start "${containerId}"
|
||||
docker exec "${containerId}" mkdir -p /src
|
||||
|
||||
function docker_exec() {
|
||||
docker exec "${containerId}" bash -c "$@"
|
||||
}
|
||||
|
||||
docker cp ./. "${containerId}":/src
|
||||
docker_exec "cd /src && yarn"
|
||||
docker_exec "cd /src && npm rebuild"
|
||||
docker_exec "cd /src && NODE_ENV=production VERSION=${version} yarn task build:server:binary"
|
||||
docker_exec "cd /src && yarn task package ${version}"
|
||||
docker cp "${containerId}":/src/release/. ./release/
|
||||
|
||||
docker stop "${containerId}"
|
||||
}
|
||||
|
||||
function main() {
|
||||
local version=${VERSION:-}
|
||||
local ostype=${OSTYPE:-}
|
||||
|
||||
if [[ -z "${version}" ]] ; then
|
||||
>&2 echo "Must set VERSION environment variable"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "${ostype}" == "darwin"* ]]; then
|
||||
NODE_ENV=production VERSION="${version}" yarn task build:server:binary
|
||||
yarn task package "${version}"
|
||||
else
|
||||
local image
|
||||
if [[ "$TARGET" == "alpine" ]]; then
|
||||
image="codercom/nbin-alpine"
|
||||
else
|
||||
image="codercom/nbin-centos"
|
||||
fi
|
||||
docker_build "${image}" "${version}"
|
||||
fi
|
||||
}
|
||||
|
||||
main "$@"
|
||||
|
||||
@@ -21,3 +21,15 @@ Object.defineProperty(fs.read, util.promisify.custom, {
|
||||
global.requestAnimationFrame = (cb) => {
|
||||
setTimeout(cb, 0);
|
||||
};
|
||||
|
||||
// lchmod might not be available. Jest runs graceful-fs which makes this a no-op
|
||||
// when it doesn't exist but that doesn't seem to always run when running
|
||||
// multiple tests (or maybe it gets undone after a test).
|
||||
if (!fs.lchmod) {
|
||||
fs.lchmod = function (path, mode, cb) {
|
||||
if (cb) {
|
||||
process.nextTick(cb);
|
||||
}
|
||||
};
|
||||
fs.lchmodSync = function () {};
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user