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

100
README.md
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 #### 1. Build a project
To use the xdrm-framework's project builder, just open a linux terminal and type : To use the xdrm-framework's project builder, just open a linux terminal and type :
1. `xdrm-framework modules` - to display the available modules 1. `./xfw packages` - to display the available modules
2. `xdrm-framework install {moduleName} 1.2` - to enable a module and its version (1.2 here) 2. `./xfw install {packageName}:1.2` - to install a package and its version (1.2 here)
3. `xdrm-framework remove {moduleName}` - to disable a module 3. `./xfw remove {packageName}` - to disable a module
4. `xdrm-framework build {projectRoot}` - will create your project in the folder `{projectRoot}` 4. `./xfw build {projectRoot}` - will create your project in the folder `{projectRoot}`
5. `xdrm-framework init` - to remove all enabled modules 5. `./xfw init` - to remove all enabled modules
#### 2. Project's file structure #### 2. Project's file structure
xdrm-framework is based on `all is in config` so you will have this structure : xdrm-framework is based on `all in config` so you will have this structure :
- folder `build` which contains framework's modules (core + data). - folder `/build` which contains framework's modules (core + data).
- folder `public_html` which contains visible content (html, css, js). - folder `/public_html` which contains visible content (html, css, js).
- folder `config` which contains the modules' config files (mainly json). - folder `/config` which contains the modules' config files (mainly json).
- file `autoloader.php` which will auto-load the components. - 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 : **Note:** In every php file you want to use framework's classes, you have to begin your file by :
```php ```php
<?php <?php
/* [1] load the autoloader with correct path */ /* [1] load the autoloader with correct path */
require_once '../autoloader.php'; require_once '../autoloader.php';
/* [2] then you can load your classes */ /* [2] then you can load your classes */
use api\core\Request; // ex1: api request manager use api\core\Request; // ex1: api request manager
use error\core\Error; // ex2: error manager use error\core\Error; // ex2: error manager
use error\core\Err; // ex3: error codes use error\core\Err; // ex3: error codes
/* [3] and use them as long as you want without namespace */ /* [3] and use them as long as you want without namespace */
$request = new Request('module/method', ['id_user' => 10]); $request = new Request('module/method', ['id_user' => 10]);
$response = $request->dispatch(); $response = $request->dispatch();
if( $response->error->get() === Err::Success ) if( $response->error->get() === Err::Success )
echo "All is going right!\n"; 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: **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. Modules
#### [3.1] API - self-managed API #### 3.1 API - self-managed API
###### How to use ###### 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 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. In order to be understood, lets call `module` a group of methods, and `method` a function which outputs data from input parameters.
**Configuration format** **Configuration format**
```json ```json
{ {
"{module_name}": { "{module_name}": {
"{http_method}::{method_name}": { "{http_method}::{method_name}": {
"description": "{method_description}", "description": "{method_description}",
"permissions": ["{perm}"], "permissions": ["{method_perm}"],
"options": { "download": {is_download} }, "options": { "download": "{is_downloadable}" },
"parameters: { "parameters": {
"{name_param}": { "description": "{desc_param}", "type": "{type_param}", "optional": {is_optional} } "{name_param}": { "description": "{desc_param}", "type": "{type_param}", "optional": "{is_optional}" }
}, },
"output": { "output": {
"{name_output}": { "description": "{desc_output}", "type": "{type_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) ###### Classes (advanced)
The API is managed through 5 classes : The API is managed through 5 classes :

View File

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

View File

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