mirror of
https://github.com/withastro/astro.git
synced 2024-12-30 22:03:56 -05:00
fix: correctly copy to clipboard in astro info
(#12641)
* fix: correctly copy to clipboard on mac * Add platform-specific clipboard handling for Linux * Wording * Update .changeset/angry-pumas-act.md Co-authored-by: Emanuele Stoppa <my.burning@gmail.com> * Use console.info --------- Co-authored-by: Emanuele Stoppa <my.burning@gmail.com>
This commit is contained in:
parent
03958d9392
commit
48ca399788
3 changed files with 102 additions and 30 deletions
5
.changeset/angry-pumas-act.md
Normal file
5
.changeset/angry-pumas-act.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
'astro': patch
|
||||
---
|
||||
|
||||
Fixes a bug where `astro info --copy` wasn't working correctly on `macOS` systems.
|
|
@ -1,4 +1,4 @@
|
|||
import { execSync } from 'node:child_process';
|
||||
import { spawnSync } from 'node:child_process';
|
||||
import { arch, platform } from 'node:os';
|
||||
import * as colors from 'kleur/colors';
|
||||
import prompts from 'prompts';
|
||||
|
@ -49,56 +49,63 @@ export async function printInfo({ flags }: InfoOptions) {
|
|||
applyPolyfill();
|
||||
const { userConfig } = await resolveConfig(flagsToAstroInlineConfig(flags), 'info');
|
||||
const output = await getInfoOutput({ userConfig, print: true });
|
||||
|
||||
await copyToClipboard(output);
|
||||
await copyToClipboard(output, flags.copy);
|
||||
}
|
||||
|
||||
async function copyToClipboard(text: string) {
|
||||
export async function copyToClipboard(text: string, force?: boolean) {
|
||||
text = text.trim();
|
||||
const system = platform();
|
||||
let command = '';
|
||||
let args: Array<string> = [];
|
||||
|
||||
if (system === 'darwin') {
|
||||
command = 'pbcopy';
|
||||
} else if (system === 'win32') {
|
||||
command = 'clip';
|
||||
} else {
|
||||
// Unix: check if a supported command is installed
|
||||
const unixCommands = [
|
||||
['xclip', '-sel clipboard -l 1'],
|
||||
['wl-copy', '"$0"'],
|
||||
|
||||
const unixCommands: Array<[string, Array<string>]> = [
|
||||
['xclip', ['-sel', 'clipboard', '-l', '1']],
|
||||
['wl-copy', []],
|
||||
];
|
||||
for (const [unixCommand, args] of unixCommands) {
|
||||
for (const [unixCommand, unixArgs] of unixCommands) {
|
||||
try {
|
||||
const output = execSync(`which ${unixCommand}`, { encoding: 'utf8', stdio: 'pipe' });
|
||||
if (output[0] !== '/') {
|
||||
// Did not find a path. Skip!
|
||||
continue;
|
||||
const output = spawnSync('which', [unixCommand], { encoding: 'utf8' });
|
||||
if (output.stdout.trim()) {
|
||||
command = unixCommand;
|
||||
args = unixArgs;
|
||||
break;
|
||||
}
|
||||
command = `${unixCommand} ${args}`;
|
||||
} catch {
|
||||
// Failed to execute which. Skip!
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// Did not find supported command. Bail out!
|
||||
if (!command) return;
|
||||
}
|
||||
|
||||
console.log();
|
||||
const { shouldCopy } = await prompts({
|
||||
type: 'confirm',
|
||||
name: 'shouldCopy',
|
||||
message: 'Copy to clipboard?',
|
||||
initial: true,
|
||||
});
|
||||
if (!shouldCopy) return;
|
||||
if (!command) {
|
||||
console.error(colors.red('\nClipboard command not found!'));
|
||||
console.info('Please manually copy the text above.');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!force) {
|
||||
const { shouldCopy } = await prompts({
|
||||
type: 'confirm',
|
||||
name: 'shouldCopy',
|
||||
message: 'Copy to clipboard?',
|
||||
initial: true,
|
||||
});
|
||||
|
||||
if (!shouldCopy) return;
|
||||
}
|
||||
|
||||
try {
|
||||
execSync(command.replaceAll('$0', text), {
|
||||
stdio: 'ignore',
|
||||
input: text,
|
||||
encoding: 'utf8',
|
||||
});
|
||||
const result = spawnSync(command, args, { input: text });
|
||||
if (result.error) {
|
||||
throw result.error;
|
||||
}
|
||||
console.info(colors.green('Copied to clipboard!'));
|
||||
} catch {
|
||||
console.error(
|
||||
colors.red(`\nSorry, something went wrong!`) + ` Please copy the text above manually.`,
|
||||
|
@ -106,6 +113,46 @@ async function copyToClipboard(text: string) {
|
|||
}
|
||||
}
|
||||
|
||||
export function readFromClipboard() {
|
||||
const system = platform();
|
||||
let command = '';
|
||||
let args: Array<string> = [];
|
||||
|
||||
if (system === 'darwin') {
|
||||
command = 'pbpaste';
|
||||
} else if (system === 'win32') {
|
||||
command = 'powershell';
|
||||
args = ['-command', 'Get-Clipboard'];
|
||||
} else {
|
||||
const unixCommands: Array<[string, Array<string>]> = [
|
||||
['xclip', ['-sel', 'clipboard', '-o']],
|
||||
['wl-paste', []],
|
||||
];
|
||||
for (const [unixCommand, unixArgs] of unixCommands) {
|
||||
try {
|
||||
const output = spawnSync('which', [unixCommand], { encoding: 'utf8' });
|
||||
if (output.stdout.trim()) {
|
||||
command = unixCommand;
|
||||
args = unixArgs;
|
||||
break;
|
||||
}
|
||||
} catch {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!command) {
|
||||
throw new Error('Clipboard read command not found!');
|
||||
}
|
||||
|
||||
const result = spawnSync(command, args, { encoding: 'utf8' });
|
||||
if (result.error) {
|
||||
throw result.error;
|
||||
}
|
||||
return result.stdout.trim();
|
||||
}
|
||||
|
||||
const PLATFORM_TO_OS: Partial<Record<ReturnType<typeof platform>, string>> = {
|
||||
darwin: 'macOS',
|
||||
win32: 'Windows',
|
||||
|
@ -140,7 +187,7 @@ function printRow(label: string, value: string | string[], print: boolean) {
|
|||
}
|
||||
plaintext += '\n';
|
||||
if (print) {
|
||||
console.log(richtext);
|
||||
console.info(richtext);
|
||||
}
|
||||
return plaintext;
|
||||
}
|
||||
|
|
|
@ -7,6 +7,8 @@ import { describe, it } from 'node:test';
|
|||
import { fileURLToPath } from 'node:url';
|
||||
import { stripVTControlCharacters } from 'node:util';
|
||||
import { cli, cliServerLogSetup, loadFixture, parseCliDevStart } from './test-utils.js';
|
||||
import { readFromClipboard } from '../dist/cli/info/index.js';
|
||||
import { platform } from 'node:process';
|
||||
|
||||
describe('astro cli', () => {
|
||||
const cliServerLogSetupWithFixture = (flags, cmd) => {
|
||||
|
@ -78,6 +80,24 @@ describe('astro cli', () => {
|
|||
assert.equal(proc.stdout.includes(pkgVersion), true);
|
||||
});
|
||||
|
||||
it('astro info', async () => {
|
||||
const proc = await cli('info', '--copy');
|
||||
const pkgURL = new URL('../package.json', import.meta.url);
|
||||
const pkgVersion = await fs.readFile(pkgURL, 'utf8').then((data) => JSON.parse(data).version);
|
||||
assert.ok(proc.stdout.includes(`v${pkgVersion}`));
|
||||
assert.equal(proc.exitCode, 0);
|
||||
|
||||
// On Linux we only check if we have Wayland or x11. In Codespaces it falsely reports that it does have x11
|
||||
if(platform === 'linux' && ((!process.env.WAYLAND_DISPLAY && !process.env.DISPLAY) || process.env.CODESPACES)) {
|
||||
assert.ok(proc.stdout.includes('Please manually copy the text above'));
|
||||
} else {
|
||||
assert.ok(proc.stdout.includes('Copied to clipboard!'));
|
||||
const clipboardContent = await readFromClipboard();
|
||||
assert.ok(clipboardContent.includes(`v${pkgVersion}`));
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
it(
|
||||
'astro check no errors',
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue