conflicts management + README.md update

This commit is contained in:
xdrm-brackets 2016-12-05 19:54:19 +01:00
parent 6fa223912d
commit d65860a78c
7 changed files with 260 additions and 251 deletions

View File

@ -6,36 +6,36 @@ xdrm-framework is a tool that wraps my framework and all it's component's versio
#### 1. Build a project
To use the xdrm-framework's project builder, just open a linux terminal and type :
1. `xdrm-framework modules` - to display the available modules
2. `xdrm-framework install {moduleName} 1.2` - to enable a module and its version (1.2 here)
3. `xdrm-framework remove {moduleName}` - to disable a module
4. `xdrm-framework build {projectRoot}` - will create your project in the folder `{projectRoot}`
5. `xdrm-framework init` - to remove all enabled modules
1. `./xfw packages` - to display the available modules
2. `./xfw install {packageName}:1.2` - to install a package and its version (1.2 here)
3. `./xfw remove {packageName}` - to disable a module
4. `./xfw build {projectRoot}` - will create your project in the folder `{projectRoot}`
5. `./xfw init` - to remove all enabled modules
#### 2. Project's file structure
xdrm-framework is based on `all is in config` so you will have this structure :
- folder `build` which contains framework's modules (core + data).
- folder `public_html` which contains visible content (html, css, js).
- folder `config` which contains the modules' config files (mainly json).
- file `autoloader.php` which will auto-load the components.
xdrm-framework is based on `all in config` so you will have this structure :
- folder `/build` which contains framework's modules (core + data).
- folder `/public_html` which contains visible content (html, css, js).
- folder `/config` which contains the modules' config files (mainly json).
- file `/autoloader.php` which will auto-load the components.
**Note:** In every php file you want to use framework's classes, you have to begin your file by :
```php
<?php
/* [1] load the autoloader with correct path */
require_once '../autoloader.php';
/* [1] load the autoloader with correct path */
require_once '../autoloader.php';
/* [2] then you can load your classes */
use api\core\Request; // ex1: api request manager
use error\core\Error; // ex2: error manager
use error\core\Err; // ex3: error codes
/* [2] then you can load your classes */
use api\core\Request; // ex1: api request manager
use error\core\Error; // ex2: error manager
use error\core\Err; // ex3: error codes
/* [3] and use them as long as you want without namespace */
$request = new Request('module/method', ['id_user' => 10]);
$response = $request->dispatch();
/* [3] and use them as long as you want without namespace */
$request = new Request('module/method', ['id_user' => 10]);
$response = $request->dispatch();
if( $response->error->get() === Err::Success )
echo "All is going right!\n";
if( $response->error->get() === Err::Success )
echo "All is going right!\n";
```
**Note:** Some global constants are created into the autoloader so they are accessible from any file which loads the autoloader:
@ -47,37 +47,53 @@ xdrm-framework is based on `all is in config` so you will have this structure :
### 3. Modules
#### [3.1] API - self-managed API
#### 3.1 API - self-managed API
###### How to use
In order to use the API, you must begin by writting your _"methods"_ in the configuration file located at `/config/modules.json`.
In order to be understood, lets call `module` a group of methods, and `method` a function which outputs data from input parameters.
**Configuration format**
```json
{
"{module_name}": {
"{module_name}": {
"{http_method}::{method_name}": {
"description": "{method_description}",
"permissions": ["{perm}"],
"options": { "download": {is_download} },
"parameters: {
"{name_param}": { "description": "{desc_param}", "type": "{type_param}", "optional": {is_optional} }
},
"output": {
"{name_output}": { "description": "{desc_output}", "type": "{type_output}" }
}
}
"{http_method}::{method_name}": {
"description": "{method_description}",
"permissions": ["{method_perm}"],
"options": { "download": "{is_downloadable}" },
"parameters": {
"{name_param}": { "description": "{desc_param}", "type": "{type_param}", "optional": "{is_optional}" }
},
"output": {
"{name_output}": { "description": "{desc_output}", "type": "{type_output}" }
}
}
}
}
}
```
|variable|description|exemple|
|-------|-------|------|
|`{module_name}`|alphanumeric module name|"publications"|
|`{http_method}`|uppercase HTTP method|"POST"|
|`{method_name}`|alphanumeric method name|"article"|
|`{method_description}`|textual description|"Returns a specific article"|
|`{method_perm}`|permission array|`["poster", "admin", "user"]`|
|`{is_downloadable}`|If you want this method to return a file|`true`, `false`|
|`{name_param}`|Your param's name|"id_article"|
|`{desc_param}`|Your param's description|"Wanted article's id"|
|`{type_param}`|Your param's type (cf. Checker)|"Wanted article's type"|
|`{is_optional}`|Whether to make your param _required_|`true`, `false`|
|`{name_output}`|Your output's name|"article"|
|`{desc_output}`|Your output's description|"Article content"|
**Implementation**
TODO
###### Classes (advanced)
The API is managed through 5 classes :

View File

@ -5,7 +5,7 @@
private static function src(){ return __ROOT__.'/src'; }
private $modules = null;
private $packages = null;
private $root = null;
@ -13,17 +13,17 @@
/* BUILDS A BUILDER WITH SPECIFIC LOCATION AND CONFIG
*
* @pRoot<String> Path to project root
* @pModules<Array> Modules to load
* @pPackages<Array> Packages to load
*
*/
public function __construct($pRoot, $pModules){
public function __construct($pRoot, $pPackages){
/* [1] Stores the path
=========================================================*/
$this->root = $pRoot;
/* [2] Stores the modules
/* [2] Stores the packages
=========================================================*/
$this->modules = $pModules;
$this->packages = $pPackages;
}
@ -37,16 +37,16 @@
/* [2] Browse each module to load
/* [2] Browse each package to load
=========================================================*/
foreach($this->modules as $module=>$version){
$path = "/$module/$version";
foreach($this->packages as $package=>$version){
$path = "/$package/$version";
/* (1) Copy module folder if it exists */
if( file_exists(__ROOT__."/src/modules$path/") && is_dir(__ROOT__."/src/modules$path/") && count(scandir(__ROOT__."/src/modules$path/")) > 2 )
shell_exec("cp -r ".__ROOT__."/src/modules$path ".$this->root."/build/$module");
/* (1) Copy package folder if it exists */
if( file_exists(__ROOT__."/src/packages$path/") && is_dir(__ROOT__."/src/packages$path/") && count(scandir(__ROOT__."/src/packages$path/")) > 2 )
shell_exec("cp -r ".__ROOT__."/src/packages$path ".$this->root."/build/$package");
/* (2) Copy module config if it exists */
/* (2) Copy package config if it exists */
if( file_exists(__ROOT__."/src/config$path/") && is_dir(__ROOT__."/src/config$path/") && count(scandir(__ROOT__."/src/config$path/")) > 2 )
shell_exec("cp -r ".__ROOT__."/src/config$path/* ".$this->root."/config/");

View File

@ -5,9 +5,9 @@
class Exporter{
private $modules; // will contain modules (config)
private $packages; // will contain packages (config)
public static function config_path(){ return __ROOT__.'/exporter/modules.json'; }
public static function config_path(){ return __ROOT__.'/exporter/packages.json'; }
@ -17,7 +17,7 @@
*/
public function __construct(){
$this->modules = json_decode( file_get_contents(self::config_path()), true);
$this->packages = json_decode( file_get_contents(self::config_path()), true);
}
@ -29,7 +29,7 @@
*
*/
public function init(){
$this->modules['enabled'] = [];
$this->packages['installed'] = [];
$this->store();
return true;
@ -37,135 +37,113 @@
/* RETURNS AVAILABLE MODULE LIST
*
* @return modules<Array> Set containing modules and their versions
* @return packages<Array> Set containing packages and their versions
*
*/
public function available(){
$modules = [];
$packages = [];
foreach($this->modules['available'] as $module=>$versions){
$modules[$module] = [];
foreach($this->packages['available'] as $package=>$versions){
$packages[$package] = [];
foreach($versions as $version=>$dependencies)
// if version of module enabled
if( isset($this->modules['enabled'][$module]) && $version == $this->modules['enabled'][$module] )
$modules[$module][] = [ 'version' => $version, 'enabled' => true ];
// if version of package enabled
if( isset($this->packages['installed'][$package]) && $version == $this->packages['installed'][$package] )
$packages[$package][] = [ 'version' => $version, 'enabled' => true ];
else
$modules[$module][] = [ 'version' => $version, 'enabled' => false ];
$packages[$package][] = [ 'version' => $version, 'enabled' => false ];
}
return $modules;
return $packages;
}
/* ENABLES A MODULE'S VERSION
*
* @pModule<String> Module's name
* @pVersion<String> Module's version
* @pPackage<String> Package's name
* @pVersion<String> Package's version
* @pDep<Boolean> dependency level
*
* @return err_msg<String> Error message | TRUE (if all is ok)
*
*/
public function enable($pModule=null, $pVersion=null, $pDep=0){
public function install($pPackage=null, $pVersion=null, $pDep=0){
/* [1] Module management
/* [1] Package management
=========================================================*/
/* (1) If @module not given, exit */
if( is_null($pModule) )
return "Missing @moduleName.\n";
/* (1) If @package not given, exit */
if( is_null($pPackage) )
return "Missing @packageName.\n";
/* (2) Checking module existence */
if( !isset($this->modules['available'][$pModule]) )
return "Module `$pModule` unknown.\n";
/* (2) Checking package existence */
if( !isset($this->packages['available'][$pPackage]) )
return "Package `$pPackage` unknown.\n";
/* (3) Set module name & content */
$mname = $pModule;
$module = $this->modules['available'][$mname];
/* (3) Set package name & content */
$mname = $pPackage;
$package = $this->packages['available'][$mname];
/* [2] Version management
=========================================================*/
/* (1) Set default version name & content */
$vname = array_slice( array_keys($module), -1 )[0];
$version = $module[$vname];
/* (1) Set default latest version name & content */
$vname = array_slice( array_keys($package), -1 )[0];
$dependencies = $package[$vname];
$flag = '#latest';
/* (2) If wrong version given, set to default */
if( is_null($pVersion) || !isset($module[$pVersion]) )
echo "chosing latest version:\n-----------------------\n [x] $mname:$vname (can throw errors)\n\n";
/* (2) Else, we get given @version */
else
$version = $module[( $vname = $pVersion )];
/* (2) Existing version set it */
if( !is_null($pVersion) && isset($package[$pVersion]) ){
$dependencies = $package[( $vname = $pVersion )];
$flag = '';
}
/* [3] Enables module & version
/* [3] Enables package & version
=========================================================*/
/* (1) If module disabled -> enables it */
if( !isset($this->modules['enabled'][$mname]) )
$this->modules['enabled'][$mname] = '0';
/* (1) If package disabled -> enables it */
if( !isset($this->packages['installed'][$mname]) )
$this->packages['installed'][$mname] = '0';
/* (3) Checks cross version dependency -> trying to enable lower-than-required version of a module*/
$crossDep = false;
/* (2) Checks cross version dependency -> if another installed package needs another version */
foreach($this->packages['installed'] as $xPackage=>$xVersion){
// For each available module
foreach($this->modules['enabled'] as $xModule=>$xVersion){
// {2.1} Loads each installed package's dependencies //
$xDependencies = $this->getDependencies($xPackage,$xVersion);
// Loads each module's dependencies
if( !isset($this->modules['available'][$xModule][$xVersion]) )
// if not found -> next
if( $xDependencies === false )
continue;
$xDependencies = $this->modules['available'][$xModule][$xVersion];
// if module needs a higher version of current module
if( isset($xDependencies[$mname]) && $this->lower($this->modules['available'][$mname], $vname, $xDependencies[$mname]) ){
$crossDep = true;
break;
}
// {2.2} if package can't have version of current package //
if( isset($xDependencies[$mname]) && !in_array($vname, $xDependencies[$mname]) )
return str_repeat(" ", $pDep)."$xPackage:$xVersion doesn't support $mname:$vname\n\n** aborted **\n";
}
/* (4) If trying to load lower than required version -> error */
if( $crossDep ){
// Update module's version
if( $this->lower($this->modules['available'][$mname], $this->modules['enabled'][$mname], $xDependencies[$mname]) )
$this->modules['enabled'][$mname] = $xDependencies[$mname];
$this->store();
return "module `$xModule:$xVersion` needs `$mname:".$xDependencies[$mname]."`\n\naborted.\n";
}
/* (5) If not a dependency or higher version -> set/update version */
if( $pDep == 0 || $this->lower($module, $this->modules['enabled'][$mname], $vname) ){
// if a dependency, set new params
if( $pDep > 0 )
echo str_repeat(" ", $pDep)."[x] $mname:$vname ($mname:$vname+ required)\n";
else
echo str_repeat(" ", $pDep)."[x] $mname:$vname\n";
// in any case -> store new module's version
$this->modules['enabled'][$mname] = $vname;
}else if( $pDep > 0 )
echo str_repeat(" ", $pDep)."[x] $mname:".$this->modules['enabled'][$mname]." ($mname:$vname+ required)\n";
/* (5) If no conflict -> set version */
echo str_repeat(" ", $pDep)."[$mname:$vname] $flag\n";
// in any case -> store new package's version
$this->packages['installed'][$mname] = $vname;
/* [4] Loading dependencies
=========================================================*/
/* (1) Loading each dependency */
if( count($version) > 0 ){
if( count($dependencies) > 0 ){
echo "\n".str_repeat(" ", $pDep);
echo "dependencies:\n";
foreach($dependencies as $depMod=>$depVersions){
foreach($version as $depMod=>$depVer)
$enabled = $this->enable($depMod, $depVer, $pDep+1);
// Only load last version
foreach($depVersions as $version)
$installed = $this->install($depMod, $version, $pDep+1);
// error propagation
if( $installed !== true )
return $installed;
}
}
@ -179,48 +157,48 @@
/* DISABLES A MODULE'S VERSION
*
* @pModule<String> Module's name
* @pPackage<String> Package's name
*
* @return err_msg<String> Error message || TRUE if success
*
*/
public function disable($pModule=null){
/* [1] Module management (existence)
public function remove($pPackage=null){
/* [1] Package management (existence)
=========================================================*/
/* (1) If @module not given, exit */
if( is_null($pModule) )
return "Missing @moduleName.\n";
/* (1) If @package not given, exit */
if( is_null($pPackage) )
return "Missing @packageName.\n";
/* (2) Checking if module is enabled */
$enabled_modules = array_keys($this->modules['enabled']);
if( !in_array($pModule, $enabled_modules) )
return "Module `$pModule` not enabled.\n";
/* (2) Checking if package is enabled */
$enabled_packages = array_keys($this->packages['installed']);
if( !in_array($pPackage, $enabled_packages) )
return "Package `$pPackage` not enabled.\n";
/* (3) Set module name & content */
$mname = $pModule;
$module = $this->modules['enabled'][$mname];
/* (3) Set package name & content */
$mname = $pPackage;
$package = $this->packages['installed'][$mname];
/* [2] Dependency verification (not needed)
=========================================================*/
$dependency = false; // if it's a dependency of another enabled module
$callers = []; // list of enabled modules that needs current one
$dependency = false; // if it's a dependency of another enabled package
$callers = []; // list of enabled packages that needs current one
/* (1) For each enabled module (excepted itself) */
foreach($enabled_modules as $module){
/* (1) For each enabled package (excepted itself) */
foreach($enabled_packages as $package){
// except current module
if( $module == $mname ) continue;
// except current package
if( $package == $mname ) continue;
/* (2) For each version of its module (and its dependencies) */
foreach($this->modules['available'][$module] as $version=>$dependencies){
/* (2) For each version of its package (and its dependencies) */
foreach($this->packages['available'][$package] as $version=>$dependencies){
// if not the current enabled module's version
if( $version != $this->modules['enabled'][$module] )
// if not the current enabled package's version
if( $version != $this->packages['installed'][$package] )
continue;
/* (3) If current module in dependencies -> can't disable */
isset($dependencies[$mname]) && ($dependency = true) && ($callers[] = "`$module`");
/* (3) If current package in dependencies -> can't disable */
isset($dependencies[$mname]) && ($dependency = true) && ($callers[] = "`$package`");
}
@ -228,13 +206,13 @@
/* (4) If a dependency, explain */
if( $dependency )
return "Cannot disable module $mname because ".implode(',',$callers)." needs it.\n";
return "Cannot disable package $mname because ".implode(',',$callers)." needs it.\n";
/* [3] Disabling module
/* [3] Disabling package
=========================================================*/
/* (1) Disabling module */
unset($this->modules['enabled'][$mname]);
/* (1) Disabling package */
unset($this->packages['installed'][$mname]);
/* (2) Storing changes */
$this->store();
@ -254,7 +232,7 @@
*
*/
public function build($pPath){
$builder = new Builder($pPath, $this->modules['enabled']);
$builder = new Builder($pPath, $this->packages['installed']);
$builder->build();
}
@ -263,41 +241,43 @@
/* CHECKS IF @pFirst IS LOWER THAN @pSecond VERSION
/* RETURNS THE LIST OF THE DEPENDENCIES OF A MODULE
*
* @pModule<Array> Module's content
* @pFirst<String> First version
* @pSecond<String> Second version
* @package<String> Package's label
* @version<String> Package's version
*
* @return lower<Boolean> Returns if @pFirst is lower
*
* Note: Supposing that @pFirst and @pSecond are keys of @pModule (no check)
* @return dependencies<Array> List of dependencies
* FALSE if error
*
*/
public function lower($pModule, $pFirst, $pSecond){
/* (1) Get @pModule keys */
$keys = array_keys($pModule);
private function getDependencies($package=null, $version=null){
/* [1] Search for package
=========================================================*/
/* (1) Checks package */
if( !isset($this->packages['available'][$package]) )
return false;
/* (1) Get @pFirst index */
$pf_index = array_search($pFirst, $keys);
/* (2) Checks version */
if( !isset($this->packages['available'][$package][$version]) )
return false;
/* (2) Get @pSecond index */
$ps_index = array_search($pSecond, $keys);
/* [2] Returns dependencies
=========================================================*/
/* (1) If not an array */
if( !is_array($this->packages['available'][$package][$version]) )
return [];
if( $pf_index === false )
return true;
return $pf_index < $ps_index;
/* (2) If all right */
return $this->packages['available'][$package][$version];
}
/* STORES DATA
*
*/
public function store(){
file_put_contents(self::config_path(), json_encode($this->modules, JSON_PRETTY_PRINT));
file_put_contents(self::config_path(), json_encode($this->packages, JSON_PRETTY_PRINT));
}
}

View File

@ -15,14 +15,14 @@
return;
}
/* (2) Load module's config */
/* (2) Load package's config */
$exporter = new Exporter();
/* [2] Commands
=========================================================*/
switch($arguments[0]){
/* (0) Reset enabled modules
/* (0) Reset enabled packages
---------------------------------------------------------*/
case 'init': {
@ -32,37 +32,37 @@
} break;
/* (1) Modules listing
/* (1) Packages listing
---------------------------------------------------------*/
case 'modules': {
case 'packages': {
echo "available modules:\n";
$modules = $exporter->available();
echo "available packages:\n";
$packages = $exporter->available();
foreach($modules as $module=>$versions){
foreach($packages as $package=>$versions){
foreach($versions as $version)
// if enabled
if( $version['enabled'] )
echo " [x] $module (version ".$version['version'].")\n";
echo " [*] $package:".$version['version']."\n";
else
echo " [ ] $module (version ".$version['version'].")\n";
echo " [ ] $package:".$version['version']."\n";
echo "\n";
}
} break;
/* (2) Enables a module and its version
/* (2) Enables a package and its version
---------------------------------------------------------*/
case 'install': {
if( $arglen < 2 || !preg_match("/^(.+):([0-9\.-]+)$/i", $arguments[1], $matches) ){
echo "You must specify @module:@version.\n";
if( $arglen < 2 || !preg_match("/^([^:]+)(:(?:[0-9\.-]+))?$/i", $arguments[1], $matches) ){
echo "You must specify @package:@version.\n";
return;
}
$err = $exporter->enable($matches[1], $matches[2]);
$err = $exporter->install($matches[1], count($matches) > 2 ? substr($matches[2], 1) : null);
/* (1) Managing state */
if( $err === true ) echo "\n\n** success **\n";
@ -70,16 +70,16 @@
} break;
/* (3) Disabled a module
/* (3) Disabled a package
---------------------------------------------------------*/
case 'remove': {
if( $arglen < 2 ){
echo "You must specify @module.\n";
echo "You must specify @package.\n";
return;
}
$err = $exporter->disable($arguments[1]);
$err = $exporter->remove($arguments[1]);
/* (1) Managing state */
if( $err === true ) echo "\n\n** success **\n";

View File

@ -1,45 +0,0 @@
{
"available": {
"error": {
"1.0": [],
"2.0": []
},
"api": {
"1.0": {
"error": "1.0"
},
"2.0": {
"error": "2.0"
}
},
"orm": {
"0.8.1": {
"database": "1.0"
},
"0.8.2": {
"database": "2.0"
}
},
"database": {
"1.0": {
"error": "1.0"
},
"2.0": {
"error": "2.0"
}
},
"lightdb": {
"1.0": []
},
"router": {
"1.0": []
}
},
"enabled": {
"orm": "0.8.2",
"database": "2.0",
"error": "2.0",
"api": "2.0",
"router": "1.0"
}
}

58
exporter/packages.json Normal file
View File

@ -0,0 +1,58 @@
{
"available": {
"error": {
"1.0": [],
"2.0": []
},
"api": {
"1.0": {
"error": [
"1.0"
]
},
"2.0": {
"error": [
"2.0"
]
}
},
"orm": {
"0.8.1": {
"database": [
"1.0"
]
},
"0.8.2": {
"database": [
"2.0"
]
}
},
"database": {
"1.0": {
"error": [
"1.0"
]
},
"2.0": {
"error": [
"2.0"
]
}
},
"lightdb": {
"1.0": []
},
"router": {
"1.0": []
}
},
"installed": {
"api": "2.0",
"error": "2.0",
"database": "2.0",
"orm": "0.8.2",
"lightdb": "1.0",
"router": "1.0"
}
}

View File