Implemented build method for building packages
This commit is contained in:
parent
477834b0a6
commit
d8ba1fbbc7
6 changed files with 283 additions and 3 deletions
|
@ -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
|
||||
|
|
31
src/ncc/Abstracts/ComponentFlags.php
Normal file
31
src/ncc/Abstracts/ComponentFlags.php
Normal 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';
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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';
|
||||
}
|
||||
}
|
81
src/ncc/Utilities/Base64.php
Normal file
81
src/ncc/Utilities/Base64.php
Normal 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;
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue