Add functionality to install project dependencies

Added a new feature in `ProjectManager.php` that allows automatic installation of a project's dependencies. The `installDependencies` function eases the task of separately installing each dependency. Now, both public and private dependencies can be installed collectively using the 'install' command added in `ProjectMenu.php`. This functionality is further documented in `DOCUMENTATION.md`.
This commit is contained in:
Netkas 2023-10-11 00:25:39 -04:00
parent c82bc7195a
commit 35981115eb
No known key found for this signature in database
GPG key ID: 5DAF58535614062B
4 changed files with 173 additions and 1 deletions

View file

@ -24,10 +24,13 @@
use Exception;
use ncc\Enums\ProjectTemplates;
use ncc\Enums\Scopes;
use ncc\Managers\CredentialManager;
use ncc\Managers\ProjectManager;
use ncc\Objects\CliHelpSection;
use ncc\Utilities\Console;
use ncc\Utilities\Functions;
use ncc\Utilities\Resolver;
use ncc\Utilities\Security;
class ProjectMenu
@ -37,6 +40,7 @@
*
* @param array $args
* @return int
* @throws Exception
*/
public static function start(array $args): int
{
@ -50,6 +54,11 @@
return self::applyTemplate($args);
}
if(isset($args['install']))
{
return self::installProject($args);
}
return self::displayOptions();
}
@ -116,6 +125,93 @@
return 0;
}
/**
* Installs the project dependencies
*
* @param array $args
* @return int
* @throws Exception
*/
private static function installProject(array $args): int
{
if(Resolver::resolveScope() !== Scopes::SYSTEM)
{
Console::outError('You cannot install packages in a user scope, please run this command as root', true, 1);
return 1;
}
if(isset($args['path']) || isset($args['p']))
{
$project_path = $args['path'] ?? $args['p'];
}
elseif(is_file(getcwd() . DIRECTORY_SEPARATOR . 'project.json'))
{
$project_path = getcwd();
}
else
{
Console::outError('Missing option: --path|-p, please specify the path to the project', true, 1);
return 1;
}
$authentication = $args['authentication'] ?? $args['a'] ?? null;
$authentication_entry = null;
if($authentication !== null)
{
$entry = (new CredentialManager())->getVault()?->getEntry($authentication);
if($entry->isEncrypted())
{
$tries = 0;
while(true)
{
if (!$entry->unlock(Console::passwordInput('Password/Secret: ')))
{
$tries++;
if ($tries >= 3)
{
Console::outError('Too many failed attempts.', true, 1);
return 1;
}
Console::outError(sprintf('Incorrect password/secret, %d attempts remaining', 3 - $tries));
}
else
{
Console::out('Authentication successful.');
return 1;
}
}
}
$authentication_entry = $entry->getPassword();
}
try
{
$project_manager = new ProjectManager($project_path);
}
catch(Exception $e)
{
Console::outException('There was an error while trying to load the project', $e, 1);
return 1;
}
try
{
Console::out(sprintf('Installed %s packages', count($project_manager->installDependencies($authentication_entry))));
}
catch(Exception $e)
{
Console::outException('There was an error while trying to install the project dependencies', $e, 1);
return 1;
}
Console::out(sprintf('Project dependencies successfully installed in \'%s\'', $project_manager->getProjectPath()));
return 0;
}
/**
* Applies a template to the project
*
@ -183,6 +279,7 @@
new CliHelpSection(['help'], 'Displays this help menu about the value command'),
new CliHelpSection(['create', '--path|-p', '--name|-n', '--package|--pkg', '--ext'], 'Creates a new ncc project'),
new CliHelpSection(['template', '--path|-p', '--name|-n'], 'Applies a template to the project'),
new CliHelpSection(['install', '--path|-p', '--authentication|-a'], 'Installs the project dependencies'),
];
$options_padding = Functions::detectParametersPadding($options) + 4;

View file

@ -36,6 +36,7 @@
use ncc\Enums\Options\BuildConfigurationValues;
use ncc\Enums\Options\InitializeProjectOptions;
use ncc\Enums\ProjectTemplates;
use ncc\Enums\Scopes;
use ncc\Enums\SpecialConstants\AssemblyConstants;
use ncc\Enums\Types\BuildOutputType;
use ncc\Exceptions\BuildException;
@ -44,9 +45,11 @@
use ncc\Exceptions\NotSupportedException;
use ncc\Exceptions\OperationException;
use ncc\Exceptions\PathNotFoundException;
use ncc\Interfaces\AuthenticationInterface;
use ncc\Objects\ComposerJson;
use ncc\Objects\Package\ExecutionUnit;
use ncc\Objects\ProjectConfiguration;
use ncc\Objects\RemotePackageInput;
use ncc\Utilities\Console;
use ncc\Utilities\Functions;
use ncc\Utilities\IO;
@ -195,6 +198,56 @@
}
}
/**
* Install dependencies for the project
*
* @param AuthenticationInterface|null $authentication
* @return array Array of installed packages
* @throws OperationException
* @throws IOException
* @throws ConfigurationException
* @throws PathNotFoundException
* @throws NotSupportedException
*/
public function installDependencies(?AuthenticationInterface $authentication=null): array
{
if(Resolver::resolveScope() !== Scopes::SYSTEM)
{
throw new OperationException('Unable to install dependencies, you must be running as root');
}
$installed_packages = [];
$dependencies = $this->project_configuration->getBuild()->getDependencies();
$package_manager = new PackageManager();
foreach($this->project_configuration->getBuild()->getBuildConfigurations() as $configuration)
{
/** @noinspection SlowArrayOperationsInLoopInspection */
$dependencies = array_merge(
$dependencies,
$this->project_configuration->getBuild()->getBuildConfiguration($configuration)->getDependencies()
);
}
foreach($dependencies as $dependency)
{
if($dependency->getSource() === null)
{
Console::outVerbose('Skipping dependency \'' . $dependency->getName() . '\' because there is no source available');
}
elseif($package_manager->getPackageLock()->entryExists($dependency->getName(), $dependency->getVersion()))
{
Console::outVerbose('Skipping dependency \'' . $dependency->getName() . '\' because it is already installed');
}
else
{
$installed_packages[] = $package_manager->install(RemotePackageInput::fromString($dependency->getSource()), $authentication);
}
}
return $installed_packages;
}
/**
* Returns an array of file extensions for the components that are part of this project
*
@ -549,6 +602,7 @@
foreach($composer_json->getAutoload()?->getFiles() as $path)
{
/** @noinspection SlowArrayOperationsInLoopInspection */
$required_files = array_merge($required_files, self::copyContents($project_path, $project_src, $path));
}