Skip to content

Commit

Permalink
Deploy new nightly language servers
Browse files Browse the repository at this point in the history
  • Loading branch information
udoprog committed Jul 22, 2024
1 parent 037c3e9 commit fa4ceaf
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 91 deletions.
114 changes: 68 additions & 46 deletions editors/code/src/ctx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,19 @@ interface LastClientError {
export class Ctx {
readonly context: vscode.ExtensionContext;
readonly config: Config;
readonly state: PersistentState;
readonly state: PersistentState;
readonly statusBar: vscode.StatusBarItem;

// Stored initialization error. Cleared when reloaded.
lastClientError: LastClientError | null;
client: lc.LanguageClient | null;
commands: {[key:string]: lc.Disposable};
commands: { [key: string]: lc.Disposable };
stopped: boolean;

constructor(context: vscode.ExtensionContext) {
this.context = context;
this.config = new Config(context);
this.state = new PersistentState(context.globalState);
this.state = new PersistentState(context.globalState);
this.statusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left);
this.lastClientError = null;
this.client = null;
Expand Down Expand Up @@ -75,7 +75,7 @@ export class Ctx {
}

this.setupStatusBar();
}
}

command(name: string, callback: (...args: any[]) => any) {
if (!this.commands[name]) {
Expand Down Expand Up @@ -152,11 +152,11 @@ export class Ctx {
let [code, out, err]: [number | null, string, string] = await new Promise((resolve, _) => {
let stdout = "";
let stderr = "";

cargoVersion.stdout.on("data", (chunk) => {
stdout += chunk;
});

cargoVersion.stderr.on("data", (chunk) => {
stderr += chunk;
});
Expand Down Expand Up @@ -211,7 +211,7 @@ export class Ctx {
child.stderr.setEncoding('utf8');
child.stdout.setEncoding('utf8');
let out = rl.createInterface(child.stdout, child.stdin);

this.statusBar.text = `rune: cargo build -p ${name}`;
this.statusBar.tooltip = `rune: building package ${name}, to use as rune language server`;
this.statusBar.backgroundColor = new vscode.ThemeColor('statusBarItem.warningBackground');
Expand Down Expand Up @@ -273,10 +273,10 @@ export class Ctx {

if (explicitPath) {
if (explicitPath.startsWith("~/")) {
return { kind: "languageserver", path: os.homedir() + explicitPath.slice("~".length) };
return { kind: "cli", path: os.homedir() + explicitPath.slice("~".length) };
}

return { kind: "languageserver", path: explicitPath };
return { kind: "cli", path: explicitPath };
}

const cargoPackage = this.config.serverCargoPackage;
Expand All @@ -297,24 +297,25 @@ export class Ctx {
return null;
}

return { kind: "languageserver", path };
return { kind: "cli", path };
}

async downloadServer(): Promise<string | null> {
// unknown platform => no download available
const platform = detectPlatform();
const platformArch = detectPlatform();

if (!platform) {
if (!platformArch) {
return null;
}


const [platform, arch] = platformArch;

// platform specific binary name / path
const ext = platform === "windows" ? ".exe" : "";
const bin = `rune-languageserver-${platform}${ext}`;
const serverDir = vscode.Uri.joinPath(this.context.extensionUri, "server");
const dest = vscode.Uri.joinPath(serverDir, bin);
const destExists = await uriExists(dest);

// Only check for updates once every two hours.
let now = (new Date()).getTime() / 1000;
let lastCheck = this.state.lastCheck;
Expand All @@ -324,19 +325,27 @@ export class Ctx {
if (destExists && !timedOut) {
return dest.fsPath;
}

// fetch new release info
await this.state.updateLastCheck(now);

const release = await fetchRelease("nightly", null);
const artifact = release.assets.find(artifact => artifact.name === `rune-languageserver-${platform}.gz`);
assert(!!artifact, `Bad release: ${JSON.stringify(release)}`);


const platform_only = `rune-languageserver-${platform}.gz`;
const platform_arch = `rune-languageserver-${platform}-${arch}.gz`;

const artifact = release.assets.find(artifact => artifact.name === platform_only || artifact.name === platform_arch);

if (!artifact) {
log.warn(`Bad release: ${JSON.stringify(release)}`);
return null;
}

// no new release
if (destExists && this.state.releaseId === artifact.id) {
return dest.fsPath;
}

// ask for update
if (this.config.updatesAskBeforeDownload) {
const userResponse = await vscode.window.showInformationMessage(
Expand All @@ -347,20 +356,20 @@ export class Ctx {
return dest.fsPath;
}
}

// delete old server version
try {
await vscode.workspace.fs.delete(dest);
} catch (exception) {
log.debug("Delete of old server binary failed", exception);
}

// create server dir if missing
if (!await uriExists(serverDir)) {
log.debug(`Creating server dir: ${serverDir}`);
await vscode.workspace.fs.createDirectory(serverDir);
}

// download new version
await download({
url: artifact.browser_download_url,
Expand All @@ -372,11 +381,11 @@ export class Ctx {

await this.state.updateReleaseId(release.id);
return dest.fsPath;
}
}

serverPath(): string | null {
return process.env.__RUNE_LSP_SERVER_DEBUG ?? this.config.serverPath;
}
}

setupStatusBar() {
this.statusBar.text = "rune";
Expand Down Expand Up @@ -455,22 +464,35 @@ export class Ctx {
/**
* Function used to detect the platform we are on.
*/
function detectPlatform(): String | undefined {
if (process.arch === "x64") {
switch (process.platform) {
case "win32":
return "windows";
case "linux":
return "linux";
case "darwin":
return "macos";
}
}

vscode.window.showErrorMessage(
`Unfortunately we don't support your platform yet.
You can open an issue about that [here](https://github.com/rune-rs/rune/issues).
Please include (platform: ${process.platform}, arch: ${process.arch}).`
);
return undefined;
function detectPlatform(): [String, String] | undefined {
let platform = null;
let arch = null;

switch (process.platform) {
case "win32":
platform = "windows";
case "linux":
platform = "linux";
case "darwin":
platform = "macos";
}

switch (process.arch) {
case "x64":
arch = "x86_64";
case "arm64":
arch = "aarch64";
}

if (!platform || !arch) {
vscode.window.showErrorMessage(
`Unfortunately we don't support your platform yet.
You can open an issue about that [here](https://github.com/rune-rs/rune/issues).
Please include (platform: ${process.platform}, arch: ${process.arch}).`
);

return undefined;
}

return [platform, arch];
}
70 changes: 25 additions & 45 deletions tools/builder/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
//! A utility project for building and packaging Rune binaries.
use anyhow::{anyhow, bail, Context as _, Result};
use regex::Regex;
use std::env;
use std::env::consts;
use std::env::consts::{self, EXE_EXTENSION};
use std::ffi::OsStr;
use std::fmt;
use std::fs;
use std::io;
use std::path::{Path, PathBuf};
use std::process::Command;

use anyhow::{anyhow, bail, Context as _, Result};
use regex::Regex;

fn main() -> Result<()> {
let mut it = env::args();
it.next();
Expand Down Expand Up @@ -39,16 +40,7 @@ fn main() -> Result<()> {
Build::Version(version)
};

if cfg!(target_os = "windows") {
do_build(build, "windows", ".exe")?;
} else if cfg!(target_os = "linux") {
do_build(build, "linux", "")?;
} else if cfg!(target_os = "macos") {
do_build(build, "macos", "")?;
} else {
bail!("unsupported operating system: {}", consts::OS);
}

do_build(build)?;
Ok(())
}

Expand Down Expand Up @@ -197,10 +189,13 @@ where
Ok(())
}

fn create_gz(output: &Path, input: &Path) -> Result<()> {
fn create_gz(output: impl AsRef<Path>, input: impl AsRef<Path>) -> Result<()> {
use flate2::write::GzEncoder;
use flate2::Compression;

let output = output.as_ref();
let input = input.as_ref();

println!("building: {}", output.display());

let input = fs::File::open(input)?;
Expand All @@ -214,24 +209,7 @@ fn create_gz(output: &Path, input: &Path) -> Result<()> {
Ok(())
}

/// Copy an iterator of files to the given directory.
fn copy_files<I, S, N>(dest: &Path, sources: I) -> Result<()>
where
I: IntoIterator<Item = (S, N)>,
S: AsRef<Path>,
N: AsRef<str>,
{
for (s, name) in sources {
let s = s.as_ref();
let name = name.as_ref();

fs::copy(s, dest.join(name))?;
}

Ok(())
}

fn do_build(build: Build, suffix: &str, ext: &str) -> Result<()> {
fn do_build(build: Build) -> Result<()> {
let readme = PathBuf::from("README.md");
let release_dir = PathBuf::from("target").join("release");
let upload = Path::new("dist");
Expand All @@ -240,8 +218,8 @@ fn do_build(build: Build, suffix: &str, ext: &str) -> Result<()> {
fs::create_dir_all(upload).context("creating upload directory")?;
}

let rune = release_dir.join(format!("rune{}", ext));
let rune_languageserver = release_dir.join(format!("rune-languageserver{}", ext));
let rune = release_dir.join(format!("rune{EXE_EXTENSION}"));
let rune_languageserver = release_dir.join(format!("rune-languageserver{EXE_EXTENSION}"));

if !rune.is_file() {
println!("building: {}", rune.display());
Expand All @@ -259,22 +237,24 @@ fn do_build(build: Build, suffix: &str, ext: &str) -> Result<()> {
.context("building .zip")?;

if build.is_channel() {
// Create rune-languageserver gzip.
// Create rune-languageserver gzips.
create_gz(
&upload.join(format!("rune-languageserver-{}.gz", consts::OS)),
upload.join(format!(
"rune-languageserver-{os}-{arch}.gz",
os = consts::OS,
arch = consts::ARCH
)),
&rune_languageserver,
)
.context("building rune-languageserver .gz")?;

// Copy files to be uploaded.
copy_files(
upload,
vec![(
rune_languageserver,
format!("rune-languageserver-{}{}", suffix, ext),
)],
)
.context("copying raw files to upload")?;
if consts::ARCH == "x86_64" {
create_gz(
upload.join(format!("rune-languageserver-{os}.gz", os = consts::OS)),
&rune_languageserver,
)
.context("building rune-languageserver .gz")?;
}
}

Ok(())
Expand Down

0 comments on commit fa4ceaf

Please sign in to comment.