1
votes

Impossible de quitter une boucle après que toutes les vérifications retournent false

J'ai quelques méthodes qui vérifient la réponse d'une commande et, sur la base de cette réponse, feront autre chose, ou échoueront.

Je l'ai amenée là où elle vérifie la sortie de la commande et renvoie false, puis passe à continuez à exécuter le reste du code.

Voici du code

Updrading 2 containers...
'composer:latest' is at the latest version
'php:7.2-fpm-alpine' is at the latest version
Fake destroy
Fake re-build

Ce qui se passe ici, c'est que upgradeImage exécute le pull et la méthode pull vérifie un tableau d'images Docker et effectue une boucle pour voir si l'image a une nouvelle version. Cela se fait en exécutant la méthode isNewVersion () , qui vérifie le $ buffer pour la sortie et la compare.

Si isNewVersion () renvoie true, il effectuera une boucle et mettra à jour les images.

Si isNewVersion () retourne false, il vous le fait savoir avec un message indiquant qu'il est en place- à ce jour.

Si la méthode renvoie false, je veux que la boucle se termine après TOUTES les vérifications et ne continue pas à exécuter le code dans upgradeImages après $ this-> pull () . Si j'ajoute une exit après la vérification, elle se fermera après la première vérification et ne vérifiera pas le reste de la boucle.

En supposant que j'ai choisi 2 images à mettre à jour et que les deux l'ont fait pas besoin d'être mis à jour, la sortie serait comme ceci:

public function upgradeImages($images)
{
    $this->pull($images);

    echo "Do next method - Fake destroy\n";

    echo "Do next method - Fake re-build\n";
}

public function pull($images)
{
    // Count how many containers will be attempted to be updated
    $countImages = count($images);

    echo("Updrading $countImages containers...");

    foreach ($images as $key => $image) {
        $key = $key + 1;

        // Is there a new version of the image?
        if ($this->isNewVersion($image)) {
            echo("($key/$countImages) Upgrading '$image'");

            $this->docker('pull ' . $image);
        }

        echo("'$image' is at the latest version");
    }
}

public function isNewVersion($image)
{
    $cmdOutput = (new Process($this->docker('pull ' . $image)));
    $cmdOutput->start();

    $cmdOutput->wait(function ($type, $buffer) {
        if (contains($buffer, 'Image is up to date')) {
            return false;
        }

        return true;
    });
}


6 commentaires

Pourriez-vous fournir un exemple de sortie?


Message mis à jour avec une sortie


Je vois, et dans ce cas, le comportement souhaité serait-il de ne pas exécuter la destruction et la reconstruction?


Correct, s'il n'y a pas d'images à mettre à jour, les méthodes de destruction / reconstruction n'ont pas besoin d'être exécutées


Avez-vous envisagé d'écrire votre logique avec ansible au lieu de PHP? Cela pourrait vous faciliter la vie et vous obtiendrez plus ou moins gratuitement l'idempotence. par exemple. l'extraction d'une image via ansible peut être archivée en utilisant le module docker_image décrit ici: docs.ansible.com/ansible/latest/modules/...


Je n'ai pas. Pas quelque chose qui correspond à mon cas d'utilisation, je ne pense pas. Mais merci pour la suggestion


3 Réponses :


1
votes

La méthode upgradeImages peut avoir plus d'une destruction / reconstruction. Au lieu de le faire dans pull , créez une autre méthode qui peut être appelée plusieurs fois. Je l'ai nommé doUpgrade () et je lui passe $ image à mettre à jour.

public function upgradeImages($images)
{
    $this->pull($images);
}

public function doUpgrade($image)
{
    echo "Do next method - Fake destroy\n";
    echo "Do next method - Fake re-build\n";
}

public function pull($images)
{
    // Count how many containers will be attempted to be updated
    $countImages = count($images);

    echo("Updrading $countImages containers...");

    foreach ($images as $key => $image) {
        $key = $key + 1;

        // Is there a new version of the image?
        if ($this->isNewVersion($image)) {
            echo("($key/$countImages) Upgrading '$image'");

            $this->docker('pull ' . $image);

            /* call the destroy/re-build */
            echo("'$image' being upgraded");
            $this->doUpgrade($image);
        }

        echo("'$image' is at the latest version");
    }
}

public function isNewVersion($image)
{
    $cmdOutput = (new Process($this->docker('pull ' . $image)));
    $cmdOutput->start();

    $cmdOutput->wait(function ($type, $buffer) {
        if (contains($buffer, 'Image is up to date')) {
            return false;
        }

        return true;
    });
}


3 commentaires

Cela ne revient-il pas dans la première itération de la boucle foreach , la cassant? Je pense que ce sera mieux si vous déclarez $ ret = false; au début de la fonction, en lui attribuant true uniquement lorsque cela est nécessaire (si l'image est mise à jour), et puis renvoyer return $ ret; en dehors de la boucle foreach , de cette façon vous êtes sûr que ce ne sera vrai que si une image a été mise à jour.


Mais il reviendra. Un retour est un retour, vous ne pouvez pas «annuler» un retour. Je pense toujours que la meilleure approche sera de parcourir le tableau dans la première fonction et d'appeler la fonction suivante à l'intérieur de la boucle à partir de la première fonction.


J'ai essayé cette méthode et cela fonctionne bien - fait ce dont j'ai besoin. Je vais l'examiner davantage et si cela convient à mon objectif, je marquerai comme la meilleure réponse. Bien que cette situation ne soit peut-être pas la meilleure pour quiconque ayant un problème similaire, cela m'a aidé avec le mien! Merci!



1
votes

Quelque chose comme ça?

public function upgradeImages($images)
{
    $imagesUpdated = $this->pull($images);

    if ($imagesUpdated > 0) {
        echo "Do next method - Fake destroy\n";

        echo "Do next method - Fake re-build\n";

    } else {
        // do nothing or explicit call 'exit' if you want
    }


}

public function pull($images)
{
    // Count how many containers will be attempted to be updated
    $countImages = count($images);
    $countUpdated = 0;
    echo("Updrading $countImages containers...");

    foreach ($images as $key => $image) {
        $key = $key + 1;

        // Is there a new version of the image?
        if ($this->isNewVersion($image)) {
            echo("($key/$countImages) Upgrading '$image'");

            $this->docker('pull ' . $image);
            $countUpdated++;
        }

        echo("'$image' is at the latest version");
    }
    return $countUpdated;
}

public function isNewVersion($image)
{
    $cmdOutput = (new Process($this->docker('pull ' . $image)));
    $cmdOutput->start();

    $cmdOutput->wait(function ($type, $buffer) {
        if (contains($buffer, 'Image is up to date')) {
            return false;
        }

        return true;
    });
}


1 commentaires

Cette façon a fonctionné pour moi et j'aime ça. Je vais creuser davantage et voir si cela convient. Merci d'avoir contribué!



1
votes

En fonction de votre problème (impossible de quitter une boucle après que toutes les vérifications aient renvoyé false) Si vous souhaitez arrêter l'exécution si elle répond à vos exigences dans les conditions, vous pouvez la forcer à l'arrêter en utilisant Break;

Vérifiez pour plus d'informations https://www.php.net/manual/en/control- structures.break.php


1 commentaires

J'ai essayé ça. Il semblait que peu importe où je l'ai mis, cela ne fonctionnait pas. Peut-être avez-vous des exemples de meilleur cas d'utilisation?