mirror of
https://github.com/withastro/astro.git
synced 2025-01-13 22:11:20 -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 { arch, platform } from 'node:os';
|
||||||
import * as colors from 'kleur/colors';
|
import * as colors from 'kleur/colors';
|
||||||
import prompts from 'prompts';
|
import prompts from 'prompts';
|
||||||
|
@ -49,56 +49,63 @@ export async function printInfo({ flags }: InfoOptions) {
|
||||||
applyPolyfill();
|
applyPolyfill();
|
||||||
const { userConfig } = await resolveConfig(flagsToAstroInlineConfig(flags), 'info');
|
const { userConfig } = await resolveConfig(flagsToAstroInlineConfig(flags), 'info');
|
||||||
const output = await getInfoOutput({ userConfig, print: true });
|
const output = await getInfoOutput({ userConfig, print: true });
|
||||||
|
await copyToClipboard(output, flags.copy);
|
||||||
await copyToClipboard(output);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function copyToClipboard(text: string) {
|
export async function copyToClipboard(text: string, force?: boolean) {
|
||||||
text = text.trim();
|
text = text.trim();
|
||||||
const system = platform();
|
const system = platform();
|
||||||
let command = '';
|
let command = '';
|
||||||
|
let args: Array<string> = [];
|
||||||
|
|
||||||
if (system === 'darwin') {
|
if (system === 'darwin') {
|
||||||
command = 'pbcopy';
|
command = 'pbcopy';
|
||||||
} else if (system === 'win32') {
|
} else if (system === 'win32') {
|
||||||
command = 'clip';
|
command = 'clip';
|
||||||
} else {
|
} else {
|
||||||
// Unix: check if a supported command is installed
|
// Unix: check if a supported command is installed
|
||||||
const unixCommands = [
|
|
||||||
['xclip', '-sel clipboard -l 1'],
|
const unixCommands: Array<[string, Array<string>]> = [
|
||||||
['wl-copy', '"$0"'],
|
['xclip', ['-sel', 'clipboard', '-l', '1']],
|
||||||
|
['wl-copy', []],
|
||||||
];
|
];
|
||||||
for (const [unixCommand, args] of unixCommands) {
|
for (const [unixCommand, unixArgs] of unixCommands) {
|
||||||
try {
|
try {
|
||||||
const output = execSync(`which ${unixCommand}`, { encoding: 'utf8', stdio: 'pipe' });
|
const output = spawnSync('which', [unixCommand], { encoding: 'utf8' });
|
||||||
if (output[0] !== '/') {
|
if (output.stdout.trim()) {
|
||||||
// Did not find a path. Skip!
|
command = unixCommand;
|
||||||
continue;
|
args = unixArgs;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
command = `${unixCommand} ${args}`;
|
|
||||||
} catch {
|
} catch {
|
||||||
// Failed to execute which. Skip!
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Did not find supported command. Bail out!
|
|
||||||
if (!command) return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log();
|
if (!command) {
|
||||||
const { shouldCopy } = await prompts({
|
console.error(colors.red('\nClipboard command not found!'));
|
||||||
type: 'confirm',
|
console.info('Please manually copy the text above.');
|
||||||
name: 'shouldCopy',
|
return;
|
||||||
message: 'Copy to clipboard?',
|
}
|
||||||
initial: true,
|
|
||||||
});
|
if (!force) {
|
||||||
if (!shouldCopy) return;
|
const { shouldCopy } = await prompts({
|
||||||
|
type: 'confirm',
|
||||||
|
name: 'shouldCopy',
|
||||||
|
message: 'Copy to clipboard?',
|
||||||
|
initial: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!shouldCopy) return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
execSync(command.replaceAll('$0', text), {
|
const result = spawnSync(command, args, { input: text });
|
||||||
stdio: 'ignore',
|
if (result.error) {
|
||||||
input: text,
|
throw result.error;
|
||||||
encoding: 'utf8',
|
}
|
||||||
});
|
console.info(colors.green('Copied to clipboard!'));
|
||||||
} catch {
|
} catch {
|
||||||
console.error(
|
console.error(
|
||||||
colors.red(`\nSorry, something went wrong!`) + ` Please copy the text above manually.`,
|
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>> = {
|
const PLATFORM_TO_OS: Partial<Record<ReturnType<typeof platform>, string>> = {
|
||||||
darwin: 'macOS',
|
darwin: 'macOS',
|
||||||
win32: 'Windows',
|
win32: 'Windows',
|
||||||
|
@ -140,7 +187,7 @@ function printRow(label: string, value: string | string[], print: boolean) {
|
||||||
}
|
}
|
||||||
plaintext += '\n';
|
plaintext += '\n';
|
||||||
if (print) {
|
if (print) {
|
||||||
console.log(richtext);
|
console.info(richtext);
|
||||||
}
|
}
|
||||||
return plaintext;
|
return plaintext;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,8 @@ import { describe, it } from 'node:test';
|
||||||
import { fileURLToPath } from 'node:url';
|
import { fileURLToPath } from 'node:url';
|
||||||
import { stripVTControlCharacters } from 'node:util';
|
import { stripVTControlCharacters } from 'node:util';
|
||||||
import { cli, cliServerLogSetup, loadFixture, parseCliDevStart } from './test-utils.js';
|
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', () => {
|
describe('astro cli', () => {
|
||||||
const cliServerLogSetupWithFixture = (flags, cmd) => {
|
const cliServerLogSetupWithFixture = (flags, cmd) => {
|
||||||
|
@ -78,6 +80,24 @@ describe('astro cli', () => {
|
||||||
assert.equal(proc.stdout.includes(pkgVersion), true);
|
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(
|
it(
|
||||||
'astro check no errors',
|
'astro check no errors',
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Reference in a new issue