Skip to content

Commit 812466e

Browse files
committed
[FrameworkBundle] Add diff option in the debug config command
1 parent e3aa0a2 commit 812466e

File tree

2 files changed

+79
-2
lines changed

2 files changed

+79
-2
lines changed

src/Symfony/Bundle/FrameworkBundle/Command/ConfigDebugCommand.php

Lines changed: 78 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Bundle\FrameworkBundle\Command;
1313

1414
use Symfony\Component\Config\Definition\ConfigurationInterface;
15+
use Symfony\Component\Config\Definition\Dumper\YamlReferenceDumper;
1516
use Symfony\Component\Config\Definition\Processor;
1617
use Symfony\Component\Console\Attribute\AsCommand;
1718
use Symfony\Component\Console\Completion\CompletionInput;
@@ -28,9 +29,11 @@
2829
use Symfony\Component\DependencyInjection\Extension\ConfigurationExtensionInterface;
2930
use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
3031
use Symfony\Component\Yaml\Yaml;
32+
use SebastianBergmann\Diff\Differ;
33+
use SebastianBergmann\Diff\Output\UnifiedDiffOutputBuilder;
3134

3235
/**
33-
* A console command for dumping available configuration reference.
36+
* A console command for dumping available configuration reference and optionally a diff with current one.
3437
*
3538
* @author Grégoire Pineau <lyrixx@lyrixx.info>
3639
*
@@ -47,6 +50,7 @@ protected function configure(): void
4750
new InputArgument('path', InputArgument::OPTIONAL, 'The configuration option path'),
4851
new InputOption('resolve-env', null, InputOption::VALUE_NONE, 'Display resolved environment variable values instead of placeholders'),
4952
new InputOption('format', null, InputOption::VALUE_REQUIRED, \sprintf('The output format ("%s")', implode('", "', $this->getAvailableFormatOptions())), class_exists(Yaml::class) ? 'txt' : 'json'),
53+
new InputOption('diff-reference-config', null, InputOption::VALUE_NONE, 'Compare the current configuration with the reference one'),
5054
])
5155
->setHelp(<<<EOF
5256
The <info>%command.name%</info> command dumps the current configuration for an
@@ -65,6 +69,10 @@ protected function configure(): void
6569
6670
<info>php %command.full_name% framework serializer.enabled</info>
6771
72+
The <info>--diff-reference-config</info> option makes a diff between current and reference configuration (only available for the yaml format):
73+
74+
<info>php %command.full_name% web_profiler --diff-reference-config --format=yaml</info>
75+
6876
EOF
6977
)
7078
;
@@ -99,6 +107,22 @@ protected function execute(InputInterface $input, OutputInterface $output): int
99107
return 1;
100108
}
101109

110+
$diff = $input->getOption('diff-reference-config');
111+
112+
if ($diff) {
113+
if (!class_exists(Differ::class)) {
114+
$errorIo->error('Using the "diff-reference-config" option requires the package "sebastian/diff". Try running "composer require --dev sebastian/diff".');
115+
116+
return 1;
117+
}
118+
119+
if ('yaml' !== $format) {
120+
$errorIo->error('Using the "diff-reference-config" option requires the output format to be "yaml".');
121+
122+
return 1;
123+
}
124+
}
125+
102126
if (null === $path = $input->getArgument('path')) {
103127
if ('txt' === $input->getOption('format')) {
104128
$io->title(
@@ -110,7 +134,15 @@ protected function execute(InputInterface $input, OutputInterface $output): int
110134
}
111135
}
112136

113-
$io->writeln($this->convertToFormat([$extensionAlias => $config], $format));
137+
$currentConfig = $this->convertToFormat($config, $format);
138+
139+
if ($diff) {
140+
$io->note(\sprintf('With Difference with default configuration for extension "%s"', $extensionAlias));
141+
142+
$currentConfig = $this->doDiff($extension, $currentConfig);
143+
}
144+
145+
$io->writeln($currentConfig);
114146

115147
return 0;
116148
}
@@ -284,4 +316,48 @@ private function getDocUrl(ExtensionInterface $extension, ContainerBuilder $cont
284316
->getNode(true)
285317
->getAttribute('docUrl');
286318
}
319+
320+
private function doDiff(ExtensionInterface $extension, string $currentConfig): string
321+
{
322+
// Use directly the existing command and get its output somehow?
323+
/*
324+
$configDumpReferenceInputs = new ArrayInput([
325+
'command' => 'config:dump-reference',
326+
'name' => $extensionAlias,
327+
'--format' => 'yaml',
328+
]);
329+
$configDumpReferenceInputs->setInteractive(false);
330+
$application = $this->getApplication();
331+
$defaultConfig = $application->doRun($configDumpReferenceInputs, $output);;
332+
*/
333+
334+
// Use the underlying code of "config:dump-reference" to dump default config and sanitize it for better diff
335+
if ($extension instanceof ConfigurationInterface) {
336+
$configuration = $extension;
337+
} else {
338+
$configuration = $extension->getConfiguration([], $this->getContainerBuilder($this->getApplication()->getKernel()));
339+
}
340+
$dumper = new YamlReferenceDumper();
341+
$defaultConfig = $dumper->dump($configuration);
342+
343+
// Remove first line, lines beginning with spaces and # and empty lines
344+
$lines = explode("\n", $defaultConfig);
345+
array_shift($lines);
346+
$lines = array_filter(
347+
$lines,
348+
fn($line) => !preg_match('/^\s*#/', $line) && trim($line) !== ''
349+
);
350+
// Remove first 4 spaces from every line
351+
$lines = array_map(fn($line) => preg_replace('/^ /', '', $line), $lines);
352+
// Remove comments (from # until end of line)
353+
$lines = array_map(fn($line) => preg_replace('/#.*$/', '', $line), $lines);
354+
// Replace multiple consecutive spaces with a single space (except at line start)
355+
$lines = array_map(fn($line) => preg_replace('/(?<=\S) {2,}/', ' ', $line), $lines);
356+
$defaultConfig = implode("\n", $lines);
357+
// Remove trailing newline
358+
$defaultConfig = rtrim($defaultConfig, "\n");
359+
$currentConfig = rtrim($currentConfig, "\n");
360+
361+
return new Differ(new UnifiedDiffOutputBuilder)->diff($defaultConfig, $currentConfig);
362+
}
287363
}

src/Symfony/Bundle/FrameworkBundle/composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
"doctrine/persistence": "^1.3|^2|^3",
3838
"dragonmantank/cron-expression": "^3.1",
3939
"phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0",
40+
"sebastian/diff": "7.0",
4041
"seld/jsonlint": "^1.10",
4142
"symfony/asset": "^7.4|^8.0",
4243
"symfony/asset-mapper": "^7.4|^8.0",

0 commit comments

Comments
 (0)