Skip to content

Commit 6d74b20

Browse files
authored
Merge pull request #129 from adamj88/depends-exclusion
Add negated dependency support
2 parents 98d94b3 + 8edab02 commit 6d74b20

File tree

4 files changed

+93
-32
lines changed

4 files changed

+93
-32
lines changed

docs/USAGE_BASIC.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ to the user when patch is being applied.
150150
@label <value> (optional) overrides the description above when provided. Otherwise above info used
151151
@ticket <value> (optional) reference to some issue ID that relates to this fix (added to label)
152152
@link <value> (optional) url to additional data about this patch (added to label)
153-
@depends <value> (optional) other/package (make version constraint target another package instead)
153+
@depends <value> (optional) other/package (make version constraint target another package instead). Use !other/package to apply patch only when package is NOT installed
154154
@version <value> (optional) >=1.1.0 <1.4.0
155155
@after <value> (optional) Used in case a patch should be applied after another branch
156156
@before <value> (optional) Used in case a patch should be applied before another branch
@@ -232,6 +232,12 @@ apply correctly.
232232
"other/package": ">=2.1.7",
233233
"php": ">=7.1.0"
234234
}
235+
},
236+
"applies when unwanted/package is NOT installed": {
237+
"source": "example/negated-dependency.patch",
238+
"depends": {
239+
"!unwanted/package": ">=1.0.0"
240+
}
235241
}
236242
}
237243
}

src/Patch/Definition/NormalizerComponents/DependencyComponent.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ function ($pattern) use ($target) {
4646
);
4747
}
4848

49+
// Handle negated dependencies in JSON config
50+
$depends = $this->processNegatedDependencies($depends);
51+
4952
return array(
5053
PatchDefinition::DEPENDS => $depends
5154
);
@@ -84,4 +87,21 @@ private function generateDependencyMatchPatterns(array $config)
8487

8588
return $patternValues;
8689
}
90+
91+
private function processNegatedDependencies(array $depends)
92+
{
93+
$processedDepends = array();
94+
95+
foreach ($depends as $packageName => $version) {
96+
// Handle negated dependencies with ! prefix in JSON config
97+
if (strpos($packageName, '!') === 0) {
98+
$packageName = substr($packageName, 1);
99+
$version = array('version' => $version, 'negated' => true);
100+
}
101+
102+
$processedDepends[$packageName] = $version;
103+
}
104+
105+
return $processedDepends;
106+
}
87107
}

src/Patch/DefinitionList/LoaderComponents/ConstraintsComponent.php

Lines changed: 57 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -93,55 +93,82 @@ private function resolveComparisonResults(array $patchConstraints, array $packag
9393
{
9494
$comparisonResults = array();
9595

96-
foreach ($patchConstraints as $constraintTarget => $version) {
96+
foreach ($patchConstraints as $constraintTarget => $constraint) {
97+
// Check if this is a negated dependency (array format)
98+
if (is_array($constraint) && isset($constraint['negated']) && $constraint['negated']) {
99+
$version = $constraint['version'];
100+
$packageExists = isset($packages[$constraintTarget]);
101+
102+
if (!$packageExists) {
103+
// Package not installed - negated dependency satisfied
104+
$comparisonResults[] = true;
105+
continue;
106+
}
107+
108+
// Package is installed - check if version constraint fails
109+
$package = $packages[$constraintTarget];
110+
$matchResult = $this->checkVersionConstraint($package, $version, $rootRequires, $constraintTarget);
111+
$comparisonResults[] = !$matchResult; // Negate the result
112+
continue;
113+
}
114+
115+
// Handle regular string constraints
116+
$version = $constraint;
117+
97118
if (!isset($packages[$constraintTarget])) {
98119
continue;
99120
}
100121

101122
$package = $packages[$constraintTarget];
102123

103-
$packageVersion = $package->getVersion();
104-
$packageVersions = array($package->getVersion());
124+
$matchResult = $this->checkVersionConstraint($package, $version, $rootRequires, $constraintTarget);
125+
$comparisonResults[] = $matchResult;
126+
}
105127

106-
if (isset($rootRequires[$constraintTarget])) {
107-
/** @var \Composer\Package\CompletePackageInterface $targetRootPackage */
108-
$targetRootPackage = $rootRequires[$constraintTarget];
128+
return $comparisonResults;
129+
}
109130

110-
$prettyVersion = $this->packageUtils->getPrettyVersion($targetRootPackage);
131+
private function checkVersionConstraint($package, $version, $rootRequires, $constraintTarget)
132+
{
133+
$packageVersion = $package->getVersion();
134+
$packageVersions = array($package->getVersion());
111135

112-
$matches = array();
113-
preg_match('/.* as (.*)$/', $prettyVersion, $matches);
136+
if (isset($rootRequires[$constraintTarget])) {
137+
/** @var \Composer\Package\CompletePackageInterface $targetRootPackage */
138+
$targetRootPackage = $rootRequires[$constraintTarget];
114139

115-
if (isset($matches[1])) {
116-
$packageVersions[] = $matches[1];
117-
}
118-
}
140+
$prettyVersion = $this->packageUtils->getPrettyVersion($targetRootPackage);
119141

120-
if ($this->constraintUtils->isDevConstraint($packageVersion)) {
121-
$definedVersion = $this->configExtractor->getConfig(
122-
$package,
123-
'version'
124-
);
142+
$matches = array();
143+
preg_match('/.* as (.*)$/', $prettyVersion, $matches);
125144

126-
$packageVersions[] = $definedVersion;
145+
if (isset($matches[1])) {
146+
$packageVersions[] = $matches[1];
127147
}
148+
}
128149

129-
$matchResult = false;
150+
if ($this->constraintUtils->isDevConstraint($packageVersion)) {
151+
$definedVersion = $this->configExtractor->getConfig(
152+
$package,
153+
'version'
154+
);
130155

131-
foreach (array_filter($packageVersions) as $packageVersion) {
132-
$packageConstraint = $this->versionParser->parseConstraints($packageVersion);
133-
$patchConstraint = $this->versionParser->parseConstraints($version);
156+
$packageVersions[] = $definedVersion;
157+
}
134158

135-
$matchResult = $patchConstraint->matches($packageConstraint);
159+
$matchResult = false;
136160

137-
if ($matchResult) {
138-
break;
139-
}
140-
}
161+
foreach (array_filter($packageVersions) as $packageVersion) {
162+
$packageConstraint = $this->versionParser->parseConstraints($packageVersion);
163+
$patchConstraint = $this->versionParser->parseConstraints($version);
141164

142-
$comparisonResults[] = $matchResult;
165+
$matchResult = $patchConstraint->matches($packageConstraint);
166+
167+
if ($matchResult) {
168+
break;
169+
}
143170
}
144171

145-
return $comparisonResults;
172+
return $matchResult;
146173
}
147174
}

src/Patch/SourceLoaders/PatchesSearch.php

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,9 +269,17 @@ private function normalizeDependencies($dependsList)
269269
$dependsNormalized = array_map(
270270
function ($item) {
271271
$valueParts = explode(':', $item);
272+
$packageName = trim(array_shift($valueParts) ?? '');
273+
$version = trim(array_shift($valueParts) ?? '') ?: '>=0.0.0';
274+
275+
// Handle negated dependencies with ! prefix
276+
if (strpos($packageName, '!') === 0) {
277+
$packageName = substr($packageName, 1);
278+
$version = array('version' => $version, 'negated' => true);
279+
}
272280

273281
return array(
274-
trim(array_shift($valueParts) ?? '') => trim(array_shift($valueParts) ?? '') ?: '>=0.0.0'
282+
$packageName => $version
275283
);
276284
},
277285
array_unique($dependsList)

0 commit comments

Comments
 (0)