Skip to content
38 changes: 27 additions & 11 deletions tools/common/lib/sqlite-integration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,20 @@ export abstract class SqliteIntegrationProvider {
return hasDbPhp || ! hasWpConfig;
}

async shouldKeepExistingDbDropin( sitePath: string ): Promise< boolean > {
const dbPhpPath = path.join( sitePath, 'wp-content', 'db.php' );
if ( ! fs.existsSync( dbPhpPath ) ) {
return false;
}

try {
const content = await fs.promises.readFile( dbPhpPath, 'utf8' );
return content.includes( '@studio-keep' );
} catch {
return false;
}
}

async getSqliteVersionFromInstallation( sqliteMuPluginPath: string ): Promise< string > {
try {
const versionFileContent = await fs.promises.readFile(
Expand All @@ -39,20 +53,22 @@ export abstract class SqliteIntegrationProvider {

const wpContentPath = path.join( sitePath, 'wp-content' );
const databasePath = path.join( wpContentPath, 'database' );
const sqliteSourcePath = this.getSqlitePluginSourcePath();
const sqliteDirname = this.getSqliteDirname();

await fs.promises.mkdir( databasePath, { recursive: true } );

const sqliteSourcePath = this.getSqlitePluginSourcePath();
const dbCopyContent = await fs.promises.readFile(
path.join( sqliteSourcePath, 'db.copy' ),
'utf8'
);
const sqliteDirname = this.getSqliteDirname();
const updatedContent = dbCopyContent.replace(
"'{SQLITE_IMPLEMENTATION_FOLDER_PATH}'",
`realpath( __DIR__ . '/mu-plugins/${ sqliteDirname }' )`
);
await fs.promises.writeFile( path.join( wpContentPath, 'db.php' ), updatedContent );
if ( ! ( await this.shouldKeepExistingDbDropin( sitePath ) ) ) {
const dbCopyContent = await fs.promises.readFile(
path.join( sqliteSourcePath, 'db.copy' ),
'utf8'
);
const updatedContent = dbCopyContent.replace(
"'{SQLITE_IMPLEMENTATION_FOLDER_PATH}'",
`realpath( __DIR__ . '/mu-plugins/${ sqliteDirname }' )`
);
await fs.promises.writeFile( path.join( wpContentPath, 'db.php' ), updatedContent );
}

const sqliteDestPath = path.join( wpContentPath, 'mu-plugins', sqliteDirname );
await fs.promises.rm( sqliteDestPath, { recursive: true, force: true } );
Expand Down
60 changes: 60 additions & 0 deletions tools/common/lib/tests/sqlite-integration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,33 @@ platformTestSuite( 'SqliteIntegrationProvider', ( { normalize } ) => {
} );
} );

describe( 'shouldKeepExistingDbDropin', () => {
it( 'should return false when db.php does not exist', async () => {
const result = await provider.shouldKeepExistingDbDropin( MOCK_SITE_PATH );
expect( result ).toBe( false );
} );

it( 'should return false when db.php does not include the Studio keep marker', async () => {
volFromJSON( {
[ normalize( `${ MOCK_SITE_PATH }/wp-content/db.php` ) ]:
"<?php\ndefine( 'SQLITE_DB_DROPIN_VERSION', '1.8.0' );\ndefine( 'MARKDOWN_DB_DROPIN', true );",
} );

const result = await provider.shouldKeepExistingDbDropin( MOCK_SITE_PATH );
expect( result ).toBe( false );
} );

it( 'should return true when db.php includes the Studio keep marker', async () => {
volFromJSON( {
[ normalize( `${ MOCK_SITE_PATH }/wp-content/db.php` ) ]:
"<?php\n// @studio-keep\ndefine( 'SQLITE_DB_DROPIN_VERSION', '1.8.0' );\ndefine( 'MARKDOWN_DB_DROPIN', true );",
} );

const result = await provider.shouldKeepExistingDbDropin( MOCK_SITE_PATH );
expect( result ).toBe( true );
} );
} );

describe( 'installSqliteIntegration', () => {
beforeEach( () => {
volFromJSON( {
Expand All @@ -109,6 +136,39 @@ platformTestSuite( 'SqliteIntegrationProvider', ( { normalize } ) => {
);
} );

it( 'should not overwrite db.php drop-in with the Studio keep marker', async () => {
volFromJSON( {
[ normalize( `wp-files/${ SQLITE_DIRNAME }/db.copy` ) ]:
"SQLIntegration path: '{SQLITE_IMPLEMENTATION_FOLDER_PATH}'",
[ normalize( `${ MOCK_SITE_PATH }/wp-content/db.php` ) ]:
"<?php\n// @studio-keep\ndefine( 'SQLITE_DB_DROPIN_VERSION', '1.8.0' );\ndefine( 'MARKDOWN_DB_DROPIN', true );",
} );

await provider.installSqliteIntegration( MOCK_SITE_PATH );

expect( vi.mocked( fs.promises.writeFile ) ).not.toHaveBeenCalledWith(
normalize( `${ MOCK_SITE_PATH }/wp-content/db.php` ),
expect.any( String )
);
} );

it( 'should still copy mu-plugin when db.php has the Studio keep marker', async () => {
volFromJSON( {
[ normalize( `wp-files/${ SQLITE_DIRNAME }/db.copy` ) ]:
"SQLIntegration path: '{SQLITE_IMPLEMENTATION_FOLDER_PATH}'",
[ normalize( `${ MOCK_SITE_PATH }/wp-content/db.php` ) ]:
"<?php\n// @studio-keep\ndefine( 'SQLITE_DB_DROPIN_VERSION', '1.8.0' );\ndefine( 'MARKDOWN_DB_DROPIN', true );",
} );

await provider.installSqliteIntegration( MOCK_SITE_PATH );

expect( vi.mocked( fs.promises.cp ) ).toHaveBeenCalledWith(
normalize( `wp-files/${ SQLITE_DIRNAME }` ),
normalize( `${ MOCK_SITE_PATH }/wp-content/mu-plugins/${ SQLITE_DIRNAME }` ),
expect.any( Object )
);
} );

it( 'should copy SQLite plugin to mu-plugins', async () => {
await provider.installSqliteIntegration( MOCK_SITE_PATH );

Expand Down