blob: 3764972f32c0a9822303b6652d0e4dd125707929 [file] [log] [blame]
// Copyright 2024 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import * as vscode from 'vscode';
import { window } from 'vscode';
import { Setup } from './extension';
import * as logger from './logger';
/**
* initialize fuchsia workflow interaction commands
*/
export function setUpWorkflowInteraction(ctx: vscode.ExtensionContext, setup: Setup) {
vscode.commands.registerCommand(
'fuchsia.fx.set',
async (product?: string, board?: string, packages?: string) => {
let status: Record<string, string> = {
'product': '',
'board': ''
};
await getStatus(status);
if (!product) {
await getList('list-products', status.product).then(async (list) => {
const selected = await window.showQuickPick(list, {
title: 'Select Product'
});
product = selected?.label;
});
}
if (!board) {
await getList('list-boards', status.board).then(async (list) => {
const selected = await window.showQuickPick(list, {
title: 'Select Board'
});
board = selected?.label;
});
}
if (!packages) {
packages = await window.showInputBox({
placeHolder: '(e.g. //examples //examples:tests)',
prompt: 'Enter packages to include in universe'
});
}
if (!product || !board) {
return;
}
let args = ['set', `${product?.trimEnd()}.${board?.trimEnd()}`];
if (packages) {
let packageList = packages?.split(' ');
packageList?.forEach(packageItem => {
args.push('--with');
args.push(packageItem);
});
}
void window.withProgress({
location: vscode.ProgressLocation.Notification,
title: 'fx set',
cancellable: true
}, async (progress, token) => {
let cmd = setup.fx.runAsync(
args,
() => void window.showInformationMessage('fx set completed'),
handleErr
);
token.onCancellationRequested(() => {
console.log('User canceled fx build operation');
cmd?.stop();
});
let exitCode = await cmd?.exitCode;
return exitCode === 0 ? Promise.resolve() : Promise.reject(exitCode);
});
/** Get current target configuration */
async function getStatus(status: Record<string, string>) {
const process = setup.fx.runJsonStreaming(['status', '--format=json'], (data: any) => {
status.product = data.buildInfo.items.products.value;
status.board = data.buildInfo.items.boards.value;
});
await process.exitCode;
}
/**
* get list of results from fx command
* @param args fx command to run
*/
async function getList(arg: string, last: string): Promise<vscode.QuickPickItem[]> {
let data: vscode.QuickPickItem[] = [];
let cmd = setup.fx.runAsync(
[arg],
(buffer: Buffer) => {
const msg = new TextDecoder().decode(buffer);
if (msg.includes('ERROR')) {
void window.showErrorMessage(msg);
} else {
let items = msg.split('\n').filter(item => item);
items.forEach((item) => {
if (item === last) {
data.unshift({
label: item,
description: '(Current)'
});
return;
}
data.push({
label: item
});
});
}
},
handleErr);
let exitCode = await cmd?.exitCode;
return exitCode === 0 ? Promise.resolve(data) : Promise.reject(exitCode);
}
// TODO(https://fxbug.dev/369839772): handle errs w/ task problem matcher
/**
* handle errs from callback
*/
function handleErr(buffer: Buffer) {
const msg = new TextDecoder().decode(buffer);
void window.showErrorMessage(msg);
}
}
);
vscode.commands.registerCommand('fuchsia.fx.build', () => {
void window.withProgress({
location: vscode.ProgressLocation.Notification,
title: 'fx build',
cancellable: true
}, async (progress, token) => {
let cmd = setup.fx.runAsync(['build'], handleData, handleData);
let percentage: number;
token.onCancellationRequested(() => {
console.log('User canceled fx build operation');
cmd?.stop();
});
/**
* callback to handle buffer from process
*/
function handleData(buffer: Buffer) {
const msg = new TextDecoder().decode(buffer);
// TODO(https://fxbug.dev/369839772): handle errs w/ task problem matcher
if (msg.includes('ERROR') || msg.includes('credentials')) {
void window.showErrorMessage(msg);
}
if (msg.includes('Locked')) {
void window.showWarningMessage(msg);
}
if (msg.includes('no work to do')) {
void window.showInformationMessage(msg);
}
// TODO(https://fxbug.dev/375234893): move msg to output window
if (msg.includes('%')) {
let match = msg.match(/\d+%/);
if (match) {
let lastPercent = percentage ?? 0;
percentage = parseInt(match[0]);
progress.report({ increment: percentage - lastPercent, message: `\n ${msg}` });
}
}
if (msg.includes('actions')) {
progress.report({ message: `${msg}` });
}
}
let exitCode = await cmd?.exitCode;
return exitCode === 0 ? Promise.resolve() : Promise.reject(exitCode);
});
});
vscode.commands.registerCommand('fuchsia.fx.serve', () => {
void window.withProgress({
location: vscode.ProgressLocation.Notification,
title: 'fx serve',
cancellable: true
}, async (progress, token) => {
let cmd = setup.fx.runAsync(['serve', '--background'], handleData, handleData);
token.onCancellationRequested(() => {
console.log('User canceled fx serve operation');
cmd?.stop();
});
let exitCode = await cmd?.exitCode;
return exitCode === 0 ? Promise.resolve() : Promise.reject(exitCode);
/** callback to handle buffer from process */
function handleData(buffer: Buffer) {
const msg = new TextDecoder().decode(buffer);
logger.info(msg, 'fuchsia');
if (msg.includes('resolve')) {
let match = msg.match(/(.*) (\[\w+\])\s+(.*)/);
if (match) {
progress.report({ message: `${match[match.length - 1]}` });
}
}
}
});
});
vscode.commands.registerCommand('fuchsia.repository.server.stop', () => {
setup.ffx.runFfx(['repository', 'server', 'stop'])
.then(() => {
logger.info('Stopped the repository server');
})
.catch((err) => {
logger.error(err);
});
});
}