Commit e3f4e9f5 authored by Laurent Lecluse's avatar Laurent Lecluse
Browse files

Le script d'installation fait maintenant partie du projet

parent 843d9af9
Loading
Loading
Loading
Loading

bin/install

0 → 100644
+619 −0
Original line number Diff line number Diff line
#!/usr/bin/env php
<?php

$c  = new Console();
$c->setInputOptions([
    'version:',
    'config-file:',
    'ose-dir:',
]);

$od = new OseDeploy($c);

$c->printMainTitle("Installation de OSE", 13);
$c->check([
    'git'        => 'Gestionnaire de versions',
    'php'        => 'Langage PHP',
    'wget'       => 'Téléchargement en ligne de commande',
    'unoconv'    => ['description' =>'Convertisseur OpenDocument vers PDF', 'facultatif' => false],
]);

if (!$od->checkPhpModules([
    'curl'         => 'Curl',
    'intl'         => 'Intl',
    'json'         => 'Json',
    'ldap'         => 'Ldap',
    'mbstring'     => 'MbString',
  //  'mcrypt'       => 'MCrypt',
    'Zend OPcache' => 'Zend OPcache',
    'xml'          => 'XML',
    'zip'          => 'ZIP',
    'bcmath'       => 'BCMath',
    'gd'           => 'GD',
    'oci8'         => 'OCI8 (Pilote Oracle)',
])){
    $c->printDie('Un ou plusieurs modules PHP sont manquants. Merci de les installer pour poursuivre l\'installation de OSE');
};

// Mise en place de la clé SSH
$c->println("\nTest de connexion au serveur GitLab hébergeant OSE", $c::COLOR_LIGHT_CYAN);
if (!$od->gitlabIsReachable()) {
    $c->printDie($od::OSE_ORIGIN." est inaccessible.");
}else{
    $c->println("URL Gitlab (".$od::OSE_ORIGIN.") accessible", $c::COLOR_LIGHT_GREEN);
}


// Création du dossier
$c->println("\nCréation du dossier et initialisation de GIT", $c::COLOR_LIGHT_CYAN);
$c->print("Veuillez indiquer un nouveau répertoire où implanter OSE: ");
$osedir = $c->getInput('ose-dir');

if (file_exists($osedir)) {
    $c->printDie("Le répertoire $osedir existe déjà. Merci d'en spécifier un nouveau.");
}

$c->exec([
    "mkdir $osedir",
    "cd $osedir",
    "git init",
    "git remote add origin " . $od::OSE_ORIGIN,
    "git fetch --all --tags --prune",
]);


// Choix de la version
$c->println("\nSélection de la version à déployer", $c::COLOR_LIGHT_CYAN);
$c->println("Voici la liste des versions de OSE disponibles:");
$tags = $od->getTags();
foreach ($tags as $tag) {
    $c->println($tag);
}
$ok = false;
while (!$ok) {
    $c->print("Veuillez choisir une version à déployer: ");
    $version = $c->getInput('version');
    if ($od->tagIsValid($version)) {
        $ok = true;
    } else {
        $c->println("$version n'est pas dans la liste des versions disponibles.");
    }
}


// Récupération des sources
$c->println("\nDéploiement à partir des sources GIT", $c::COLOR_LIGHT_CYAN);
$c->exec([
    "cd $osedir",
    "git checkout tags/$version",
    "mkdir cache",
    "mkdir cache/Doctrine",
    "chmod 777 cache/Doctrine",
    "chmod 777 cache",
    "mkdir log",
    "chmod 777 log",
    "chmod +7 bin/ose",
]);
$od->writeVersion($osedir, $version);


// Récupération de Composer
$c->println("\nRécupération de l'outil de gestion des dépendances Composer", $c::COLOR_LIGHT_CYAN);
$c->passthru("cd $osedir;wget https://getcomposer.org/composer.phar");

// Récupération des dépendances
$c->println("\nChargement des dépendances à l'aide de Composer", $c::COLOR_LIGHT_CYAN);
$c->passthru("cd $osedir;php composer.phar install");


// Mise à jour des liens vers les répertoires publics des dépendances
$c->println("\nMise à jour des liens vers les répertoires publics des dépendances", $c::COLOR_LIGHT_CYAN);
$od->majUnicaenSymLinks($osedir);
$c->println('Liens mis en place', $c::COLOR_LIGHT_GREEN);

// Configuration locale
//$c->println("\nMise en place de la base de données", $c::COLOR_LIGHT_CYAN);
//$c->println("\nUne base de données Oracle doit préalablement avoir été créée. Merci de fournir dès à présent ses"
//." paramètres d'accès pour que OSE initialialise la base de données :");

$configFile = $c->getOption('config-file');
if ($configFile && !file_exists($configFile)){
    $configFile = getcwd().'/'.$configFile;
}
if ($configFile && !file_exists($configFile)){
    $c->println("Le fichier de configuration $configFile est introuvable. A sa place, un nouveau fichier de configuration ser créé sur la base de celui par défaut.");
    $configFile = null;
}
if ($configFile){
    $configFile = realpath($configFile);
}else{
    $configFile = $osedir.'/config.local.php.default';
}
copy($configFile, $osedir.'/config.local.php');


// Génération des proxies pour l'ORM Doctrine
$c->println("\nGénération des proxies pour l'ORM Doctrine", $c::COLOR_LIGHT_CYAN);
$c->exec([
    "cd $osedir",
    "php vendor/bin/doctrine-module orm:generate-proxies",
    "chmod -R 777 cache/DoctrineProxy",
]);

// Mise en place des tâches CRON ??

// Conclusion
$c->println("\nFin du script d'installation des fichiers", $c::COLOR_LIGHT_GREEN);
$c->println("Il reste encore plusieurs étapes à réaliser pour que OSE soit pleinement fonctionnel :");
$c->println(" 1 - Configurez votre serveur Apache");
$c->println(" 2 - Initialisez la base de données de OSE à l'aide du script prévu à cet effet");
$c->println(" 3 - Mettez en place la configuration locale de l'application, si ce n'est déjà le cas");
$c->println(" 4 - Une fois bien connecté, configurez vos connecteurs en vous appuyant\n     le cas échéant sur ceux qui vous sont fournis");
$c->println(" 5 - Mettez en place les tâches CRON nécessaires (envoi de mails pour les indicateurs, Synchronisation automatique, etc.");
$c->println(" 6 - Paramétrez l'application pour l'adapter à vos besoins");
$c->println('');
$c->println("Pour la suite, merci de vous reporter au guide de l'administrateur pour vous aider à configurer l'application");
$c->println('');
/*
$c->println(" 1 - Configurez le cas échéant votre serveur Apache");
$c->println(" 2 - Veuillez personnaliser le fichier de configuration de OSE config.local.php, si ce n'est déjà le cas");
$c->println(" 3 - La base de données devra au besoin être initialisée à l'aide de la commande ./bin/ose install-bdd");
$c->println(" 4 - Mettez en place les tâches CRON nécessaires (envoi de mails pour les indicateurs, Synchronisation automatique, etc.");
*/


/************************************************************
 *                      Classes utiles                      *
 ************************************************************/
class OseDeploy
{
    const OSE_ORIGIN = 'https://git.unicaen.fr/open-source/OSE';

    /**
     * @var Console
     */
    protected $console;

    /**
     * @var array
     */
    private $tags = false;



    /**
     * OseDeploy constructor.
     *
     * @param Console $console
     */
    public function __construct(Console $console)
    {
        $this->console = $console;
    }



    public function majUnicaenSymLinks($oseDir): bool
    {
        if (substr($oseDir, -1) !== '/') {
            $oseDir .= '/';
        }

        $oldLibs = [];
        $od      = array_filter(glob($oseDir . 'public/vendor/unicaen/*'), 'is_dir');
        foreach ($od as $dir) {
            $oldLibs[] = basename($dir);
        }

        $newLibs = [];
        $nd      = array_filter(glob($oseDir . 'vendor/unicaen/*'), 'is_dir');
        foreach ($nd as $dir) {
            if (is_dir($dir . '/public')) {
                $newLibs[] = basename($dir);
            }
        }

        $deleteLibs = array_diff($oldLibs, $newLibs);
        $createLibs = array_diff($newLibs, $oldLibs);

        foreach ($deleteLibs as $lib) {
            $command = "rm $oseDir"."public/vendor/unicaen/$lib";
            $this->console->print($command);
            $this->console->exec($command);
        }

        foreach ($createLibs as $lib) {
            $command = "cd $oseDir"."public/vendor/unicaen;ln -sf ../../../vendor/unicaen/$lib/public $lib";
            $this->console->print($command);
            $this->console->exec($command);
        }

        return !(empty($deleteLibs) && empty($createLibs));
    }




    public function checkPhpModules(array $modules)
    {
        $len = 60;
        $result = true;

        $this->console->println("Contrôle d'existance des modules PHP nécessaires", $this->console::COLOR_LIGHT_CYAN);
        $this->console->println($this->console->strPad('Module PHP', $len) . "Résultat");
        $this->console->println($this->console->strPad('----------', $len) . "--------");
        foreach ($modules as $module => $description) {
            $return = null;
            $passed = in_array($module, get_loaded_extensions());

            $this->console->print($this->console->strPad($description, $len));
            if ($passed) {
                $this->console->println('Module trouvé', $this->console::COLOR_LIGHT_GREEN);
            } else {
                $this->console->println('Module manquant', $this->console::COLOR_LIGHT_RED);
            }

            if (!$passed) $result = false;
        }

        return $result;
    }



    public function gitlabIsReachable(): bool
    {
        exec("git ls-remote --heads " . self::OSE_ORIGIN, $gitCheck );

        return (false !== strpos(implode(' ', $gitCheck), 'heads/master'));
    }



    public function getTags(): array
    {
        if (false === $this->tags) {
            $this->tags = [];

            $ts = $this->console->exec("git ls-remote --tags --refs " . self::OSE_ORIGIN, false);
            foreach ($ts as $tag) {
                $this->tags[] = substr($tag, strpos($tag, 'refs/tags/') + 10);
            }
        }

        $minVersion = 8;
        foreach ($this->tags as $i => $tag) {
            $version = (int)substr($tag, 0, strpos($tag, '.'));
            if ($version < $minVersion) unset($this->tags[$i]);
        }

        return $this->tags;
    }



    /**
     * @param string $tag
     *
     * @return bool
     */
    public function tagIsValid(string $tag): bool
    {
        return in_array($tag, $this->getTags());
    }



    public function currentVersion(string $osedir): string
    {
        $vf = $this->getVersionFile($osedir);
        if (!file_exists($vf)) {
            return 'inconnue';
        }

        return file_get_contents($vf);
    }



    public function writeVersion(string $osedir, string $version)
    {
        $vf = $this->getVersionFile($osedir);
        file_put_contents($vf, $version);
    }



    private function getVersionFile(string $osedir): string
    {
        if ('/' == substr($osedir, -1)) {
            return $osedir . 'VERSION';
        } else {
            return $osedir . '/VERSION';
        }
    }
}





class Console
{
    const COLOR_BLACK        = '0;30';
    const COLOR_DARK_GRAY    = '1;30';
    const COLOR_BLUE         = '0;34';
    const COLOR_LIGHT_BLUE   = '1;34';
    const COLOR_GREEN        = '0;32';
    const COLOR_LIGHT_GREEN  = '1;32';
    const COLOR_CYAN         = '0;36';
    const COLOR_LIGHT_CYAN   = '1;36';
    const COLOR_RED          = '0;31';
    const COLOR_LIGHT_RED    = '1;31';
    const COLOR_PURPLE       = '0;35';
    const COLOR_LIGHT_PURPLE = '1;35';
    const COLOR_BROWN        = '0;33';
    const COLOR_YELLOW       = '1;33';
    const COLOR_LIGHT_GRAY   = '0;37';
    const COLOR_WHITE        = '1;37';

    const BG_BLACK      = '40';
    const BG_RED        = '41';
    const BG_GREEN      = '42';
    const BG_YELLOW     = '43';
    const BG_BLUE       = '44';
    const BG_MAGENTA    = '45';
    const BG_CYAN       = '46';
    const BG_LIGHT_GRAY = '47';

    /**
     * @var array
     */
    protected $inputOptions = false;

    /**
     * @var array
     */
    protected $options=false;



    public function check(array $prerequis)
    {
        $len = 60;
        $res = true;

        $this->println("Contrôle des prérequis à l'exécution du script", self::COLOR_LIGHT_CYAN);
        $this->println($this->strPad('Commande (description éventuelle)', $len) . "Résultat");
        $this->println($this->strPad('----------------------', $len) . "--------");
        foreach ($prerequis as $command => $desc) {
            if (is_array($desc)) {
                extract($desc);
            } else {
                $description = $desc;
                $facultatif  = false;
            }

            $return = null;
            exec('command -v ' . $command, $null, $result);
            $passed = ($result == 0);

            $this->print($this->strPad($command . ($description ? " ($description)" : ''), $len));
            if ($passed) {
                $this->println('Commande trouvée', self::COLOR_LIGHT_GREEN);
            } elseif ($facultatif) {
                $this->println('Manquante, facultative', self::COLOR_LIGHT_PURPLE);
            } else {
                $this->println('Commande manquante', self::COLOR_LIGHT_RED);
                $res = false;
            }
        }

        if (!$res) {
            $this->printDie('Un ou plusieurs prérequis nécessaires ne sont pas présents sur cette machine. Merci de les installer avant de poursuivre l\'installation.');
        }

        return $res;
    }



    public function printMainTitle($title, $spaces = 1)
    {
        $pstr = str_repeat(' ', $spaces);
        $t    = $pstr . $title . $pstr;

        $len = mb_strlen($t);

        echo '╔' . str_repeat('═', $len) . "╗\n";
        echo '║' . str_repeat(' ', $len) . "║\n";
        echo "║" . $t . "║\n";
        echo '║' . str_repeat(' ', $len) . "║\n";
        echo '╚' . str_repeat('═', $len) . "╝\n\n";
    }



    public function print($text, $color = null, $bgColor = null)
    {
        if ($bgColor) $bgColor = ';' . $bgColor;

        if (!$color && !$bgColor) {
            echo $text;
        } else {
            echo "\e[$color$bgColor" . "m$text\e[0m";
        }
    }



    public function println($text, $color = null, $bgColor = null)
    {
        $this->print($text, $color, $bgColor);
        echo "\n";
    }



    public function gestExitCode($code)
    {
        if (0 == $code) return;

        $this->printDie("Une erreur ($code) est survenue. Le script est stoppé");
    }



    public function printDie($text)
    {
        $this->println($text, self::COLOR_LIGHT_RED);
        $this->println(' -- FIN Prématurée de l\'exécution du script -- ', null, self::BG_RED);
        die("\n");
    }



    public function getArg($index = null)
    {
        $args = isset($_SERVER['argv']) ? $_SERVER['argv'] : [];

        if (null === $index) return $args;

        if (isset($args[$index])) {
            return $args[$index];
        } else {
            return null;
        }
    }



    /**
     * @return array
     */
    public function getInputOptions(): array
    {
        return $this->inputOptions;
    }



    /**
     * @param array $inputOptions
     */
    public function setInputOptions(array $inputOptions)
    {
        $this->inputOptions = $inputOptions;
    }



    public function getOption(string $option)
    {
        if (!is_array($this->options)){
            if (is_array($this->inputOptions)){
                $this->options = getopt('', $this->inputOptions);
            }else{
                return null;
            }
        }

        if (isset($this->options[$option])){
            return $this->options[$option];
        }else{
            return null;
        }
    }



    public function getInput($option=null)
    {
        if ($option){
            $optionParam = $this->getOption($option);
            if (null !== $optionParam){
                $this->println($optionParam);
                return $optionParam;
            }
        }

        return trim(fgets(STDIN));
    }



    public function getSilentInput($option=null)
    {
        if ($option){
            $optionParam = $this->getOption($option);
            if (null !== $optionParam){
                return $optionParam;
            }
        }

        if (preg_match('/^win/i', PHP_OS)) {
            $vbscript = sys_get_temp_dir() . 'prompt_password.vbs';
            file_put_contents(
                $vbscript, 'wscript.echo(InputBox("'
                . addslashes('')
                . '", "", "password here"))');
            $command  = "cscript //nologo " . escapeshellarg($vbscript);
            $password = rtrim(shell_exec($command));
            unlink($vbscript);

            return $password;
        } else {
            $command = "/usr/bin/env bash -c 'echo OK'";
            if (rtrim(shell_exec($command)) !== 'OK') {
                trigger_error("Can't invoke bash");

                return;
            }
            $command  = "/usr/bin/env bash -c 'read -s -p \""
                . addslashes('')
                . "\" mypassword && echo \$mypassword'";
            $password = rtrim(shell_exec($command));
            echo "\n";

            return $password;
        }
    }



    public function exec($command, $autoDisplay = true)
    {
        if (is_array($command)) {
            $command = implode(';', $command);
        }

        exec($command, $output, $return);
        if ($autoDisplay) {
            echo implode("\n", $output) . "\n";
        }
        $this->gestExitCode($return);

        return $output;
    }



    public function passthru($command)
    {
        if (is_array($command)) {
            $command = implode(';', $command);
        }

        passthru($command, $returnVar);
        $this->gestExitCode($returnVar);

        return $returnVar;
    }



    public function strPad($input, $padLength = null, $padString = ' ')
    {
        return utf8_encode(str_pad(utf8_decode($input), $padLength, $padString));
    }
}