mirror of
https://github.com/Strum355/mcshader-lsp.git
synced 2025-08-04 00:49:17 +00:00
extension release bootstrapping and updating
This commit is contained in:
parent
8fab7bd0f2
commit
4573dd86fd
8 changed files with 209 additions and 49 deletions
|
@ -1,17 +1,5 @@
|
|||
{
|
||||
"name": "vscode-mc-shader-client",
|
||||
"description": "A Visual Studio Code extension for linting/etc Minecraft GLSL Shaders",
|
||||
"version": "0.0.1",
|
||||
"publisher": "Noah Santschi-Cooney (Strum355)",
|
||||
"author": "Noah Santschi-Cooney (Strum355)",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Strum355/vscode-mc-shader"
|
||||
},
|
||||
"engines": {
|
||||
"vscode": "^1.43.0"
|
||||
},
|
||||
"scripts": {
|
||||
"compile": "tsc -p ./"
|
||||
},
|
||||
|
|
|
@ -1,13 +1,30 @@
|
|||
import { mkdirSync, promises as fs } from 'fs'
|
||||
import * as vscode from 'vscode'
|
||||
import * as lsp from 'vscode-languageclient'
|
||||
import * as commands from './commands'
|
||||
import { log } from './log'
|
||||
import { LanguageClient } from './lspClient'
|
||||
import { download, getReleaseInfo } from './net'
|
||||
import { PersistentState } from './persistent_state'
|
||||
import * as path from 'path'
|
||||
|
||||
const platforms: { [key: string]: string } = {
|
||||
'x64 win32': 'x86_64-pc-windows-gnu',
|
||||
'x64 linux': 'x86_64-unknown-linux-gnu',
|
||||
'x64 darwin': 'x86_64-apple-darwin',
|
||||
}
|
||||
|
||||
export class Extension {
|
||||
private statusBarItem: vscode.StatusBarItem | null = null
|
||||
private extensionContext: vscode.ExtensionContext | null = null
|
||||
private client: lsp.LanguageClient
|
||||
private state: PersistentState
|
||||
|
||||
readonly extensionID = 'strum355.vscode-mc-shader'
|
||||
|
||||
readonly package: {
|
||||
version: string
|
||||
} = vscode.extensions.getExtension(this.extensionID)!.packageJSON;
|
||||
|
||||
public get context(): vscode.ExtensionContext {
|
||||
return this.extensionContext
|
||||
|
@ -19,6 +36,9 @@ export class Extension {
|
|||
|
||||
public activate = async (context: vscode.ExtensionContext) => {
|
||||
this.extensionContext = context
|
||||
this.state = new PersistentState(context.globalState)
|
||||
|
||||
await this.bootstrap()
|
||||
|
||||
this.registerCommand('graphDot', commands.generateGraphDot)
|
||||
this.registerCommand('restart', commands.restartExtension)
|
||||
|
@ -54,6 +74,40 @@ export class Extension {
|
|||
public clearStatus = () => {
|
||||
this.statusBarItem?.dispose()
|
||||
}
|
||||
|
||||
private bootstrap = async () => {
|
||||
mkdirSync(this.extensionContext.globalStoragePath, { recursive: true })
|
||||
|
||||
const dest = path.join(this.extensionContext.globalStoragePath, 'mcshader-lsp' + (process.platform === 'win32' ? '.exe' : ''))
|
||||
const exists = await fs.stat(dest).then(() => true, () => false)
|
||||
if (!exists) await this.state.updateServerVersion(undefined)
|
||||
|
||||
this.state.updateServerVersion('borger')
|
||||
|
||||
const release = await getReleaseInfo(this.package.version)
|
||||
|
||||
const platform = platforms[`${process.arch} ${process.platform}`]
|
||||
if (platform === undefined) {
|
||||
vscode.window.showErrorMessage('Unfortunately we don\'t ship binaries for your platform yet.')
|
||||
return
|
||||
}
|
||||
|
||||
if (release.tag_name === this.state.serverVersion) return
|
||||
|
||||
const artifact = release.assets.find(artifact => artifact.name === `mcshader-lsp-${platform}`)
|
||||
|
||||
const userResponse = await vscode.window.showInformationMessage(
|
||||
this.state.serverVersion == undefined ?
|
||||
`Language server version ${this.package.version} is not installed.` :
|
||||
`An update is available. Upgrade from ${this.state.serverVersion} to ${release.tag_name}?`,
|
||||
'Download now'
|
||||
)
|
||||
if (userResponse !== 'Download now') return
|
||||
|
||||
await download(artifact.browser_download_url, dest)
|
||||
|
||||
this.state.updateServerVersion(release.tag_name)
|
||||
}
|
||||
}
|
||||
|
||||
export const activate = new Extension().activate
|
|
@ -10,13 +10,15 @@ export class LanguageClient extends lsp.LanguageClient {
|
|||
|
||||
constructor(ext: Extension) {
|
||||
super('vscode-mc-shader', 'VSCode MC Shader', {
|
||||
command: ext.context.asAbsolutePath(path.join('server', 'target', 'debug', 'vscode-mc-shader')),
|
||||
command: process.env['MCSHADER_DEBUG'] ?
|
||||
ext.context.asAbsolutePath(path.join('server', 'target', 'debug', 'vscode-mc-shader')) :
|
||||
path.join(ext.context.globalStoragePath, 'mcshader-lsp')
|
||||
}, {
|
||||
documentSelector: [{scheme: 'file', language: 'glsl'}],
|
||||
outputChannel: lspOutputChannel,
|
||||
synchronize: {
|
||||
configurationSection: 'mcglsl',
|
||||
fileEvents: workspace.createFileSystemWatcher('**/*.{fsh,gsh,vsh,glsl}')
|
||||
fileEvents: workspace.createFileSystemWatcher('**/*.{fsh,gsh,vsh,glsl,inc}')
|
||||
},
|
||||
})
|
||||
this.extension = ext
|
||||
|
|
101
client/src/net.ts
Normal file
101
client/src/net.ts
Normal file
|
@ -0,0 +1,101 @@
|
|||
import { log } from './log'
|
||||
import fetch from 'node-fetch'
|
||||
import * as vscode from 'vscode'
|
||||
import * as stream from 'stream'
|
||||
import * as fs from 'fs'
|
||||
import * as util from 'util'
|
||||
|
||||
const pipeline = util.promisify(stream.pipeline)
|
||||
|
||||
interface GithubRelease {
|
||||
tag_name: string;
|
||||
assets: Array<{
|
||||
name: string;
|
||||
browser_download_url: string;
|
||||
}>;
|
||||
}
|
||||
|
||||
export async function getReleaseInfo(releaseTag: string): Promise<GithubRelease> {
|
||||
const response = await fetch(`https://api.github.com/repos/strum355/mcshader-lsp/releases/tags/${releaseTag}`, {
|
||||
headers: {Accept: 'application/vnd.github.v3+json'}
|
||||
})
|
||||
|
||||
const isRelease = (obj: unknown): obj is GithubRelease => {
|
||||
return obj != null && typeof obj === 'object'
|
||||
&& typeof (obj as GithubRelease).tag_name === 'string'
|
||||
&& Array.isArray((obj as GithubRelease).assets)
|
||||
&& (obj as GithubRelease).assets.every((a) => typeof a.name === 'string' && typeof a.browser_download_url === 'string')
|
||||
}
|
||||
|
||||
const json = await response.json()
|
||||
if(!isRelease(json)) {
|
||||
throw new TypeError('Received malformed request from Github Release API')
|
||||
}
|
||||
return json
|
||||
}
|
||||
|
||||
export async function download(url: string, downloadDest: string) {
|
||||
await vscode.window.withProgress(
|
||||
{
|
||||
location: vscode.ProgressLocation.Notification,
|
||||
cancellable: false,
|
||||
title: `Downloading ${url}`
|
||||
},
|
||||
async (progress, _) => {
|
||||
let lastPercentage = 0
|
||||
await downloadFile(url, downloadDest, (readBytes, totalBytes) => {
|
||||
const newPercentage = Math.round((readBytes / totalBytes) * 100)
|
||||
if (newPercentage !== lastPercentage) {
|
||||
progress.report({
|
||||
message: `${newPercentage.toFixed(0)}%`,
|
||||
increment: newPercentage - lastPercentage
|
||||
})
|
||||
|
||||
lastPercentage = newPercentage
|
||||
}
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
async function downloadFile(
|
||||
url: string,
|
||||
destFilePath: fs.PathLike,
|
||||
onProgress: (readBytes: number, totalBytes: number) => void
|
||||
): Promise<void> {
|
||||
const res = await fetch(url)
|
||||
if (!res.ok) {
|
||||
log.error(res.status, 'while downloading file from', url)
|
||||
log.error({ body: await res.text(), headers: res.headers })
|
||||
throw new Error(`Got response ${res.status} when trying to download ${url}.`)
|
||||
}
|
||||
|
||||
const totalBytes = Number(res.headers.get('content-length'))
|
||||
|
||||
log.debug('downloading file of', totalBytes, 'bytes size from', url, 'to', destFilePath)
|
||||
|
||||
let readBytes = 0
|
||||
res.body.on('data', (chunk: Buffer) => {
|
||||
readBytes += chunk.length
|
||||
onProgress(readBytes, totalBytes)
|
||||
})
|
||||
|
||||
const destFileStream = fs.createWriteStream(destFilePath, { mode: 0o755 })
|
||||
|
||||
await pipeline(res.body, destFileStream)
|
||||
|
||||
// Don't apply the workaround in fixed versions of nodejs, since the process
|
||||
// freezes on them, the process waits for no-longer emitted `close` event.
|
||||
// The fix was applied in commit 7eed9d6bcc in v13.11.0
|
||||
// See the nodejs changelog:
|
||||
// https://github.com/nodejs/node/blob/master/doc/changelogs/CHANGELOG_V13.md
|
||||
const [, major, minor] = /v(\d+)\.(\d+)\.(\d+)/.exec(process.version)!
|
||||
if (+major > 13 || (+major === 13 && +minor >= 11)) return
|
||||
|
||||
await new Promise<void>(resolve => {
|
||||
destFileStream.on('close', resolve)
|
||||
destFileStream.destroy()
|
||||
// This workaround is awaiting to be removed when vscode moves to newer nodejs version:
|
||||
// https://github.com/rust-analyzer/rust-analyzer/issues/3167
|
||||
})
|
||||
}
|
16
client/src/persistent_state.ts
Normal file
16
client/src/persistent_state.ts
Normal file
|
@ -0,0 +1,16 @@
|
|||
import { Memento } from 'vscode'
|
||||
import { log } from './log'
|
||||
|
||||
export class PersistentState {
|
||||
constructor(private readonly state: Memento) {
|
||||
const { serverVersion } = this
|
||||
log.info('working with state', { serverVersion })
|
||||
}
|
||||
|
||||
get serverVersion(): string | undefined {
|
||||
return this.state.get('serverVersion')
|
||||
}
|
||||
async updateServerVersion(value: string | undefined) {
|
||||
await this.state.update('serverVersion', value)
|
||||
}
|
||||
}
|
11
package.json
11
package.json
|
@ -21,8 +21,7 @@
|
|||
"onLanguage:glsl",
|
||||
"workspaceContains:**/*.fsh",
|
||||
"workspaceContains:**/*.vsh",
|
||||
"workspaceContains:**/*.gsh",
|
||||
"workspaceContains:**/*.glsl"
|
||||
"workspaceContains:**/*.gsh"
|
||||
],
|
||||
"extensionDependencies": [
|
||||
"slevesque.shader"
|
||||
|
@ -31,17 +30,17 @@
|
|||
"contributes": {
|
||||
"commands": [
|
||||
{
|
||||
"command": "mcshader.graphDot",
|
||||
"command": "mcglsl.graphDot",
|
||||
"title": "Generate Graphviz DOT dependency graph",
|
||||
"category": "Minecraft Shader"
|
||||
},
|
||||
{
|
||||
"command": "mcshader.restart",
|
||||
"command": "mcglsl.restart",
|
||||
"title": "Restart Language Server",
|
||||
"category": "Minecraft Shader"
|
||||
},
|
||||
{
|
||||
"command": "mcshader.virtualMerge",
|
||||
"command": "mcglsl.virtualMerge",
|
||||
"title": "Show flattened file",
|
||||
"category": "Minecraft Shader"
|
||||
}
|
||||
|
@ -69,7 +68,7 @@
|
|||
"vscode:prepublish": "npm run compile && cd client && rollup -c",
|
||||
"compile": "tsc -b",
|
||||
"package": "vsce package -o vscode-mc-shader.vsix",
|
||||
"watch": "concurrently \"tsc -b -w\" \"cd server && cargo watch -x build\"",
|
||||
"watch": "concurrently \"tsc -b -w\" \"cd server && MCSHADER_DEBUG=true cargo watch -x build\"",
|
||||
"postinstall": "cd client && npm install",
|
||||
"lint": "eslint 'client/**/*.ts' --max-warnings 1",
|
||||
"fix": "eslint 'client/**/*.ts' --fix"
|
||||
|
|
56
server/Cargo.lock
generated
56
server/Cargo.lock
generated
|
@ -699,6 +699,34 @@ version = "2.0.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00"
|
||||
|
||||
[[package]]
|
||||
name = "mcshader-lsp"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bit-set",
|
||||
"chan",
|
||||
"ctor",
|
||||
"fs_extra",
|
||||
"gl",
|
||||
"glutin",
|
||||
"hamcrest2",
|
||||
"lazy_static",
|
||||
"mockall",
|
||||
"path-slash",
|
||||
"percent-encoding",
|
||||
"petgraph",
|
||||
"pretty_assertions",
|
||||
"regex",
|
||||
"rust_lsp",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tempdir",
|
||||
"thiserror",
|
||||
"url",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.3.4"
|
||||
|
@ -1505,34 +1533,6 @@ version = "0.9.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
|
||||
|
||||
[[package]]
|
||||
name = "vscode-mc-shader"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bit-set",
|
||||
"chan",
|
||||
"ctor",
|
||||
"fs_extra",
|
||||
"gl",
|
||||
"glutin",
|
||||
"hamcrest2",
|
||||
"lazy_static",
|
||||
"mockall",
|
||||
"path-slash",
|
||||
"percent-encoding",
|
||||
"petgraph",
|
||||
"pretty_assertions",
|
||||
"regex",
|
||||
"rust_lsp",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tempdir",
|
||||
"thiserror",
|
||||
"url",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.3.1"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
[package]
|
||||
name = "vscode-mc-shader"
|
||||
name = "mcshader-lsp"
|
||||
version = "0.1.0"
|
||||
authors = ["Noah Santschi-Cooney <noah@santschi-cooney.ch>"]
|
||||
edition = "2018"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue