Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Always install latest version - and also some strcutured logging #35

Merged
merged 2 commits into from
Nov 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,341 changes: 869 additions & 472 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@
"webpack-cli": "^4.9.1"
},
"dependencies": {
"@octokit/rest": "^21.0.2",
"extract-zip": "^2.0.1",
"got": "^11.8.3",
"mkdirp": "^1.0.4",
Expand Down
12 changes: 6 additions & 6 deletions src/commands/deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import * as spin from '../spin';
import { shell } from '../utils/shell';
import { isErr } from '../errorable';
import { longRunningProcess } from '../longrunning';
import * as output from '../output';
import * as log from '../logger';
import { promptLogin } from '../fermyon/environment-ui';

export async function deploy() {
Expand Down Expand Up @@ -38,15 +38,15 @@ export async function deploy() {
}

if (isErr(deployResult)) {
output.appendLine(`Spin ${description} failed. Details:`);
output.appendLine(deployResult.message);
output.appendLine('');
log.error(deploy.name, `Spin ${description} failed. Details:`);
log.error(deploy.name, deployResult.message);
log.error(deploy.name, '');
await vscode.window.showErrorMessage(`Spin ${description} failed. Error: ${deployResult.message}`);
return;
}

output.appendLine(deployResult.value);
output.show();
log.info(deploy.name, deployResult.value);
log.show();
const message = `Spin ${description} complete. See output pane for application URL.`;
await vscode.window.showInformationMessage(message);
}
58 changes: 43 additions & 15 deletions src/installer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,35 +10,45 @@ import * as config from './config';
import { Errorable, err, ok, isErr, isOk } from "./errorable";
import * as layout from './layout';
import { longRunning } from './longrunning';
import * as log from './logger';
import { Octokit } from "@octokit/rest";

const SPIN_VERSION = "0.8.0";
const SPIN_DONWLOAD_URL_TEMPLATE = `https://github.com/fermyon/spin/releases/download/v${SPIN_VERSION}/spin-v${SPIN_VERSION}-{{subst:os}}-{{subst:arch}}.{{subst:fmt}}`;
// Fallback version is used if the call to getLatestReleases() fails
const SPIN_VERSION_FALLBACK = "3.0.0";
const SPIN_TOOL_NAME = "spin";
const SPIN_BIN_NAME = "spin";

export async function ensureSpinInstalled(): Promise<Errorable<string>> {
const spinVersion = await getLatestReleases();
log.info(ensureSpinInstalled.name, `Checking if Spin ${spinVersion} is installed`);

const customPath = config.customPath();
if (customPath) {
log.info(ensureSpinInstalled.name, `Using the following custom path from configuration: ${customPath}`);
return ok(customPath);
}

const toolFile = installLocation(SPIN_TOOL_NAME, SPIN_BIN_NAME);
if (!fs.existsSync(toolFile) || !isInstallCurrent()) {
const downloadResult = await longRunning(`Downloading Spin ${SPIN_VERSION}...`, () =>
downloadSpinTo(toolFile)
log.info(ensureSpinInstalled.name, `Checking for Spin at: ${toolFile}`);
if (!fs.existsSync(toolFile) || !isInstallCurrent(spinVersion)) {
log.info(ensureSpinInstalled.name, `Didn't find Spin locally.`);
const downloadResult = await longRunning(`Downloading Spin ${spinVersion}...`, () =>
downloadSpinTo(toolFile, spinVersion)
);
if (isErr(downloadResult)) {
log.error(ensureSpinInstalled.name, `Error installing Spin: ${JSON.stringify(downloadResult)}`);
return downloadResult;
}
}
markInstallCurrent();
}
markInstallCurrent(spinVersion);
log.info(ensureSpinInstalled.name, `Spin installed at: ${toolFile}`);
return ok(toolFile);
}

async function downloadSpinTo(toolFile: string): Promise<Errorable<null>> {
async function downloadSpinTo(toolFile: string, spinVersion: string): Promise<Errorable<null>> {
const toolDir = path.dirname(toolFile);

const sourceUrl = downloadSource();
const sourceUrl = downloadSource(spinVersion);
if (isErr(sourceUrl)) {
return sourceUrl;
}
Expand All @@ -56,7 +66,7 @@ async function downloadSpinTo(toolFile: string): Promise<Errorable<null>> {
return unarchiveResult;
}

function downloadSource(): Errorable<string> {
function downloadSource(spinVersion: string): Errorable<string> {
const osId = os();
const archId = arch();
const fmtId = fmt();
Expand All @@ -65,7 +75,8 @@ function downloadSource(): Errorable<string> {
return err("Unsupported operating system or processor architecture");
}

const url = SPIN_DONWLOAD_URL_TEMPLATE.replace("{{subst:os}}", osId).replace("{{subst:arch}}", archId).replace("{{subst:fmt}}", fmtId);
const url = `https://github.com/fermyon/spin/releases/download/${spinVersion}/spin-${spinVersion}-${osId}-${archId}.${fmtId}`;
log.info(downloadSource.name, `"Download URI: ${url}`);
return ok(url);
}

Expand All @@ -79,18 +90,18 @@ export function installLocation(tool: string, bin: string): string {
return toolFile;
}

function isInstallCurrent(): boolean {
function isInstallCurrent(spinVersion: string): boolean {
const versionFile = installedVersionLocation(SPIN_TOOL_NAME);
if (!fs.existsSync(versionFile)) {
return false;
}
const text = fs.readFileSync(versionFile, { encoding: 'utf-8' });
return text.trim() === SPIN_VERSION;
return text.trim() === spinVersion;
}

function markInstallCurrent() {
function markInstallCurrent(spinVersion: string) {
const versionFile = installedVersionLocation(SPIN_TOOL_NAME);
fs.writeFileSync(versionFile, SPIN_VERSION, { encoding: 'utf-8' });
fs.writeFileSync(versionFile, spinVersion, { encoding: 'utf-8' });
}

function installedVersionLocation(tool: string): string {
Expand Down Expand Up @@ -185,3 +196,20 @@ async function unzip(sourceFile: string, destinationFolder: string): Promise<Err
return err("zip extract failed");
}
}

async function getLatestReleases(): Promise<string> {
const octokit = new Octokit();
const { data: release } = await octokit.rest.repos.getLatestRelease({
owner: "fermyon",
repo: "spin",
headers: {
'X-GitHub-Api-Version': '2022-11-28'
}
});

if (release.name === null) {
return SPIN_VERSION_FALLBACK;
} else {
return release.name;
}
}
66 changes: 66 additions & 0 deletions src/logger.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import * as vscode from 'vscode';

const OUTPUT_CHANNEL = vscode.window.createOutputChannel("Spin", );

let shownInstallErrorToast = false;

enum logLevel {
Info = "Info",
Warning = "Warning",
Error = "Error",
}

interface logMessage {
level: logLevel,
function: string,
message: string,
}

export function info(caller: string, message: string) {
const log: logMessage = {
level:logLevel.Info,
function: caller,
message: message
};
OUTPUT_CHANNEL.appendLine(formatLog(log));
}

export function warning(caller: string, message: string) {
const log: logMessage = {
level:logLevel.Warning,
function: caller,
message: message
};
OUTPUT_CHANNEL.appendLine(formatLog(log));
}

export function error(caller: string, message: string) {
const log: logMessage = {
level:logLevel.Error,
function: caller,
message: message
};
OUTPUT_CHANNEL.appendLine(formatLog(log));
}

export function logMessage(logMessage: logMessage) {
OUTPUT_CHANNEL.appendLine(formatLog(logMessage));
}

export function warnInstallNotEnsured(message: string, always?: 'always' | 'if-not-shown') {
if (!shownInstallErrorToast || always === 'always') {
shownInstallErrorToast = true;
vscode.window.showWarningMessage(message);
} else {
warning(warnInstallNotEnsured.name, message);
}
}

export function show(preserveFocus?: boolean) {
OUTPUT_CHANNEL.show(preserveFocus);
}

function formatLog(log: logMessage): string {
const date = new Date().toISOString();
return `${date} [${log.level}] ${log.message}`;
}
22 changes: 0 additions & 22 deletions src/output.ts

This file was deleted.

6 changes: 3 additions & 3 deletions src/spin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { CancellationToken } from 'vscode';
import { Errorable, isErr, ok } from './errorable';
import { ensureSpinInstalled } from './installer';
import * as shell from './utils/shell';
import * as output from './output';
import * as log from './logger';

async function invokeObj<T>(sh: shell.Shell, command: string, args: string, opts: shell.ExecOpts, fn: (stdout: string) => T): Promise<Errorable<T>> {
const binOpt = await ensureSpinInstalled();
Expand All @@ -12,7 +12,7 @@ async function invokeObj<T>(sh: shell.Shell, command: string, args: string, opts
const bin = binOpt.value;

const cmd = `${bin} ${command} ${args}`;
output.appendLine(`$ ${cmd}`);
log.info(invokeObj.name, `$ ${cmd}`);
return await sh.execObj<T>(
cmd,
`spin ${command}`,
Expand All @@ -23,7 +23,7 @@ async function invokeObj<T>(sh: shell.Shell, command: string, args: string, opts

function andLog<T>(fn: (s: string) => T): (s: string) => T {
return (s: string) => {
output.appendLine(s);
log.info(andLog.name, s);
return fn(s);
};
}
Expand Down
2 changes: 1 addition & 1 deletion src/tasks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as vscode from 'vscode';
import { isOk } from './errorable';

import * as installer from './installer';
import { warnInstallNotEnsured } from './output';
import { warnInstallNotEnsured } from './logger';
import { cantHappen } from './utils/never';

const TASK_SOURCE = "spin";
Expand Down
Loading