diff --git a/src/hooks/tests/use-chat-context.test.tsx b/src/hooks/tests/use-chat-context.test.tsx index e41ebaa7c..3efe1f619 100644 --- a/src/hooks/tests/use-chat-context.test.tsx +++ b/src/hooks/tests/use-chat-context.test.tsx @@ -123,10 +123,12 @@ describe( 'useChatContext hook', () => { expect( getIpcApi().executeWPCLiInline ).toHaveBeenNthCalledWith( 1, { siteId: SELECTED_SITE.id, args: 'plugin list --format=json --status=active', + skipPluginsAndThemes: true, } ); expect( getIpcApi().executeWPCLiInline ).toHaveBeenNthCalledWith( 2, { siteId: SELECTED_SITE.id, args: 'theme list --format=json', + skipPluginsAndThemes: true, } ); expect( getIpcApi().executeWPCLiInline ).toHaveBeenCalledTimes( 2 ); } ); @@ -234,10 +236,12 @@ describe( 'useChatContext hook', () => { expect( getIpcApi().executeWPCLiInline ).toHaveBeenNthCalledWith( 1, { siteId: ANOTHER_SITE.id, args: 'plugin list --format=json --status=active', + skipPluginsAndThemes: true, } ); expect( getIpcApi().executeWPCLiInline ).toHaveBeenNthCalledWith( 2, { siteId: ANOTHER_SITE.id, args: 'theme list --format=json', + skipPluginsAndThemes: true, } ); expect( getIpcApi().executeWPCLiInline ).toHaveBeenCalledTimes( 2 ); } ); @@ -288,10 +292,12 @@ describe( 'useChatContext hook', () => { expect( getIpcApi().executeWPCLiInline ).toHaveBeenNthCalledWith( 1, { siteId: SELECTED_SITE.id, args: 'plugin list --format=json --status=active', + skipPluginsAndThemes: true, } ); expect( getIpcApi().executeWPCLiInline ).toHaveBeenNthCalledWith( 2, { siteId: SELECTED_SITE.id, args: 'theme list --format=json', + skipPluginsAndThemes: true, } ); expect( getIpcApi().executeWPCLiInline ).toHaveBeenCalledTimes( 2 ); } ); @@ -391,10 +397,12 @@ describe( 'useChatContext hook', () => { expect( getIpcApi().executeWPCLiInline ).toHaveBeenNthCalledWith( 1, { siteId: NEW_SITE.id, args: 'plugin list --format=json --status=active', + skipPluginsAndThemes: true, } ); expect( getIpcApi().executeWPCLiInline ).toHaveBeenNthCalledWith( 2, { siteId: NEW_SITE.id, args: 'theme list --format=json', + skipPluginsAndThemes: true, } ); expect( getIpcApi().executeWPCLiInline ).toHaveBeenCalledTimes( 2 ); } ); @@ -436,10 +444,12 @@ describe( 'useChatContext hook', () => { expect( getIpcApi().executeWPCLiInline ).toHaveBeenNthCalledWith( 1, { siteId: SELECTED_SITE.id, args: 'plugin list --format=json --status=active', + skipPluginsAndThemes: true, } ); expect( getIpcApi().executeWPCLiInline ).toHaveBeenNthCalledWith( 2, { siteId: SELECTED_SITE.id, args: 'theme list --format=json', + skipPluginsAndThemes: true, } ); expect( getIpcApi().executeWPCLiInline ).toHaveBeenCalledTimes( 2 ); } ); diff --git a/src/hooks/use-chat-context.tsx b/src/hooks/use-chat-context.tsx index fbca2cc9d..ce502e9e8 100644 --- a/src/hooks/use-chat-context.tsx +++ b/src/hooks/use-chat-context.tsx @@ -80,6 +80,7 @@ export const ChatProvider: React.FC< ChatProviderProps > = ( { children } ) => { const { stdout, stderr } = await getIpcApi().executeWPCLiInline( { siteId, args: 'plugin list --format=json --status=active', + skipPluginsAndThemes: true, } ); if ( stderr ) { return []; @@ -91,6 +92,7 @@ export const ChatProvider: React.FC< ChatProviderProps > = ( { children } ) => { const { stdout, stderr } = await getIpcApi().executeWPCLiInline( { siteId, args: 'theme list --format=json', + skipPluginsAndThemes: true, } ); if ( stderr ) { return []; diff --git a/src/hooks/use-execute-cli.ts b/src/hooks/use-execute-cli.ts index fc8920f3a..702129102 100644 --- a/src/hooks/use-execute-cli.ts +++ b/src/hooks/use-execute-cli.ts @@ -28,6 +28,7 @@ export function useExecuteWPCLI( const result = await getIpcApi().executeWPCLiInline( { siteId: siteId || '', args: args.join( ' ' ), + skipPluginsAndThemes: false, } ); const msTime = Date.now() - startTime; diff --git a/src/ipc-handlers.ts b/src/ipc-handlers.ts index 2409d9863..8e47b47a7 100644 --- a/src/ipc-handlers.ts +++ b/src/ipc-handlers.ts @@ -815,7 +815,15 @@ export async function saveOnboarding( export async function executeWPCLiInline( _event: IpcMainInvokeEvent, - { siteId, args }: { siteId: string; args: string } + { + siteId, + args, + skipPluginsAndThemes = false, + }: { + siteId: string; + args: string; + skipPluginsAndThemes?: boolean; + } ): Promise< WpCliResult > { if ( SiteServer.isDeleted( siteId ) ) { return { @@ -828,7 +836,9 @@ export async function executeWPCLiInline( if ( ! server ) { throw new Error( 'Site not found.' ); } - return server.executeWpCliCommand( args ); + return server.executeWpCliCommand( args, { + skipPluginsAndThemes, + } ); } export async function getThumbnailData( _event: IpcMainInvokeEvent, id: string ) { diff --git a/src/lib/import-export/export/export-database.ts b/src/lib/import-export/export/export-database.ts index ddea88d33..3667f9b52 100644 --- a/src/lib/import-export/export/export-database.ts +++ b/src/lib/import-export/export/export-database.ts @@ -18,7 +18,10 @@ export async function exportDatabaseToFile( // Execute the command to export directly to the temp file const { stderr, exitCode } = await server.executeWpCliCommand( - `sqlite export ${ tempFileName } --require=/tmp/sqlite-command/command.php` + `sqlite export ${ tempFileName } --require=/tmp/sqlite-command/command.php`, + { + skipPluginsAndThemes: true, + } ); if ( stderr ) { @@ -47,7 +50,10 @@ export async function exportDatabaseToMultipleFiles( } const tablesResult = await server.executeWpCliCommand( - `sqlite tables --format=json --require=/tmp/sqlite-command/command.php` + `sqlite tables --format=json --require=/tmp/sqlite-command/command.php`, + { + skipPluginsAndThemes: true, + } ); if ( tablesResult.stderr ) { throw new Error( `Database export failed: ${ tablesResult.stderr }` ); @@ -79,7 +85,10 @@ export async function exportDatabaseToMultipleFiles( // Execute the command to export directly to a temporary file in the project directory const { stderr, exitCode } = await server.executeWpCliCommand( - `sqlite export ${ fileName } --tables=${ table } --require=/tmp/sqlite-command/command.php` + `sqlite export ${ fileName } --tables=${ table } --require=/tmp/sqlite-command/command.php`, + { + skipPluginsAndThemes: true, + } ); if ( stderr ) { diff --git a/src/lib/import-export/export/exporters/default-exporter.ts b/src/lib/import-export/export/exporters/default-exporter.ts index 6e3eff2c2..eb436c0e9 100644 --- a/src/lib/import-export/export/exporters/default-exporter.ts +++ b/src/lib/import-export/export/exporters/default-exporter.ts @@ -268,7 +268,10 @@ export class DefaultExporter extends EventEmitter implements Exporter { } const { stderr, stdout } = await server.executeWpCliCommand( - 'plugin list --status=active,inactive --fields=name,status,version --format=json' + 'plugin list --status=active,inactive --fields=name,status,version --format=json', + { + skipPluginsAndThemes: true, + } ); if ( stderr ) { @@ -296,7 +299,10 @@ export class DefaultExporter extends EventEmitter implements Exporter { } const { stderr, stdout } = await server.executeWpCliCommand( - 'theme list --fields=name,status,version --format=json' + 'theme list --fields=name,status,version --format=json', + { + skipPluginsAndThemes: true, + } ); if ( stderr ) { diff --git a/src/lib/import-export/import/importers/importer.ts b/src/lib/import-export/import/importers/importer.ts index 4a61d9e80..3e3e7af33 100644 --- a/src/lib/import-export/import/importers/importer.ts +++ b/src/lib/import-export/import/importers/importer.ts @@ -57,7 +57,7 @@ abstract class BaseImporter extends EventEmitter implements Importer { const { stderr, exitCode } = await server.executeWpCliCommand( `sqlite import ${ sqlTempFile } --require=/tmp/sqlite-command/command.php`, // SQLite plugin requires PHP 8+ - { targetPhpVersion: DEFAULT_PHP_VERSION } + { targetPhpVersion: DEFAULT_PHP_VERSION, skipPluginsAndThemes: true } ); if ( stderr ) { @@ -86,7 +86,9 @@ abstract class BaseImporter extends EventEmitter implements Importer { throw new Error( 'Site not found.' ); } - const { stdout: currentSiteUrl } = await server.executeWpCliCommand( `option get siteurl` ); + const { stdout: currentSiteUrl } = await server.executeWpCliCommand( `option get siteurl`, { + skipPluginsAndThemes: true, + } ); if ( ! currentSiteUrl ) { console.error( 'Failed to fetch site URL after import' ); @@ -96,7 +98,10 @@ abstract class BaseImporter extends EventEmitter implements Importer { const studioUrl = `http://localhost:${ server.details.port }`; const { stderr, exitCode } = await server.executeWpCliCommand( - `search-replace '${ currentSiteUrl.trim() }' '${ studioUrl.trim() }'` + `search-replace '${ currentSiteUrl.trim() }' '${ studioUrl.trim() }'`, + { + skipPluginsAndThemes: true, + } ); if ( stderr ) { diff --git a/src/lib/import-export/tests/export/exporters/sql-exporter.test.ts b/src/lib/import-export/tests/export/exporters/sql-exporter.test.ts index 067a2e017..2dbd8e7ba 100644 --- a/src/lib/import-export/tests/export/exporters/sql-exporter.test.ts +++ b/src/lib/import-export/tests/export/exporters/sql-exporter.test.ts @@ -58,7 +58,10 @@ describe( 'SqlExporter', () => { const siteServer = SiteServer.get( '123' ); expect( siteServer?.executeWpCliCommand ).toHaveBeenCalledWith( - 'sqlite export studio-backup-db-export-2024-08-01-12-00-00.sql --require=/tmp/sqlite-command/command.php' + 'sqlite export studio-backup-db-export-2024-08-01-12-00-00.sql --require=/tmp/sqlite-command/command.php', + { + skipPluginsAndThemes: true, + } ); } ); diff --git a/src/lib/import-export/tests/import/importer/default-importer.test.ts b/src/lib/import-export/tests/import/importer/default-importer.test.ts index fc4f3514c..416cc5edc 100644 --- a/src/lib/import-export/tests/import/importer/default-importer.test.ts +++ b/src/lib/import-export/tests/import/importer/default-importer.test.ts @@ -80,9 +80,11 @@ describe( 'JetpackImporter', () => { 'sqlite import studio-backup-sql-2024-08-01-12-00-00.sql --require=/tmp/sqlite-command/command.php'; expect( siteServer?.executeWpCliCommand ).toHaveBeenNthCalledWith( 1, expectedCommand, { targetPhpVersion: '8.1', + skipPluginsAndThemes: true, } ); expect( siteServer?.executeWpCliCommand ).toHaveBeenNthCalledWith( 2, expectedCommand, { targetPhpVersion: '8.1', + skipPluginsAndThemes: true, } ); const expectedUnlinkPath = '/path/to/studio/site/studio-backup-sql-2024-08-01-12-00-00.sql'; diff --git a/src/lib/import-export/tests/import/importer/playground-importer.test.ts b/src/lib/import-export/tests/import/importer/playground-importer.test.ts index ab7defd03..82a1a4a3e 100644 --- a/src/lib/import-export/tests/import/importer/playground-importer.test.ts +++ b/src/lib/import-export/tests/import/importer/playground-importer.test.ts @@ -75,7 +75,9 @@ describe( 'localImporter', () => { const siteServer = SiteServer.get( mockStudioSiteId ); const expectedCommand = 'option get siteurl'; - expect( siteServer?.executeWpCliCommand ).toHaveBeenNthCalledWith( 1, expectedCommand ); + expect( siteServer?.executeWpCliCommand ).toHaveBeenNthCalledWith( 1, expectedCommand, { + skipPluginsAndThemes: true, + } ); expect( move ).toHaveBeenNthCalledWith( 1, diff --git a/src/site-server.ts b/src/site-server.ts index 0784d3db6..102b650e8 100644 --- a/src/site-server.ts +++ b/src/site-server.ts @@ -168,7 +168,13 @@ export class SiteServer { async executeWpCliCommand( args: string, - { targetPhpVersion }: { targetPhpVersion?: string } = {} + { + targetPhpVersion, + skipPluginsAndThemes = false, + }: { + targetPhpVersion?: string; + skipPluginsAndThemes?: boolean; + } = {} ): Promise< WpCliResult > { const projectPath = this.details.path; const phpVersion = targetPhpVersion ?? this.details.phpVersion; @@ -180,6 +186,11 @@ export class SiteServer { const wpCliArgs = parse( args ); + if ( skipPluginsAndThemes ) { + wpCliArgs.push( '--skip-plugins' ); + wpCliArgs.push( '--skip-themes' ); + } + // The parsing of arguments can include shell operators like `>` or `||` that the app don't support. const isValidCommand = wpCliArgs.every( ( arg: unknown ) => typeof arg === 'string' || arg instanceof String