Skip to content

Commit 76b198c

Browse files
committed
Allow support for non-default vendor-dir by using official Composer API
1 parent 4130efb commit 76b198c

2 files changed

Lines changed: 83 additions & 57 deletions

File tree

src/mate/bin/mate.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,12 @@
2323
foreach ($autoloadPaths as $autoloadPath) {
2424
if (file_exists($autoloadPath)) {
2525
require_once $autoloadPath;
26-
$root = dirname(realpath($autoloadPath), 2);
26+
if (method_exists(InstalledVersions::class, 'getInstallPath')) {
27+
$root = Composer\InstalledVersions::getInstallPath('__root__');
28+
} else {
29+
$root = dirname(realpath($autoloadPath), 2);
30+
}
31+
2732
break;
2833
}
2934
}

src/mate/src/Discovery/ComposerExtensionDiscovery.php

Lines changed: 77 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
namespace Symfony\AI\Mate\Discovery;
1313

14+
use Composer\InstalledVersions;
1415
use Psr\Log\LoggerInterface;
1516

1617
/**
@@ -161,64 +162,13 @@ private function getInstalledPackages(): array
161162
return $this->installedPackages;
162163
}
163164

164-
$installedJsonPath = $this->rootDir.'/vendor/composer/installed.json';
165-
if (!file_exists($installedJsonPath)) {
166-
$this->logger->warning('Composer installed.json not found', ['path' => $installedJsonPath]);
167-
168-
return $this->installedPackages = [];
165+
if (method_exists(InstalledVersions::class, 'getAllRawData')) {
166+
$packages = InstalledVersions::getAllRawData();
167+
} else {
168+
$packages = $this->getPackagesWithoutComposer();
169169
}
170170

171-
$content = file_get_contents($installedJsonPath);
172-
if (false === $content) {
173-
$this->logger->warning('Could not read installed.json', [
174-
'path' => $installedJsonPath,
175-
'error' => error_get_last()['message'] ?? 'Unknown error',
176-
]);
177-
178-
return $this->installedPackages = [];
179-
}
180-
181-
try {
182-
$data = json_decode($content, true, 512, \JSON_THROW_ON_ERROR);
183-
} catch (\JsonException $e) {
184-
$this->logger->error('Invalid JSON in installed.json', ['error' => $e->getMessage()]);
185-
186-
return $this->installedPackages = [];
187-
}
188-
189-
if (!\is_array($data)) {
190-
return $this->installedPackages = [];
191-
}
192-
193-
// Handle both formats: {"packages": [...]} and direct array
194-
$packages = $data['packages'] ?? $data;
195-
if (!\is_array($packages)) {
196-
return $this->installedPackages = [];
197-
}
198-
199-
$indexed = [];
200-
foreach ($packages as $package) {
201-
if (!\is_array($package) || !isset($package['name']) || !\is_string($package['name'])) {
202-
continue;
203-
}
204-
205-
/** @var array{
206-
* name: string,
207-
* extra: array<string, mixed>,
208-
* } $validPackage */
209-
$validPackage = [
210-
'name' => $package['name'],
211-
'extra' => [],
212-
];
213-
214-
if (isset($package['extra']) && \is_array($package['extra'])) {
215-
/** @var array<string, mixed> $extra */
216-
$extra = $package['extra'];
217-
$validPackage['extra'] = $extra;
218-
}
219-
220-
$indexed[$package['name']] = $validPackage;
221-
}
171+
$indexed = $this->indexPackagesByName($packages);
222172

223173
return $this->installedPackages = $indexed;
224174
}
@@ -420,4 +370,75 @@ private function extractAiMateConfigString(array $composer, string $key): ?strin
420370

421371
return $value;
422372
}
373+
374+
private function getPackagesWithoutComposer(): array
375+
{
376+
$installedJsonPath = $this->rootDir.'/vendor/composer/installed.json';
377+
378+
if (!file_exists($installedJsonPath)) {
379+
$this->logger->warning('Composer installed.json not found', ['path' => $installedJsonPath]);
380+
381+
return [];
382+
}
383+
384+
$content = file_get_contents($installedJsonPath);
385+
if (false === $content) {
386+
$this->logger->warning('Could not read installed.json', [
387+
'path' => $installedJsonPath,
388+
'error' => error_get_last()['message'] ?? 'Unknown error',
389+
]);
390+
391+
return [];
392+
}
393+
394+
try {
395+
$data = json_decode($content, true, 512, \JSON_THROW_ON_ERROR);
396+
} catch (\JsonException $e) {
397+
$this->logger->error('Invalid JSON in installed.json', ['error' => $e->getMessage()]);
398+
399+
return [];
400+
}
401+
402+
if (!\is_array($data)) {
403+
return [];
404+
}
405+
406+
// Handle both formats: {"packages": [...]} and direct array
407+
$packages = $data['packages'] ?? $data;
408+
409+
if (!\is_array($packages)) {
410+
return [];
411+
}
412+
413+
return $packages;
414+
}
415+
416+
private function indexPackagesByName(array $packages): array
417+
{
418+
$indexed = [];
419+
foreach ($packages as $package) {
420+
if (!\is_array($package) || !isset($package['name']) || !\is_string($package['name'])) {
421+
continue;
422+
}
423+
424+
/** @var array{
425+
* name: string,
426+
* extra: array<string, mixed>,
427+
* } $validPackage
428+
*/
429+
$validPackage = [
430+
'name' => $package['name'],
431+
'extra' => [],
432+
];
433+
434+
if (isset($package['extra']) && \is_array($package['extra'])) {
435+
/** @var array<string, mixed> $extra */
436+
$extra = $package['extra'];
437+
$validPackage['extra'] = $extra;
438+
}
439+
440+
$indexed[$package['name']] = $validPackage;
441+
}
442+
return $indexed;
443+
}
423444
}

0 commit comments

Comments
 (0)