Implemented build method for building packages

This commit is contained in:
Netkas 2022-10-23 16:21:41 -04:00
parent 477834b0a6
commit d8ba1fbbc7
6 changed files with 283 additions and 3 deletions

View file

@ -25,6 +25,7 @@ a PPM extension may be built in the future to allow for backwards compatibility.
## Special Thanks
- Marc Gutt (mgutt) <[marc@gutt.it](mailto:marc@gutt.it)>
- Debusschère Alexandre ([debuss](https://github.com/debuss))
## Copyright
- Copyright (c) 2022-2022, Nosial - All Rights Reserved

View file

@ -0,0 +1,31 @@
<?php
namespace ncc\Abstracts;
abstract class ComponentFlags
{
/**
* Indicates whether the component is represented as an AST representation
*/
const AST = 'ast';
/**
* Indicates whether the component is represented as plaintext
*/
const Plain = 'plain';
/**
* Indicates whether the component is represented as bytecode
*/
const Bytecode = 'bytecode';
/**
* Indicates whether the component is represented as binary or executable
*/
const Binary = 'binary';
/**
* Indicates whether the component is represented as as a base64 encoded string (Raw bytes' representation)
*/
const b64encoded = 'b64enc';
}

View file

@ -2,10 +2,12 @@
namespace ncc\CLI;
use Exception;
use ncc\Abstracts\CompilerExtensions;
use ncc\Abstracts\Options\BuildConfigurationValues;
use ncc\Classes\PhpExtension\Compiler;
use ncc\Exceptions\BuildConfigurationNotFoundException;
use ncc\Exceptions\BuildException;
use ncc\Exceptions\FileNotFoundException;
use ncc\Exceptions\MalformedJsonException;
use ncc\Exceptions\PackagePreparationFailedException;
@ -105,12 +107,22 @@
{
$Compiler->prepare([], getcwd(), $build_configuration);
}
catch (PackagePreparationFailedException $e)
catch (Exception $e)
{
Console::outException('The package preparation process failed', $e, 1);
return;
}
try
{
$Compiler->build([], getcwd());
}
catch (Exception $e)
{
Console::outException('Build Failed', $e, 1);
return;
}
exit(0);
}

View file

@ -6,6 +6,7 @@
use FilesystemIterator;
use ncc\Abstracts\ComponentFileExtensions;
use ncc\Abstracts\ComponentFlags;
use ncc\Abstracts\Options\BuildConfigurationValues;
use ncc\Exceptions\BuildConfigurationNotFoundException;
use ncc\Exceptions\BuildException;
@ -14,10 +15,13 @@
use ncc\ncc;
use ncc\Objects\Package;
use ncc\Objects\ProjectConfiguration;
use ncc\ThirdParty\nikic\PhpParser\Error;
use ncc\ThirdParty\nikic\PhpParser\ParserFactory;
use ncc\ThirdParty\theseer\DirectoryScanner\DirectoryScanner;
use ncc\ThirdParty\theseer\DirectoryScanner\Exception;
use ncc\Utilities\Console;
use ncc\Utilities\Functions;
use ncc\ZiProto\ZiProto;
use SplFileInfo;
class Compiler implements CompilerInterface
@ -145,7 +149,7 @@
Console::out('Scanning for resources... ', false);
/** @var SplFileInfo $item */
foreach($DirectoryScanner($source_path, true) as $item)
foreach($DirectoryScanner($source_path) as $item)
{
// Ignore directories, they're not important. :-)
if(is_dir($item->getPathName()))
@ -170,6 +174,14 @@
}
}
/**
* Builds the package by parsing the AST contents of the components and resources
*
* @param array $options
* @param string $path
* @return string
* @throws BuildException
*/
public function build(array $options, string $path): string
{
if($this->package == null)
@ -177,6 +189,113 @@
throw new BuildException('The prepare() method must be called before building the package');
}
// TODO: Implement build() method
// Append trailing slash to the end of the path if it's not already there
if(substr($path, -1) !== DIRECTORY_SEPARATOR)
{
$path .= DIRECTORY_SEPARATOR;
}
$source_path = $path . $this->project->Build->SourcePath;
// Append trailing slash to the end of the source path if it's not already there
if(substr($source_path, -1) !== DIRECTORY_SEPARATOR)
{
$source_path .= DIRECTORY_SEPARATOR;
}
// Runtime variables
$components = [];
$resources = [];
$processed_items = 0;
$total_items = 0;
if(count($this->package->Components) > 0)
{
if(ncc::cliMode())
{
Console::out('Compiling components');
$total_items = count($this->package->Components);
}
// Process the components and attempt to create an AST representation of the source
foreach($this->package->Components as $component)
{
if(ncc::cliMode())
{
Console::inlineProgressBar($processed_items, $total_items);
}
$content = file_get_contents(Functions::correctDirectorySeparator($source_path . $component->Name));
$parser = (new ParserFactory())->create(ParserFactory::PREFER_PHP7);
try
{
$stmts = $parser->parse($content);
$encoded = json_encode($stmts);
if($encoded === false)
{
$component->Flags[] = ComponentFlags::b64encoded;
$component->Data = Functions::byteEncode($content);
}
else
{
$component->Flags[] = ComponentFlags::AST;
$component->Data = ZiProto::encode(json_decode($encoded));
}
}
catch(Error $e)
{
$component->Flags[] = ComponentFlags::b64encoded;
$component->Data = Functions::byteEncode($content);
unset($e);
}
// Calculate the checksum
$component->Checksum = hash('sha1', $component->Data);
$components[] = $component;
$processed_items += 1;
}
// Update the components
$this->package->Components = $components;
}
if(count($this->package->Resources) > 0)
{
// Process the resources
if(ncc::cliMode())
{
Console::out('Processing resources');
$processed_items = 0;
$total_items = count($this->package->Resources);
}
foreach($this->package->Resources as $resource)
{
if(ncc::cliMode())
{
Console::inlineProgressBar($processed_items, $total_items);
}
// Get the data and
$resource->Data = file_get_contents(Functions::correctDirectorySeparator($source_path . $resource->Name));
$resource->Data = Functions::byteEncode($resource->Data);
$resource->Checksum = hash('sha1', $resource->Checksum);
}
// Update the resources
$this->package->Resources = $resources;
}
if(ncc::cliMode())
{
Console::out($this->package->Assembly->Package . ' compiled successfully');
}
// Write the package to disk
file_put_contents(getcwd() . DIRECTORY_SEPARATOR . 'test.bin', ZiProto::encode($this->package->toArray(true)));
return getcwd() . DIRECTORY_SEPARATOR . 'test.bin';
}
}

View file

@ -0,0 +1,81 @@
<?php
namespace ncc\Utilities;
/**
* @author Debusschère Alexandre
* @link https://gist.github.com/debuss/c750fa2d90085316a04154f5b481a047
*/
class Base64
{
/**
* Encodes data with MIME base64
*
* @param string $string
* @return string
*/
public static function encode(string $string): string
{
$base64 = str_split('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/');
$bit_pattern = '';
$padding = 0;
$encoded = '';
foreach (str_split($string) as $char)
{
$bit_pattern .= sprintf('%08s', decbin(ord($char)));
}
$bit_pattern = str_split($bit_pattern, 6);
$offset = count($bit_pattern) - 1;
if (strlen($bit_pattern[$offset]) < 6)
{
$padding = 6 - strlen($bit_pattern[$offset]);
$bit_pattern[$offset] .= str_repeat('0', $padding);
$padding /= 2;
}
foreach ($bit_pattern as $bit6)
{
$index = bindec($bit6);
$encoded .= $base64[$index];
}
return $encoded.str_repeat('=', $padding);
}
/**
* Decodes data encoded with MIME base64
*
* @param string $string
* @return string
*/
public static function decode(string $string): string
{
$base64 = str_split('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/');
$bit_pattern = '';
$padding = substr_count(substr(strrev($string), 0, 2), '=');
$decoded = '';
foreach (str_split($string) as $b64_encoded)
{
$bit_pattern .= sprintf('%06s', decbin(array_search($b64_encoded, $base64)));
}
$bit_pattern = str_split($bit_pattern, 8);
if ($padding)
{
$bit_pattern = array_slice($bit_pattern, 0, -$padding);
}
foreach ($bit_pattern as $bin)
{
$decoded .= chr(bindec($bin));
}
return $decoded;
}
}

View file

@ -208,4 +208,40 @@
// If the path is "/etc/foo/text.txt" and the basename is "/etc" then the returned path will be "foo/test.txt"
return str_replace($basename, (string)null, $path);
}
/**
* Corrects the directory separator for the given path
*
* @param $path
* @return string
*/
public static function correctDirectorySeparator($path): string
{
$path = str_ireplace('/', DIRECTORY_SEPARATOR, $path);
return str_ireplace('\\', DIRECTORY_SEPARATOR, $path);
}
/**
* Converts the input string into a Bas64 encoding before returning it as a
* byte representation
*
* @param string $string
* @return string
*/
public static function byteEncode(string $string): string
{
return convert_uuencode(Base64::encode($string));
}
/**
* Decodes the input string back into the normal string representation that was encoded
* by the byteEncode() function
*
* @param string $string
* @return string
*/
public static function byteDecode(string $string): string
{
return base64_decode(convert_uudecode($string));
}
}