145
ci/build.ts
145
ci/build.ts
@ -1,14 +1,10 @@
|
||||
import { Binary } from "@coder/nbin"
|
||||
import * as cp from "child_process"
|
||||
import * as fs from "fs-extra"
|
||||
import * as os from "os"
|
||||
import Bundler from "parcel-bundler"
|
||||
import * as path from "path"
|
||||
import * as util from "util"
|
||||
|
||||
enum Task {
|
||||
Binary = "binary",
|
||||
Package = "package",
|
||||
Build = "build",
|
||||
Watch = "watch",
|
||||
}
|
||||
@ -16,10 +12,8 @@ enum Task {
|
||||
class Builder {
|
||||
private readonly rootPath = path.resolve(__dirname, "..")
|
||||
private readonly vscodeSourcePath = path.join(this.rootPath, "lib/vscode")
|
||||
private readonly binariesPath = path.join(this.rootPath, "binaries")
|
||||
private readonly buildPath = path.join(this.rootPath, "build")
|
||||
private readonly codeServerVersion: string
|
||||
private _target?: "darwin" | "alpine" | "linux"
|
||||
private currentTask?: Task
|
||||
|
||||
public constructor() {
|
||||
@ -66,17 +60,9 @@ class Builder {
|
||||
throw new Error("No task provided")
|
||||
}
|
||||
|
||||
const arch = this.ensureArgument("arch", os.arch().replace(/^x/, "x86_"))
|
||||
const target = this.ensureArgument("target", await this.target())
|
||||
const binaryName = `code-server-${this.codeServerVersion}-${target}-${arch}`
|
||||
|
||||
switch (task) {
|
||||
case Task.Watch:
|
||||
return this.watch()
|
||||
case Task.Binary:
|
||||
return this.binary(binaryName)
|
||||
case Task.Package:
|
||||
return this.package(binaryName)
|
||||
case Task.Build:
|
||||
return this.build()
|
||||
default:
|
||||
@ -84,29 +70,6 @@ class Builder {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the target of the system.
|
||||
*/
|
||||
private async target(): Promise<"darwin" | "alpine" | "linux"> {
|
||||
if (!this._target) {
|
||||
if (os.platform() === "darwin" || (process.env.OSTYPE && /^darwin/.test(process.env.OSTYPE))) {
|
||||
this._target = "darwin"
|
||||
} else {
|
||||
// Alpine's ldd doesn't have a version flag but if you use an invalid flag
|
||||
// (like --version) it outputs the version to stderr and exits with 1.
|
||||
const result = await util
|
||||
.promisify(cp.exec)("ldd --version")
|
||||
.catch((error) => ({ stderr: error.message, stdout: "" }))
|
||||
if (/musl/.test(result.stderr) || /musl/.test(result.stdout)) {
|
||||
this._target = "alpine"
|
||||
} else {
|
||||
this._target = "linux"
|
||||
}
|
||||
}
|
||||
}
|
||||
return this._target
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure the argument is set. Display the value if it is.
|
||||
*/
|
||||
@ -256,114 +219,6 @@ class Builder {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Bundles the built code into a binary.
|
||||
*/
|
||||
private async binary(binaryName: string): Promise<void> {
|
||||
const prependCode = async (code: string, relativeFilePath: string): Promise<void> => {
|
||||
const filePath = path.join(this.buildPath, relativeFilePath)
|
||||
const content = await fs.readFile(filePath, "utf8")
|
||||
if (!content.startsWith(code)) {
|
||||
await fs.writeFile(filePath, code + content)
|
||||
}
|
||||
}
|
||||
|
||||
// Unpack binaries since we can't run them within the binary.
|
||||
const unpack = `
|
||||
if (global.NBIN_LOADED) {
|
||||
try {
|
||||
const fs = require("fs-extra")
|
||||
const rg = require("vscode-ripgrep")
|
||||
const path = require("path")
|
||||
const { logger, field } = require("@coder/logger")
|
||||
|
||||
const unpackExecutables = async (filePath, destination) => {
|
||||
logger.debug("unpacking executable", field("src", filePath), field("dest", destination))
|
||||
await fs.mkdirp(path.dirname(destination))
|
||||
if (filePath && !(await fs.pathExists(destination))) {
|
||||
await fs.writeFile(destination, await fs.readFile(filePath))
|
||||
await fs.chmod(destination, "755")
|
||||
}
|
||||
}
|
||||
|
||||
unpackExecutables(rg.binaryRgPath, rg.rgPath).catch((error) => console.warn(error))
|
||||
} catch (error) {
|
||||
console.warn(error)
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
// Enable finding files within the binary.
|
||||
const loader = `
|
||||
if (!global.NBIN_LOADED) {
|
||||
try {
|
||||
const nbin = require("nbin")
|
||||
nbin.shimNativeFs("${this.buildPath}")
|
||||
global.NBIN_LOADED = true
|
||||
require("@coder/logger").logger.debug("shimmed file system at ${this.buildPath}")
|
||||
const path = require("path")
|
||||
const rg = require("vscode-ripgrep")
|
||||
rg.binaryRgPath = rg.rgPath
|
||||
rg.rgPath = path.join(require("os").tmpdir(), "code-server/binaries", path.basename(rg.binaryRgPath))
|
||||
} catch (error) {
|
||||
// Most likely not in the binary.
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
await this.task("Prepending nbin loader", () => {
|
||||
return Promise.all([
|
||||
prependCode(loader, "out/node/entry.js"),
|
||||
prependCode(loader, "lib/vscode/out/vs/server/entry.js"),
|
||||
prependCode(loader + unpack, "lib/vscode/out/vs/server/fork.js"),
|
||||
prependCode(loader, "lib/vscode/out/bootstrap-fork.js"),
|
||||
prependCode(loader, "lib/vscode/extensions/node_modules/typescript/lib/tsserver.js"),
|
||||
])
|
||||
})
|
||||
|
||||
const bin = new Binary({
|
||||
mainFile: path.join(this.buildPath, "out/node/entry.js"),
|
||||
target: await this.target(),
|
||||
})
|
||||
|
||||
bin.writeFiles(path.join(this.buildPath, "**"))
|
||||
|
||||
await fs.mkdirp(this.binariesPath)
|
||||
|
||||
const binaryPath = path.join(this.binariesPath, binaryName)
|
||||
await fs.writeFile(binaryPath, await bin.build())
|
||||
await fs.chmod(binaryPath, "755")
|
||||
|
||||
this.log(`binary: ${binaryPath}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* Package the binary into a release archive.
|
||||
*/
|
||||
private async package(binaryName: string): Promise<void> {
|
||||
const releasePath = path.join(this.rootPath, "release")
|
||||
const archivePath = path.join(releasePath, binaryName)
|
||||
|
||||
await fs.remove(archivePath)
|
||||
await fs.mkdirp(archivePath)
|
||||
|
||||
await fs.copyFile(path.join(this.binariesPath, binaryName), path.join(archivePath, "code-server"))
|
||||
await fs.copyFile(path.join(this.rootPath, "README.md"), path.join(archivePath, "README.md"))
|
||||
await fs.copyFile(path.join(this.vscodeSourcePath, "LICENSE.txt"), path.join(archivePath, "LICENSE.txt"))
|
||||
await fs.copyFile(
|
||||
path.join(this.vscodeSourcePath, "ThirdPartyNotices.txt"),
|
||||
path.join(archivePath, "ThirdPartyNotices.txt"),
|
||||
)
|
||||
|
||||
if ((await this.target()) === "darwin") {
|
||||
await util.promisify(cp.exec)(`zip -r "${binaryName}.zip" "${binaryName}"`, { cwd: releasePath })
|
||||
this.log(`archive: ${archivePath}.zip`)
|
||||
} else {
|
||||
await util.promisify(cp.exec)(`tar -czf "${binaryName}.tar.gz" "${binaryName}"`, { cwd: releasePath })
|
||||
this.log(`archive: ${archivePath}.tar.gz`)
|
||||
}
|
||||
}
|
||||
|
||||
private async watch(): Promise<void> {
|
||||
let server: cp.ChildProcess | undefined
|
||||
const restartServer = (): void => {
|
||||
|
6
ci/code-server.sh
Executable file
6
ci/code-server.sh
Executable file
@ -0,0 +1,6 @@
|
||||
#!/usr/bin/env sh
|
||||
# code-server.sh -- Run code-server with the bundled Node binary.
|
||||
|
||||
cd "$(dirname "$0")" || exit 1
|
||||
|
||||
./node ./out/node/entry.js "$@"
|
@ -16,7 +16,7 @@ RUN apt-get install -y dumb-init sudo
|
||||
RUN apt-get install -y man procps vim nano htop ssh git
|
||||
|
||||
RUN adduser --gecos '' --disabled-password coder && \
|
||||
echo "coder ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers.d/nopasswd
|
||||
echo "coder ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers.d/nopasswd
|
||||
|
||||
RUN curl -SsL https://github.com/boxboat/fixuid/releases/download/v0.4/fixuid-0.4-linux-amd64.tar.gz | tar -C /usr/local/bin -xzf - && \
|
||||
chown root:root /usr/local/bin/fixuid && \
|
||||
@ -27,11 +27,12 @@ RUN curl -SsL https://github.com/boxboat/fixuid/releases/download/v0.4/fixuid-0.
|
||||
RUN rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY release/code-server*.tar.gz /tmp
|
||||
RUN cd /tmp && tar -xzf code-server*.tar.gz && \
|
||||
cp code-server*/code-server /usr/local/bin/code-server
|
||||
RUN rm -rf /tmp/*
|
||||
RUN cd /tmp && tar -xzf code-server*.tar.gz && rm code-server*.tar.gz && \
|
||||
mv code-server* /usr/local/lib/code-server && \
|
||||
sed 's/\$0/\/usr\/local\/lib\/code-server\/code-server/g' /usr/local/lib/code-server/code-server > /usr/local/bin/code-server && \
|
||||
chmod +x /usr/local/bin/code-server
|
||||
|
||||
EXPOSE 8080
|
||||
USER coder
|
||||
WORKDIR /home/coder
|
||||
ENTRYPOINT ["dumb-init", "fixuid", "-q", "code-server", "--host", "0.0.0.0", "."]
|
||||
ENTRYPOINT ["dumb-init", "fixuid", "-q", "/usr/local/bin/code-server", "--host", "0.0.0.0", "."]
|
||||
|
@ -3,52 +3,72 @@
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
function package() {
|
||||
local target
|
||||
target=$(uname | tr '[:upper:]' '[:lower:]')
|
||||
if [[ $target == "linux" ]]; then
|
||||
# Alpine's ldd doesn't have a version flag but if you use an invalid flag
|
||||
# (like --version) it outputs the version to stderr and exits with 1.
|
||||
local ldd_output
|
||||
ldd_output=$(ldd --version 2>&1 || true)
|
||||
if echo "$ldd_output" | grep -iq musl; then
|
||||
target="alpine"
|
||||
fi
|
||||
fi
|
||||
|
||||
local arch
|
||||
arch="$(uname -m)"
|
||||
|
||||
echo -n "Creating release..."
|
||||
|
||||
cp "$(command -v node)" ./build
|
||||
cp README.md ./build
|
||||
cp LICENSE.txt ./build
|
||||
cp ./lib/vscode/ThirdPartyNotices.txt ./build
|
||||
cp ./ci/code-server.sh ./build/code-server
|
||||
|
||||
local archive_name="code-server-$VERSION-$target-$arch"
|
||||
mkdir -p ./release
|
||||
|
||||
local ext
|
||||
if [[ $target == "linux" ]]; then
|
||||
ext=".tar.gz"
|
||||
tar -czf "release/$archive_name$ext" --transform "s/^\.\/build/$archive_name/" ./build
|
||||
else
|
||||
mv ./build "./$archive_name"
|
||||
ext=".zip"
|
||||
zip -r "release/$archive_name$ext" ./code-server
|
||||
mv "./$archive_name" ./build
|
||||
fi
|
||||
|
||||
echo "done (release/$archive_name)"
|
||||
|
||||
mkdir -p "./release-upload/$VERSION"
|
||||
cp "./release/$archive_name$ext" "./release-upload/$VERSION/$target-$arch.tar.gz"
|
||||
mkdir -p "./release-upload/latest"
|
||||
cp "./release/$archive_name$ext" "./release-upload/latest/$target-$arch.tar.gz"
|
||||
}
|
||||
|
||||
# This script assumes that yarn has already ran.
|
||||
function build() {
|
||||
# Always minify and package on CI.
|
||||
if [[ ${CI:-} ]]; then
|
||||
export MINIFY="true"
|
||||
fi
|
||||
|
||||
yarn build
|
||||
}
|
||||
|
||||
function main() {
|
||||
cd "$(dirname "${0}")/.."
|
||||
source ./ci/lib.sh
|
||||
|
||||
set_version
|
||||
|
||||
# Always minify and package on CI since that's when releases are pushed.
|
||||
build
|
||||
|
||||
if [[ ${CI:-} ]]; then
|
||||
export MINIFY="true"
|
||||
export PACKAGE="true"
|
||||
fi
|
||||
|
||||
yarn build
|
||||
yarn binary
|
||||
if [[ -n ${PACKAGE:-} ]]; then
|
||||
yarn package
|
||||
fi
|
||||
|
||||
cd binaries
|
||||
|
||||
if [[ -n ${STRIP_BIN_TARGET:-} ]]; then
|
||||
# In this case provide plainly named binaries.
|
||||
for binary in code-server*; do
|
||||
echo "Moving $binary to code-server"
|
||||
mv "$binary" code-server
|
||||
done
|
||||
elif [[ -n ${DRONE_TAG:-} || -n ${TRAVIS_TAG:-} ]]; then
|
||||
# Prepare directory for uploading binaries on release.
|
||||
for binary in code-server*; do
|
||||
mkdir -p "../binary-upload"
|
||||
|
||||
local prefix="code-server-$VERSION-"
|
||||
local target="${binary#$prefix}"
|
||||
if [[ $target == "linux-x86_64" ]]; then
|
||||
echo "Copying $binary to ../binary-upload/latest-linux"
|
||||
cp "$binary" "../binary-upload/latest-linux"
|
||||
fi
|
||||
|
||||
local gcp_dir
|
||||
gcp_dir="../binary-upload/releases/$VERSION/$target"
|
||||
mkdir -p "$gcp_dir"
|
||||
|
||||
echo "Copying $binary to $gcp_dir/code-server"
|
||||
cp "$binary" "$gcp_dir/code-server"
|
||||
done
|
||||
package
|
||||
fi
|
||||
}
|
||||
|
||||
|
@ -179,22 +179,6 @@ index 5a631e0b39..4114bd9287 100644
|
||||
} else if (typeof process === 'object') {
|
||||
_isWindows = (process.platform === 'win32');
|
||||
_isMacintosh = (process.platform === 'darwin');
|
||||
diff --git a/src/vs/base/common/processes.ts b/src/vs/base/common/processes.ts
|
||||
index c52f7b3774..967943d27b 100644
|
||||
--- a/src/vs/base/common/processes.ts
|
||||
+++ b/src/vs/base/common/processes.ts
|
||||
@@ -110,7 +110,10 @@ export function sanitizeProcessEnvironment(env: IProcessEnvironment, ...preserve
|
||||
/^ELECTRON_.+$/,
|
||||
/^GOOGLE_API_KEY$/,
|
||||
/^VSCODE_.+$/,
|
||||
- /^SNAP(|_.*)$/
|
||||
+ /^SNAP(|_.*)$/,
|
||||
+ // NOTE@coder: Add our variables.
|
||||
+ /^NBIN_BYPASS$/,
|
||||
+ /^LAUNCH_VSCODE$/
|
||||
];
|
||||
const envKeys = Object.keys(env);
|
||||
envKeys
|
||||
diff --git a/src/vs/base/node/languagePacks.js b/src/vs/base/node/languagePacks.js
|
||||
index 2c64061da7..c0ef8faedd 100644
|
||||
--- a/src/vs/base/node/languagePacks.js
|
||||
|
Reference in New Issue
Block a user