Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mydumper integration #1962

Merged
merged 34 commits into from
Aug 14, 2024
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
a7b3113
Add functions for testing if a file is a mydumper file
abdullah-kasim Jul 26, 2024
9b4a143
Utilize wp search-replace if we're importing a mydumper file
abdullah-kasim Jul 26, 2024
52cb749
Remove yauzl by reverting back to trunk's shrinkwrap.
abdullah-kasim Jul 29, 2024
12874f8
Remove .zip file support.
abdullah-kasim Jul 29, 2024
fd67819
Consistency - wonder if we can turn this into an eslint rule
abdullah-kasim Jul 29, 2024
20104e1
Merge branch 'trunk' into esp-72/mydumper-support
abdullah-kasim Jul 29, 2024
d683089
Throw an error if search-and-replace is used for mydumper
abdullah-kasim Jul 30, 2024
6cf1100
Close streams once we're done using them to prevent hanging handles
abdullah-kasim Jul 30, 2024
b3f6f25
Switch to myloader if mydumper sqldump is detected
abdullah-kasim Jul 30, 2024
4485a2f
Merge branch 'esp-72/mydumper-support' of github.com:Automattic/vip-c…
abdullah-kasim Jul 30, 2024
b4aab5b
Fix copy-paste fail
abdullah-kasim Jul 31, 2024
893fdd6
readLine.close() doesn't generate an event, so we need to remove that…
abdullah-kasim Jul 31, 2024
fbc3cae
Fix myloader description
abdullah-kasim Jul 31, 2024
39b9a85
Fix myloader errors by switching to root
abdullah-kasim Jul 31, 2024
bd1aaf1
Eliminate tight coupling by moving all exec calls to another file and…
abdullah-kasim Jul 31, 2024
7d01388
Fix SQL validation for mydumper files
abdullah-kasim Jul 31, 2024
062e29a
Fix searchReplace not working with a single search-replace
abdullah-kasim Aug 1, 2024
35ae6a2
Add fixMyDumperTransform() so that we can use it to transform our myd…
abdullah-kasim Aug 1, 2024
6d2b707
Oops, ignore line if there's no match.
abdullah-kasim Aug 1, 2024
7f80865
Use a more concise regex
abdullah-kasim Aug 1, 2024
c07d6b5
Remove unused flags to simplify things a bit
abdullah-kasim Aug 1, 2024
b9d2d1d
Add mysqldump fixtures to hopefully make our testing easier
abdullah-kasim Aug 1, 2024
6d7ae75
Add tests and remove as much mocking as possible so that we won't hav…
abdullah-kasim Aug 1, 2024
f9e717d
Merge branch 'trunk' into esp-72/mydumper-support
abdullah-kasim Aug 1, 2024
ec587ee
Rename fixture files to fit its purpose
abdullah-kasim Aug 1, 2024
6b7b15a
Gunzip stream doesn't have the `.on('close')` event.
abdullah-kasim Aug 1, 2024
4a01b34
Merge branch 'esp-72/mydumper-support' of github.com:Automattic/vip-c…
abdullah-kasim Aug 1, 2024
55377bf
Add tracking where possible on the type of sqldump used
abdullah-kasim Aug 2, 2024
68d2b25
Update src/lib/database.ts
sanmai Aug 2, 2024
a7416dc
Grab shrinkwrap from trunk to keep things consistent
abdullah-kasim Aug 2, 2024
d7792bc
Merge remote-tracking branch 'origin/esp-72/readability-refactor' int…
abdullah-kasim Aug 2, 2024
83b3e1c
Remove wpSearchReplace again as we're not using it
abdullah-kasim Aug 2, 2024
286feff
Merge branch 'trunk' into esp-72/mydumper-support
abdullah-kasim Aug 2, 2024
62918e7
Merge branch 'trunk' into esp-72/mydumper-support
abdullah-kasim Aug 14, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions assets/dev-env.lando.template.yml.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,14 @@ tooling:
cmd:
- wp

tooling:
db-myloader:
service: php
description: "Run WP-CLI command"
user: www-data
cmd:
- myloader -h database -u wordpress -p wordpress --database wordpress

db:
service: php
description: "Connect to the DB using mysql client (e.g. allow to run imports)"
Expand Down
12 changes: 6 additions & 6 deletions npm-shrinkwrap.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

56 changes: 51 additions & 5 deletions src/commands/dev-env-import-sql.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
import chalk from 'chalk';
import fs from 'fs';
import os from 'os';

import * as exit from '../lib/cli/exit';
import { getFileMeta, unzipFile } from '../lib/client-file-uploader';
import { getSqlDumpDetails, SqlDumpDetails, SqlDumpType } from '../lib/database';
import {
processBooleanOption,
validateDependencies,
} from '../lib/dev-environment/dev-environment-cli';
import {
exec,
getEnvironmentPath,
resolveImportPath,
exec,
} from '../lib/dev-environment/dev-environment-core';
import { bootstrapLando, isEnvUp } from '../lib/dev-environment/dev-environment-lando';
import UserError from '../lib/user-error';
Expand Down Expand Up @@ -38,6 +40,9 @@ export class DevEnvImportSQLCommand {

validateImportFileExtension( this.fileName );

const dumpDetails = await getSqlDumpDetails( this.fileName );
const isMyDumper = dumpDetails.type === SqlDumpType.MYDUMPER;

// Check if file is compressed and if so, extract the
const fileMeta = await getFileMeta( this.fileName );
if ( fileMeta.isCompressed ) {
Expand Down Expand Up @@ -66,7 +71,7 @@ export class DevEnvImportSQLCommand {
const resolvedPath = await resolveImportPath(
this.slug,
this.fileName,
searchReplace,
isMyDumper ? [] : searchReplace,
inPlace
);

Expand All @@ -84,9 +89,8 @@ export class DevEnvImportSQLCommand {
}

const fd = await fs.promises.open( resolvedPath, 'r' );
const importArg = [ 'db', '--disable-auto-rehash' ].concat(
this.options.quiet ? '--silent' : []
);
const importArg = this.getImportArgs( dumpDetails );
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extracted to a function to satisfy eslint complexity limit - which I totally agree with.


const origIsTTY = process.stdin.isTTY;

try {
Expand All @@ -111,6 +115,23 @@ export class DevEnvImportSQLCommand {
fs.unlinkSync( resolvedPath );
}

if ( isMyDumper && searchReplace?.length ) {
for ( const pair of searchReplace ) {
const [ from, to ] = pair.split( ',' ).map( item => item.trim() );
// TODO: Investigate if it's worth it to refactor everything to only use wp's version of wp search-replace
// eslint-disable-next-line no-await-in-loop
await exec( lando, this.slug, [
'wp',
'search-replace',
'--all-tables',
`//${ from }`,
`//${ to }`,
'--skip-plugins',
'--skip-themes',
] );
}
}

const cacheArg = [ 'wp', 'cache', 'flush', '--skip-plugins', '--skip-themes' ].concat(
this.options.quiet ? '--quiet' : []
);
Expand Down Expand Up @@ -145,4 +166,29 @@ export class DevEnvImportSQLCommand {
].concat( this.options.quiet ? '--quiet' : [] );
await exec( lando, this.slug, addUserArg );
}

public getImportArgs( dumpDetails: SqlDumpDetails ) {
let importArg = [ 'db', '--disable-auto-rehash' ].concat(
this.options.quiet ? '--silent' : []
);
const threadCount = Math.max( os.cpus().length - 2, 1 );
if ( dumpDetails.type === SqlDumpType.MYDUMPER ) {
importArg = [
'db-myloader',
'--overwrite-tables',
`--threads=${ threadCount }`,
'--max-threads-for-schema-creation=10',
'--max-threads-for-index-creation=10',
'--skip-triggers',
'--skip-post',
'--checksum="SKIP"',
'--metadata-refresh-interval=2000000',
'--stream',
'--source-db',
dumpDetails.sourceDb,
].concat( this.options.quiet ? [ '--verbose=0' ] : [ '--verbose=3' ] );
}

return importArg;
abdullah-kasim marked this conversation as resolved.
Show resolved Hide resolved
}
}
89 changes: 73 additions & 16 deletions src/commands/dev-env-sync-sql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import { TrackFunction } from '../lib/analytics/clients/tracks';
import { BackupStorageAvailability } from '../lib/backup-storage-availability/backup-storage-availability';
import * as exit from '../lib/cli/exit';
import { unzipFile } from '../lib/client-file-uploader';
import { getSqlDumpDetails, SqlDumpType } from '../lib/database';
import { exec } from '../lib/dev-environment/dev-environment-core';
import { makeTempDir } from '../lib/utils';
import { getReadInterface } from '../lib/validations/line-by-line';

Expand Down Expand Up @@ -62,6 +64,7 @@ export class DevEnvSyncSQLCommand {
public siteUrls: string[] = [];
public searchReplaceMap: Record< string, string > = {};
public track: TrackFunction;
private _sqlDumpType?: SqlDumpType;

/**
* Creates a new instance of the command
Expand Down Expand Up @@ -95,6 +98,19 @@ export class DevEnvSyncSQLCommand {
return `${ this.tmpDir }/sql-export.sql.gz`;
}

private getSqlDumpType(): SqlDumpType {
if ( ! this._sqlDumpType ) {
throw new Error( 'SQL Dump type not initialized' );
}

return this._sqlDumpType;
}

private async initSqlDumpType(): Promise< void > {
const dumpDetails = await getSqlDumpDetails( this.sqlFile );
this._sqlDumpType = dumpDetails.type;
}

private async confirmEnoughStorage( job: Job ) {
const storageAvailability = BackupStorageAvailability.createFromDbCopyJob( job );
return await storageAvailability.validateAndPromptDiskSpaceWarningForDevEnvBackupImport();
Expand Down Expand Up @@ -138,6 +154,23 @@ export class DevEnvSyncSQLCommand {
} );
}

public async runWPSearchReplace(): Promise< void > {
const replacements = this.searchReplaceMap;
for ( const url in replacements ) {
const replacement = replacements[ url ];
// eslint-disable-next-line no-await-in-loop
await exec( this.lando, this.slug, [
'wp',
'search-replace',
'--all-tables',
`//${ url }`,
`//${ replacement }`,
'--skip-plugins',
'--skip-themes',
] );
}
}

public generateSearchReplaceMap(): void {
this.searchReplaceMap = {};

Expand Down Expand Up @@ -212,6 +245,7 @@ export class DevEnvSyncSQLCommand {
try {
console.log( `Extracting the exported file ${ this.gzFile }...` );
await unzipFile( this.gzFile, this.sqlFile );
await this.initSqlDumpType();
console.log( `${ chalk.green( '✓' ) } Extracted to ${ this.sqlFile }` );
} catch ( err ) {
const error = err as Error;
Expand Down Expand Up @@ -239,29 +273,30 @@ export class DevEnvSyncSQLCommand {
console.log( 'Generating search-replace configuration...' );
this.generateSearchReplaceMap();

try {
console.log( 'Running the following search-replace operations on the SQL file:' );
for ( const [ domain, landoDomain ] of Object.entries( this.searchReplaceMap ) ) {
console.log( ` ${ domain } -> ${ landoDomain }` );
if ( this.getSqlDumpType() === SqlDumpType.MYSQLDUMP ) {
try {
console.log( 'Running the following search-replace operations on the SQL file:' );
for ( const [ domain, landoDomain ] of Object.entries( this.searchReplaceMap ) ) {
console.log( ` ${ domain } -> ${ landoDomain }` );
}

await this.runSearchReplace();
console.log( `${ chalk.green( '✓' ) } Search-replace operation is complete` );
} catch ( err ) {
const error = err as Error;
await this.track( 'error', {
error_type: 'search_replace',
error_message: error.message,
stack: error.stack,
} );
exit.withError( `Error replacing domains: ${ error.message }` );
}

await this.runSearchReplace();
console.log( `${ chalk.green( '✓' ) } Search-replace operation is complete` );
} catch ( err ) {
const error = err as Error;
await this.track( 'error', {
error_type: 'search_replace',
error_message: error.message,
stack: error.stack,
} );
exit.withError( `Error replacing domains: ${ error.message }` );
}

try {
console.log( 'Importing the SQL file...' );
await this.runImport();
console.log( `${ chalk.green( '✓' ) } SQL file imported` );
return true;
} catch ( err ) {
const error = err as Error;
await this.track( 'error', {
Expand All @@ -271,5 +306,27 @@ export class DevEnvSyncSQLCommand {
} );
exit.withError( `Error importing SQL file: ${ error.message }` );
}

if ( this.getSqlDumpType() === SqlDumpType.MYDUMPER ) {
try {
console.log( 'Running the following search-replace operations on the database:' );
for ( const [ domain, landoDomain ] of Object.entries( this.searchReplaceMap ) ) {
console.log( ` ${ domain } -> ${ landoDomain }` );
}

await this.runWPSearchReplace();
console.log( `${ chalk.green( '✓' ) } Search-replace operation is complete` );
} catch ( err ) {
const error = err as Error;
await this.track( 'error', {
error_type: 'search_replace',
error_message: error.message,
stack: error.stack,
} );
exit.withError( `Error replacing domains: ${ error.message }` );
}
}

return true;
}
}
Loading
Loading