Added functionality to remove symlink registrations during the uninstallation process & upgraded fix-broken to also detect broken packages that are installed on the system

This commit is contained in:
Netkas 2023-10-08 15:13:19 -04:00
parent 6388b27b7a
commit 0a2cee2a02
No known key found for this signature in database
GPG key ID: 5DAF58535614062B
4 changed files with 173 additions and 23 deletions

View file

@ -111,7 +111,7 @@
} }
catch(Exception $e) catch(Exception $e)
{ {
Console::outException(sprintf('Unable to fix missing packages: %s', $e->getMessage()), $e, 1); Console::outException(sprintf('Unable to fix broken packages: %s', $e->getMessage()), $e, 1);
return 1; return 1;
} }
} }
@ -401,6 +401,7 @@
/** /**
* Uninstall all packages from the system * Uninstall all packages from the system
* *
* @param array $args
* @return int * @return int
* @throws IOException * @throws IOException
* @throws OperationException * @throws OperationException
@ -450,18 +451,21 @@
} }
$package_manager = new PackageManager(); $package_manager = new PackageManager();
$results = $package_manager->getMissingPackages(); $missing_dependencies = $package_manager->getMissingPackages();
$broken_packages = $package_manager->getBrokenPackages();
$auto_yes = isset($args['y']); $auto_yes = isset($args['y']);
if(count($results) === 0) if(count($missing_dependencies) === 0 && count($broken_packages) === 0)
{ {
Console::out('No missing packages found'); Console::out('No broken packages found');
return 0; return 0;
} }
if(count($missing_dependencies) > 0)
{
Console::out('The following packages that are required by other packages are missing:'); Console::out('The following packages that are required by other packages are missing:');
$unfixable_count = 0; $unfixable_count = 0;
foreach($results as $package => $source) foreach($missing_dependencies as $package => $source)
{ {
if($source === null) if($source === null)
{ {
@ -475,7 +479,7 @@
if($unfixable_count > 0) if($unfixable_count > 0)
{ {
Console::out('The following packages packages cannot be fixed because they are missing and no source was specified:'); Console::out('The following packages packages cannot be fixed because they are missing and no source was specified:');
foreach($results as $package => $source) foreach($missing_dependencies as $package => $source)
{ {
if($source !== null) if($source !== null)
{ {
@ -485,13 +489,38 @@
Console::out(sprintf(' %s', $package)); Console::out(sprintf(' %s', $package));
} }
} }
}
if(!$auto_yes && !Console::getBooleanInput('Do you want attempt to fix these missing packages?')) if(count($broken_packages) > 0)
{
Console::out('The following packages are broken and should be removed:');
foreach($broken_packages as $package)
{
Console::out(sprintf(' %s', $package));
}
}
if(!$auto_yes && !Console::getBooleanInput('Do you want attempt to fix these packages?'))
{ {
return 0; return 0;
} }
foreach($results as $package => $source) foreach($broken_packages as $package)
{
Console::out(sprintf('Removing broken package %s', $package));
$parsed = explode('=', $package, 2);
if(count($parsed) === 1)
{
Console::out(sprintf('Uninstalling all versions of %s, removed %s packages', $package, count($package_manager->uninstall($parsed[0]))));
}
else
{
Console::out(sprintf('Uninstalling %s, removed %s packages', $package, count($package_manager->uninstall($parsed[0], $parsed[1]))));
}
}
foreach($missing_dependencies as $package => $source)
{ {
if($source === null) if($source === null)
{ {

View file

@ -42,6 +42,7 @@
use ncc\Enums\RegexPatterns; use ncc\Enums\RegexPatterns;
use ncc\Enums\Scopes; use ncc\Enums\Scopes;
use ncc\Enums\Types\ProjectType; use ncc\Enums\Types\ProjectType;
use ncc\Enums\Versions;
use ncc\Exceptions\ConfigurationException; use ncc\Exceptions\ConfigurationException;
use ncc\Exceptions\IOException; use ncc\Exceptions\IOException;
use ncc\Exceptions\NetworkException; use ncc\Exceptions\NetworkException;
@ -200,6 +201,30 @@
if($version === null) if($version === null)
{ {
if($this->package_lock->getEntry($package_name)->isSymlinkRegistered())
{
Console::outVerbose(sprintf(
'Removing symlink for %s=%s at %s',
$package_name, $this->package_lock->getEntry($package_name)->getVersion(Versions::LATEST)->getVersion(),
PathFinder::findBinPath() . DIRECTORY_SEPARATOR . strtolower($package_name)
));
try
{
$symlink_path = PathFinder::findBinPath() . DIRECTORY_SEPARATOR . strtolower($this->package_lock->getEntry($package_name)->getAssembly()->getName());
}
catch(Exception $e)
{
throw new IOException(sprintf('Failed to resolve symlink for %s=%s: %s', $package_name, $this->package_lock->getEntry($package_name)->getVersion(Versions::LATEST)->getVersion(), $e->getMessage()), $e);
}
if(is_file($symlink_path))
{
(new Filesystem())->remove($symlink_path);
$this->package_lock->getEntry($package_name)->setSymlinkRegistered(false);
}
}
foreach($this->package_lock->getEntry($package_name)->getVersions() as $iter_version) foreach($this->package_lock->getEntry($package_name)->getVersions() as $iter_version)
{ {
Console::out(sprintf('Uninstalling package %s=%s', $package_name, $iter_version)); Console::out(sprintf('Uninstalling package %s=%s', $package_name, $iter_version));
@ -209,11 +234,37 @@
$removed_packages[] = sprintf('%s=%s', $package_name, $iter_version); $removed_packages[] = sprintf('%s=%s', $package_name, $iter_version);
} }
$this->package_lock->removeEntry($package_name);
} }
else else
{ {
Console::out(sprintf('Uninstalling package %s=%s', $package_name, $version)); Console::out(sprintf('Uninstalling package %s=%s', $package_name, $version));
$package_path = $this->package_lock->getPath($package_name, $version); $package_path = $this->package_lock->getPath($package_name, $version);
if($this->package_lock->getEntry($package_name)->isSymlinkRegistered())
{
Console::outVerbose(sprintf(
'Removing symlink for %s=%s at %s',
$package_name, $version, PathFinder::findBinPath() . DIRECTORY_SEPARATOR . strtolower($package_name)
));
try
{
$symlink_path = PathFinder::findBinPath() . DIRECTORY_SEPARATOR . strtolower($this->package_lock->getEntry($package_name)->getAssembly($version)->getName());
}
catch(Exception $e)
{
Console::outWarning(sprintf('Failed to resolve symlink for %s=%s: %s', $package_name, $version, $e->getMessage()));
}
if(isset($symlink_path) && is_file($symlink_path))
{
(new Filesystem())->remove($symlink_path);
$this->package_lock->getEntry($package_name)->setSymlinkRegistered(false);
}
}
$this->package_lock->getEntry($package_name)->removeVersion($version); $this->package_lock->getEntry($package_name)->removeVersion($version);
(new Filesystem())->remove($package_path); (new Filesystem())->remove($package_path);
@ -309,6 +360,31 @@
return $results; return $results;
} }
/**
* Returns an array of broken packages detected on the system
*
* @return array
*/
public function getBrokenPackages(): array
{
$results = [];
foreach($this->package_lock->getEntries() as $entry)
{
foreach($this->package_lock->getEntry($entry)->getBrokenVersions() as $version)
{
if(in_array(sprintf('%s=%s', $entry, $version), $results, true))
{
continue;
}
$results[] = sprintf('%s=%s', $entry, $version);
}
}
return $results;
}
/** /**
* Installs a package onto the system from a local ncc package file * Installs a package onto the system from a local ncc package file
* *

View file

@ -459,6 +459,26 @@
return $execution_binary_path; return $execution_binary_path;
} }
/**
* Returns an array of all broken versions
*
* @return array
*/
public function getBrokenVersions(): array
{
$broken_versions = [];
foreach($this->versions as $version)
{
if($version->isBroken($this->name))
{
$broken_versions[] = $version->getVersion();
}
}
return $broken_versions;
}
/** /**
* Returns an array representation of the object * Returns an array representation of the object
* *

View file

@ -234,6 +234,31 @@
return $this->getPath($package_name) . DIRECTORY_SEPARATOR . FileDescriptor::SHADOW_PACKAGE; return $this->getPath($package_name) . DIRECTORY_SEPARATOR . FileDescriptor::SHADOW_PACKAGE;
} }
/**
* Returns True if the package is broken, false otherwise
*
* @return bool
*/
public function isBroken(string $package_name): bool
{
if(!is_file($this->getPath($package_name) . DIRECTORY_SEPARATOR . FileDescriptor::SHADOW_PACKAGE))
{
return true;
}
if(!is_file($this->getPath($package_name) . DIRECTORY_SEPARATOR . FileDescriptor::ASSEMBLY))
{
return true;
}
if(!is_file($this->getPath($package_name) . DIRECTORY_SEPARATOR . FileDescriptor::METADATA))
{
return true;
}
return false;
}
/** /**
* Returns an array representation of the object * Returns an array representation of the object
* *