Changeset 99168 in spip-zone


Ignore:
Timestamp:
Aug 14, 2016, 3:14:48 PM (3 years ago)
Author:
marcimat@…
Message:

Amélioration de l'analyse de l'ordre des actions à réaliser (ticket : https://core.spip.net/issues/3689)

Lorsqu'un plugin A dépend de B, et B dépend de C, et qu'on désactive ou active les 3 plugins en même temps,
le placement pouvait être incorrect, car A n'avait pas connaissance directement de sa dépendance à C,
et C n'avait pas directement connaissance d'être dépendant de A. On se limitait à 1 niveau n'analyse.

Du coup, on complète la description d'un paquet et de ses dépendances avec la liste des dépendances
complètes que l'on connait pour les paquets qui font partie du lot d'actions à traiter (si A dépend de D,
mais que D ne fait pas partie des paquets à activer ou enlever, on s'en fiche). Ainsi, pour chaque paquet,
dans l'Actionneur, on a une entrée 'dp' (dépendances préfixes) qui liste tous les préfixes des plugins nécessités, avec leurs descendances
(jusqu'à 10 générations, ça devrait suffire). Inversement on a une entrée 'dmp' (dépendent de moi préfixes) qui liste
les préfixes des plugins actionnés qui dépendent de moi.

Avec ces 2 listes, on peut améliorer le placement des actions 'on' / 'geton' (activer / télécharger un plugin et l'activer)
et 'off' pour désactiver / désinstaller.

ScolaSPIP ou Soyez Créateurs se téléchargent et téléchargent et activent tous leurs plugins sans erreur d'ordre des dépendances.
De même en désinstallant tout.

Location:
_core_/plugins/svp
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • _core_/plugins/svp/inc/svp_actionner.php

    r93656 r99168  
    250250         */
    251251        public function ordonner_actions() {
     252                $this->log("Ordonner les actions à réaliser");
    252253                // nettoyer le terrain
    253254                $this->clear();
    254255
     256                // récupérer les descriptions de chaque paquet
     257                $this->log("> Récupérer les descriptions des paquets concernés");
     258                $infos = array();
    255259                foreach ($this->start as $id => $action) {
    256                         $i = array(); // description du paquet. Ne s'applique pas si librairie ($id = md5)
     260                        // seulement les identifiants de paquets (pas les librairies)
    257261                        if (is_int($id)) {
    258                                 $i = $this->decideur->infos_courtes_id($id);
    259                                 $i = $i['i'][$id];
    260                         }
     262                                $info = $this->decideur->infos_courtes_id($id);
     263                                $infos[$id] = $info['i'][$id];
     264                        }
     265                }
     266
     267                // Calculer les dépendances (nécessite) profondes pour chaque paquet,
     268                // si les plugins en questions sont parmis ceux actionnés
     269                // (ie A dépend de B qui dépend de C => a dépend de B et C).
     270                $infos = $this->calculer_necessites_complets($infos);
     271
     272                foreach ($this->start as $id => $action) {
     273                        // infos du paquet. Ne s'applique pas sur librairie ($id = md5)
     274                        $i = is_int($id) ? $infos[$id] : array();
     275
    261276                        switch ($action) {
    262277                                case 'getlib':
     
    316331
    317332        /**
     333         * Complète les infos des paquets actionnés pour qu'ils contiennent
     334         * en plus de leurs 'necessite' directs, tous les nécessite des
     335         * plugins dont ils dépendent, si ceux ci sont aussi actionnés.
     336         *
     337         * Ie: si A indique dépendre de B, et B de C, la clé
     338         * 'dp' (dépendances prefixes). indiquera les préfixes
     339         * des plugins B et C
     340         *
     341         * On ne s'occupe pas des versions de compatibilité ici
     342         *
     343         * @param array $infos (identifiant => description courte du plugin)
     344         * @return array $infos
     345        **/
     346        public function calculer_necessites_complets($infos) {
     347                $this->log("> Calculer les dépendances nécessités sur paquets concernés");
     348
     349                // prefixe => array(prefixes)
     350                $necessites = array();
     351
     352                // 1) déjà les préfixes directement nécessités
     353                foreach ($infos as $i => $info) {
     354                        if (!empty($info['dn'])) {
     355                                $necessites[$info['p']] = array_map('strtoupper', array_keys($info['dn']));
     356                        }
     357                        // préparer la clé dp (dépendances préfixes) et 'dmp' (dépendent de moi) vide
     358                        $infos[$i]['dp'] = array();
     359                        $infos[$i]['dmp'] = array();
     360                }
     361
     362                if ($nb = count($necessites)) {
     363                        $this->log(">- $nb plugins ont des nécessités");
     364                        // 2) ensuite leurs dépendances, récursivement
     365                        $necessites = $this->calculer_necessites_complets_rec($necessites);
     366
     367                        // 3) intégrer le résultat
     368                        foreach ($infos as $i => $info) {
     369                                if (!empty($necessites[$info['p']])) {
     370                                        $infos[$i]['dp'] = $necessites[$info['p']];
     371                                }
     372                        }
     373
     374                        // 4) calculer une clé 'dmp' : liste des paquets actionnés qui dépendent de moi
     375                        foreach ($infos as $i => $info) {
     376                                $dmp = array();
     377                                foreach ($necessites as $prefixe => $liste) {
     378                                        if (in_array($info['p'], $liste)) {
     379                                                $dmp[] = $prefixe;
     380                                        }
     381                                }
     382                                $infos[$i]['dmp'] = $dmp;
     383                        }
     384                }
     385
     386                return $infos;
     387        }
     388
     389        /**
     390         * Fonction récursive pour calculer la liste de tous les préfixes
     391         * de plugins nécessités par un autre.
     392         *
     393         * Avec une liste fermée connue d'avance des possibilités de plugins
     394         * (ceux qui seront actionnés)
     395         *
     396         * @param array prefixe => liste de prefixe dont il dépend
     397         * @param bool $profondeur
     398         * @return array prefixe => liste de prefixe dont il dépend
     399        **/
     400        public function calculer_necessites_complets_rec($necessites, $profondeur = 0) {
     401                $changement = false;
     402                foreach ($necessites as $prefixe => $liste) {
     403                        $n = count($liste);
     404                        foreach ($liste as $prefixe_necessite) {
     405                                // si un des plugins dépendants fait partie des plugins actionnés,
     406                                // il faut aussi lui ajouter ses dépendances…
     407                                if (isset($necessites[$prefixe_necessite])) {
     408                                        $liste = array_unique(array_merge($liste, $necessites[$prefixe_necessite]));
     409                                }
     410                        }
     411                        $necessites[$prefixe] = $liste;
     412                        if ($n !== count($liste)) {
     413                                $changement = true;
     414                        }
     415                }
     416
     417                // limiter à 10 les successions de dépendances !
     418                if ($changement and $profondeur <= 10) {
     419                        $necessites = $this->calculer_necessites_complets_rec($necessites, $profondeur++);
     420                }
     421
     422                if ($changement and $profondeur > 10) {
     423                        $this->log("! Problème de calcul de dépendances complètes : récursion probable. On stoppe.");
     424                }
     425
     426                return $necessites;
     427        }
     428
     429        /**
    318430         * Ajoute un paquet à activer
    319431         *
     
    345457                // raz des cles pour avoir les memes que $out (utile reellement ?)
    346458                $this->middle['on'] = array_values($this->middle['on']);
    347                 // ajout des dependance
    348                 foreach ($info['dn'] as $dep) {
    349                         $in[] = $dep['nom'];
    350                 }
     459                // ajout des dependances
     460                $in = $info['dp'];
    351461                // $info fourni ses procure
    352462                if (isset($info['procure']) and $info['procure']) {
     
    376486                                }
    377487                        }
    378                         foreach ($inf['dn'] as $dep) {
    379                                 $deps[$inf['p']][] = $dep['nom'];
    380                                 $deps_all[] = $dep['nom'];
    381                         }
     488
     489                        $deps[$inf['p']] = $inf['dp'];
     490                        $deps_all = array_merge($deps_all, $inf['dp']);
    382491                }
    383492
     
    491600                // raz des cles pour avoir les memes que $out (utile reellement ?)
    492601                $this->middle['off'] = array_values($this->middle['off']);
    493                 foreach ($info['dn'] as $dep) {
    494                         $in[] = $dep['nom'];
    495                 }
     602                // in : si un plugin en dépend, il faudra désactiver celui là avant.
     603                $in = $info['dp'];
     604
    496605                foreach ($this->middle['off'] as $inf) {
    497606                        $out[] = $inf['p'];
    498607                }
    499608
    500                 if (!$in) {
     609                if (!$info['dn']) {
    501610                        // ce plugin n'a pas de dependance, on le met en dernier !
    502611                        $this->log("- placer $p tout en bas");
     
    516625                                $this->log("- placer $p avant " . $this->middle['off'][$key]['p']);
    517626                                array_splice($this->middle['off'], $key, 0, array($info));
     627                        // inversement des plugins dépendants de ce plugin sont présents…
     628                        // on le met juste après le dernier
     629                        } elseif ($diff = array_intersect($info['dmp'], $out)) {
     630                                $key = array();
     631                                foreach ($diff as $d) {
     632                                        $key[] = array_search($d, $out);
     633                                }
     634                                $key = max($key);
     635                                $this->log("- placer $p apres " . $this->middle['off'][$key]['p']);
     636                                if ($key == count($this->middle['off'])) {
     637                                        $this->middle['off'][] = $info;
     638                                } else {
     639                                        array_splice($this->middle['off'], $key + 1, 0, array($info));
     640                                }
    518641                        } else {
    519642                                // aucune des dependances n'est a desactiver
     
    521644                                // on le met en premier !
    522645                                $this->log("- placer $p tout en haut");
    523                                 array_unshift($this->middle['off'], $info); // etait ->middle['on'] ?? ...
     646                                array_unshift($this->middle['off'], $info);
    524647                        }
    525648                }
  • _core_/plugins/svp/paquet.xml

    r99161 r99168  
    22        prefix="svp"
    33        categorie="maintenance"
    4         version="1.1.3"
     4        version="1.1.4"
    55        etat="stable"
    66        compatibilite="[3.2.0-dev;]"
Note: See TracChangeset for help on using the changeset viewer.