Skip to content

Commit 96f9d60

Browse files
Merge pull request #46 from move-elevator/feat/migrate-db-sync-tool-file-sync-tool-integration-to-php-sync-tool
feat: migrate db-sync-tool/file-sync-tool integration to php-sync-tool
2 parents 321dc0a + c8cc9f2 commit 96f9d60

9 files changed

Lines changed: 132 additions & 25 deletions

File tree

deployer/dev/task/dump.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,14 @@
1818
$dbSyncToolOriginPath = str_replace('<feature>', $target, get('dev_db_sync_tool_origin_path'));
1919
$additionalOptions = "--origin-path $dbSyncToolOriginPath";
2020

21+
$dbSyncTool = requireSyncTool('dump');
22+
23+
// php-sync-tool has no -kd/-dn equivalent yet (konradmichalik/php-sync-tool#33); until it
24+
// does, the dump lands wherever the project's own sync-tool YAML config's "dump_dir" says,
25+
// not necessarily $dbDumpDir
26+
$dumpLocationOptions = usingPhpSyncTool($dbSyncTool) ? '' : "-kd $dbDumpDir -dn $dbDumpFilename";
27+
2128
$dbSyncToolConfigPath = get('dev_db_sync_tool_config_path');
22-
runLocally("db_sync_tool -f $dbSyncToolConfigPath/$dbSyncToolSync -y -kd $dbDumpDir -dn $dbDumpFilename $additionalOptions", ['real_time_output' => true]);
29+
runLocally(escapeshellarg($dbSyncTool) . " -f $dbSyncToolConfigPath/$dbSyncToolSync -y $dumpLocationOptions $additionalOptions", ['real_time_output' => true]);
2330
})
2431
->desc('Sync database with drush');

deployer/dev/task/import.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88

99
$dbSyncToolSync = get('dev_db_sync_tool_default_sync');
1010

11+
$dbSyncTool = requireSyncTool('import');
12+
1113
$dbSyncToolConfigPath = get('dev_db_sync_tool_config_path');
12-
runLocally("db_sync_tool -f $dbSyncToolConfigPath/$dbSyncToolSync -y -i $dbDumpDir/$dbDumpFilename.sql", ['real_time_output' => true]);
14+
runLocally(escapeshellarg($dbSyncTool) . " -f $dbSyncToolConfigPath/$dbSyncToolSync -y -i $dbDumpDir/$dbDumpFilename.sql", ['real_time_output' => true]);
1315
})
1416
->desc('Sync database with drush');

deployer/dev/task/sync.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,10 @@
4747

4848
info("sync database from remote: $target");
4949

50+
$dbSyncTool = requireSyncTool('sync');
51+
5052
$dbSyncToolConfigPath = get('dev_db_sync_tool_config_path');
51-
runLocally("db_sync_tool -f $dbSyncToolConfigPath/$dbSyncToolSync -y $additionalOptions", ['real_time_output' => true]);
53+
runLocally(escapeshellarg($dbSyncTool) . " -f $dbSyncToolConfigPath/$dbSyncToolSync -y $additionalOptions", ['real_time_output' => true]);
5254
info("💽 Database from $target synced successfully");
5355
})
5456
->desc('Sync database with db-sync-tool');

deployer/feature/config/set.php

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,14 @@
2323
* Feature Sync
2424
*/
2525
#set('feature_sync_config', null);
26-
set('db_sync_tool', 'db_sync_tool'); # set to false, to disable db sync
27-
set('file_sync_tool', 'file_sync_tool'); # set to false, to disable file sync
26+
// resolves to vendor/bin/sync-tool (php-sync-tool) when available locally, falling back
27+
// to the legacy db_sync_tool PATH binary; set to false, to disable db sync
28+
set('db_sync_tool', function () {
29+
return resolveSyncTool('db_sync_tool');
30+
});
31+
// legacy-only: php-sync-tool syncs files via --with-files on the db_sync_tool call above,
32+
// so this is unused once db_sync_tool resolves to it; set to false, to disable file sync
33+
set('file_sync_tool', 'file_sync_tool');
2834

2935

3036
set('feature_sync_target_path', null);

deployer/feature/task/feature_sync.php

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -120,35 +120,44 @@ function resolveDatabaseHostToIp(string $hostname): void
120120
$optionalVerbose = isVerbose() ? '-v' : '';
121121

122122
/*
123-
* db_sync_tool
123+
* db_sync_tool / php-sync-tool
124124
* https://github.com/jackd248/db-sync-tool
125+
* https://github.com/konradmichalik/php-sync-tool
125126
*/
126-
if (get('db_sync_tool') !== false) {
127-
if (commandExistLocally("{{db_sync_tool}}")) {
127+
$dbSyncTool = get('db_sync_tool');
128+
$isPhpSyncTool = false !== $dbSyncTool && usingPhpSyncTool($dbSyncTool);
129+
130+
if (false !== $dbSyncTool) {
131+
if (syncToolAvailableLocally($dbSyncTool)) {
132+
$useRsync = $isPhpSyncTool ? '' : '--use-rsync';
133+
// php-sync-tool has file sync integrated, no separate file_sync_tool call needed
134+
$withFiles = $isPhpSyncTool && false !== get('file_sync_tool') ? '--with-files' : '';
128135
info('Synching database');
129-
runLocally("{{db_sync_tool}} -f {{feature_sync_config}} --target-path {{feature_sync_target_path}} --use-rsync -y $optionalVerbose");
136+
runLocally(escapeshellarg($dbSyncTool) . " -f {{feature_sync_config}} --target-path {{feature_sync_target_path}} $useRsync $withFiles -y $optionalVerbose");
130137
$synced = true;
131138
} else {
132-
debug("Skipping database sync, command \”{{db_sync_tool}}\” not available");
139+
debug("Skipping database sync, command \”$dbSyncTool\” not available");
133140
}
134141
} else {
135142
debug("Skipping database sync, db_sync_tool was disabled");
136143
}
137144

138145
/*
139-
* file_sync_tool
146+
* file_sync_tool (legacy only, see above)
140147
* https://github.com/jackd248/file-sync-tool
141148
*/
142-
if (get('file_sync_tool') !== false) {
143-
if (commandExistLocally("{{file_sync_tool}}")) {
144-
info('Synching files');
145-
runLocally("{{file_sync_tool}} -f {{feature_sync_config}} --files-target {{feature_sync_target_path_files}} $optionalVerbose");
146-
$synced = true;
149+
if (!$isPhpSyncTool) {
150+
if (get('file_sync_tool') !== false) {
151+
if (commandExistLocally("{{file_sync_tool}}")) {
152+
info('Synching files');
153+
runLocally("{{file_sync_tool}} -f {{feature_sync_config}} --files-target {{feature_sync_target_path_files}} $optionalVerbose");
154+
$synced = true;
155+
} else {
156+
debug("Skipping file sync, command \”{{file_sync_tool}}\” not available");
157+
}
147158
} else {
148-
debug("Skipping file sync, command \”{{file_sync_tool}}\” not available");
159+
debug("Skipping file sync, file_sync_tool was disabled");
149160
}
150-
} else {
151-
debug("Skipping file sync, file_sync_tool was disabled");
152161
}
153162

154163
if ($synced) info("feature branch <fg=magenta;options=bold>$feature</> was successfully synced");

deployer/functions.php

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,74 @@ function commandExistLocally(string $command): bool
131131
return testLocally("hash $command 2>/dev/null");
132132
}
133133

134+
/**
135+
* Checks whether a local path is executable. Unlike commandExistLocally()/hash (built
136+
* for PATH lookups), this reliably resolves a relative path containing a slash, e.g.
137+
* vendor/bin/sync-tool.
138+
*/
139+
function isExecutableLocally(string $path): bool
140+
{
141+
return testLocally('[ -x ' . escapeshellarg($path) . ' ]');
142+
}
143+
144+
/**
145+
* Resolves the sync tool binary to use: prefers the Composer-installed php-sync-tool
146+
* (https://github.com/konradmichalik/php-sync-tool) when present locally, falling back
147+
* to the legacy PATH-installed Python tool (db-sync-tool/file-sync-tool) otherwise.
148+
*
149+
* Lets each downstream project migrate independently by running
150+
* `composer require --dev konradmichalik/php-sync-tool` - no deploy.php opt-in needed.
151+
*/
152+
function resolveSyncTool(string $legacyBinary, string $phpBinary = 'vendor/bin/sync-tool'): string
153+
{
154+
return isExecutableLocally($phpBinary) ? $phpBinary : $legacyBinary;
155+
}
156+
157+
/**
158+
* Whether a resolved sync tool binary is php-sync-tool rather than the legacy tool.
159+
* Compared against the known php-sync-tool path, not path-shape - a downstream
160+
* project's legacy binary can itself be configured as an absolute or relative path,
161+
* which would otherwise be misclassified.
162+
*/
163+
function usingPhpSyncTool(string $resolvedBinary, string $phpBinary = 'vendor/bin/sync-tool'): bool
164+
{
165+
return $resolvedBinary === $phpBinary;
166+
}
167+
168+
/**
169+
* Checks whether a resolved sync tool binary is actually available locally: a path
170+
* (containing a slash) via isExecutableLocally(), a bare PATH command via
171+
* commandExistLocally().
172+
*/
173+
function syncToolAvailableLocally(string $binary): bool
174+
{
175+
return str_contains($binary, '/')
176+
? isExecutableLocally($binary)
177+
: commandExistLocally($binary);
178+
}
179+
180+
/**
181+
* Resolves the sync tool binary and verifies it is actually available locally, or
182+
* throws. Used by the dev:* tasks, which have no "disabled" concept and must hard-fail
183+
* rather than silently skip when the tool is missing.
184+
*
185+
* @throws \RuntimeException if db_sync_tool was disabled or is not available locally
186+
*/
187+
function requireSyncTool(string $action): string
188+
{
189+
$dbSyncTool = get('db_sync_tool');
190+
191+
if (false === $dbSyncTool) {
192+
throw new \RuntimeException("db_sync_tool was disabled, cannot $action.");
193+
}
194+
195+
if (!syncToolAvailableLocally($dbSyncTool)) {
196+
throw new \RuntimeException("Sync tool \"$dbSyncTool\" not available locally.");
197+
}
198+
199+
return $dbSyncTool;
200+
}
201+
134202
/**
135203
* Runs a remote command with the possibility to overwrite the default command options
136204
*/

deployer/sync/config/set.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,9 @@
22

33
namespace Deployer;
44

5-
set('db_sync_tool', 'db_sync_tool'); # set to false, to disable db backup
5+
// resolves to vendor/bin/sync-tool (php-sync-tool) when available locally, falling back
6+
// to the legacy db_sync_tool PATH binary; set to false, to disable db backup
7+
set('db_sync_tool', function () {
8+
return resolveSyncTool('db_sync_tool');
9+
});
610
#set('sync_database_backup_config', null);

deployer/sync/task/database_backup.php

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,19 @@
66

77
$optionalVerbose = isVerbose() ? '-v' : '';
88

9-
if (false === get('db_sync_tool')) {
9+
$dbSyncTool = get('db_sync_tool');
10+
11+
if (false === $dbSyncTool) {
1012
debug('Skipping database backup, db_sync_tool was disabled');
1113
return;
1214
}
1315

14-
if (commandExistLocally("{{db_sync_tool}}")) {
16+
if (syncToolAvailableLocally($dbSyncTool)) {
17+
$useRsync = usingPhpSyncTool($dbSyncTool) ? '' : '--use-rsync';
1518
info('Generating a database backup');
16-
runLocally("{{db_sync_tool}} -f {{sync_database_backup_config}} --use-rsync -y $optionalVerbose");
19+
runLocally(escapeshellarg($dbSyncTool) . " -f {{sync_database_backup_config}} $useRsync -y $optionalVerbose");
1720
} else {
18-
debug("Skipping database backup, {{db_sync_tool}} not available");
21+
debug("Skipping database backup, $dbSyncTool not available");
1922
}
2023

2124
})

docs/FEATURE.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,13 @@ labels:
3939
type: feature-branch-deployment
4040
```
4141
42-
For using the [synchronization](#synchronization), you need to have the following pip packages installed:
42+
For using the [synchronization](#synchronization), you need a sync tool installed. The preferred, Composer-native option is [php-sync-tool](https://github.com/konradmichalik/php-sync-tool):
43+
44+
```bash
45+
$ composer require --dev konradmichalik/php-sync-tool
46+
```
47+
48+
It is auto-detected at `vendor/bin/sync-tool` and used automatically once installed, no `deploy.php` change needed. The legacy Python tools remain supported as a fallback for projects that have not migrated yet:
4349

4450
```bash
4551
$ pip3 install db-sync-tool-kmi file-sync-tool-kmi

0 commit comments

Comments
 (0)