| // Copyright 2022 The ChromiumOS Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| import * as fs from 'fs'; |
| import * as path from 'path'; |
| import * as vscode from 'vscode'; |
| import * as commonUtil from '../common/common_util'; |
| import * as logs from '../logs'; |
| import * as bgTaskStatus from '../ui/bg_task_status'; |
| import {TaskStatus} from '../ui/bg_task_status'; |
| |
| // The gn executable file path in chroot. |
| const GN_PATH = '/usr/bin/gn'; |
| |
| export function activate( |
| context: vscode.ExtensionContext, |
| statusManager: bgTaskStatus.StatusManager, |
| log: logs.LoggingBundle |
| ): void { |
| // Format a GN file under platform2 on save |
| // because cros lint requires formatting upon upload. |
| context.subscriptions.push( |
| vscode.workspace.onDidSaveTextDocument(document => { |
| if (document.languageId !== 'gn') { |
| return; |
| } |
| if (!document.uri.path.includes('src/platform2/')) { |
| return; |
| } |
| |
| // Passing an async function to vscode.Event essentially ignores promise |
| // results, so we keep this function non-async and ignore results |
| // explicitly with void. |
| void format(document.uri.fsPath, statusManager, log); |
| }) |
| ); |
| } |
| |
| async function format( |
| fsPath: string, |
| statusManager: bgTaskStatus.StatusManager, |
| log: logs.LoggingBundle |
| ) { |
| const realpath = await fs.promises.realpath(fsPath); |
| const chroot = commonUtil.findChroot(realpath); |
| if (chroot === undefined) { |
| log.channel.appendLine( |
| 'ERROR: chroot not found when attempting `gn format`' |
| ); |
| return; |
| } |
| |
| const args = ['format', realpath]; |
| const res = await commonUtil.exec(path.join(chroot, GN_PATH), args, { |
| logger: log.channel, |
| ignoreNonZeroExit: true, |
| logStdout: true, |
| }); |
| |
| if (res instanceof Error) { |
| log.channel.appendLine('ERROR: failed to run `gn format`: ' + res.message); |
| statusManager.setTask(log.taskId, { |
| status: TaskStatus.ERROR, |
| command: log.showLogCommand, |
| }); |
| return; |
| } |
| |
| // Exit status is 1 for all of these cases: |
| // - There was a syntax error in the file. This should be ignored. |
| // - Couldn't read the. This should be reported to the user. |
| // - Other errors (e.g. wrong subcommand name to gn, etc.) |
| // These can be distinguished by the error messages, but it is not a public API. |
| if (res.exitStatus === 1 && res.stdout.includes("ERROR Couldn't read")) { |
| log.channel.appendLine( |
| 'ERROR: `gn format` command exited with error: ' + res.stdout |
| ); |
| } |
| } |