Journal bout de code pour relancer une commande dans certaines conditions

Posté par . Licence CC by-sa.
Tags :
6
22
avr.
2020

J'avais besoin d'un truc pour relancer une commande au plus un certain nombre de fois et attendre un certain temps entre deux exécution pour une bricole, alors j'ai pondu ça. Ça aurait pu me prendre 5 lignes de shell, mais c'est le genre de trucs que j'aime bien avoir sous le $PATH, et implémenter ça en vrai shell me semblais un peu du gâchis (à noter, ça existe)

J'ai fait quelques tests rapides, ça semble marcher, je pousserai plus demain pour voir si ça s'intègre bien dans mes scripts, en attendant je vous passe le source, dès fois que j'oublie alors que ça aurait pu servir a quelqu'un…

//Copyright 2020
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.

//to build:
//cc retry.c -o retry

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/unistd.h>
#include <errno.h>
#include <limits.h>

#define VERSION "0.1.0"

#define CHECK_ERR() \
    do {\
        if( errno ){ \
            fprintf( stderr, "[%d]: %s\n", __LINE__, strerror( errno ) ); \
            return EXIT_FAILURE; \
        }\
    } while( 0 )

#define INT_ARG( ival ) \
    do {\
        ival = strtoul( val, &endptr, 0 );\
        if( ival > INT_MAX || *endptr )\
        { \
            fputs( "invalid " #ival " value\n", stderr );\
            return EXIT_FAILURE;\
        } \
        CHECK_ERR();\
    } while( 0 )

int run_cmd( unsigned int time, unsigned int tsleep, char** cmd );
int print_bad_opt( char const* opt );
int print_version( void );
int print_help( int ret );

int main( int argc, char** argv )
{
    unsigned long count  = 0;
    unsigned long pause_time = 0;
    unsigned long sleep_time = 0;

    char** arg = argv;
    char** cmd = argv + argc;
    char* endptr = 0;
    while( *arg )
    {
        ++arg;
        if( !*arg || ( *arg && **arg != '-' ) )
        {
            return print_bad_opt( *arg );
        }
        char opt = (*arg)[1];
        char* val = &(*arg)[2];
        switch( opt )
        {
            case '-':
                cmd = arg + 1;
                arg = argv + argc;
                break;
            case 'v':
                return print_version();
            case 'h':
                return print_help( EXIT_SUCCESS );
            case 's':
                INT_ARG( sleep_time );
                val = endptr;
                break;
            case 't':
                INT_ARG( pause_time );
                val = endptr;
                break;
            case 'c':
                INT_ARG( count );
                val = endptr;
                break;
            default:
                return print_bad_opt( *arg );
        }
    }
    if( !( *cmd ) )
    {
        return print_help( EXIT_FAILURE );
    }

    if( count == 0 )
    {
        while( run_cmd( (unsigned)pause_time, (unsigned)sleep_time, cmd ) )
        {
        }
        return EXIT_SUCCESS;
    }

    for( ; count && run_cmd( (unsigned)pause_time, (unsigned)sleep_time, cmd ); --count )
    {
    }
    return count ? EXIT_SUCCESS : EXIT_FAILURE;
}

int run_cmd( unsigned int time, unsigned int tsleep, char** cmd )
{
    sleep( tsleep );
    int status;
    switch( fork() )
    {
        case 0:
            alarm( time );
            execvp( *cmd, cmd );
        case -1:
            CHECK_ERR();
            break;
        default:
            break;
    }
    pid_t child = wait( &status );
    return child != -1 ? WEXITSTATUS( status ) : -1;
}

int print_bad_opt( char const* opt )
{
    fprintf( stderr, "Unknown option: %s\n", opt );
    return print_help( EXIT_FAILURE );
}

int print_version( void )
{
    fputs( VERSION "\n", stderr );
    return EXIT_SUCCESS;
}

int print_help( int ret )
{
    fputs( "retry [OPTIONS] -- command arguments\n"
            "\trun a command until it returns successfully.\n"
            "\t\n"
            "\tOptions:\n"
            "\t-v: print the version number of this program\n"
            "\t-h: print this screen\n"
            "\t-tTIME: if the command didn't return in TIME seconds, sends it SIGARLM. 0 means no limit.\n"
            "\t-cCOUNT: try running the command up to COUNT times. 0 means no limit.\n"
            "\t-sTIME: waits TIME seconds before executing command. 0 is invalid.\n"
            , ret == EXIT_FAILURE ? stderr : stdout );
    return ret;
}

Sur ce, bonne nuit.

PS: si vous préférez mettre la licence en CC-0, ou autre trucs sans prise de tête, faites.

  • # bash

    Posté par . Évalué à 7 (+6/-0).

    Personnellement je fais :

    for i in `seq 3`;do commmande;sleep delai;done

    Mais c'est vrai que c'est du shell bash.

    • [^] # Re: bash

      Posté par . Évalué à 10 (+9/-0).

      J'ajouterai un break pour sortir a la première réussite:

      for i in $(seq 3); do commmande && break; sleep 1; done

      Mais c'est vrai que c'est du shell sh ;).

    • [^] # Re: bash

      Posté par . Évalué à 2 (+0/-0).

      La ou c'est chiant, c'est quand tu as plusieurs fois le même bloc de code avec juste la commande qui change.
      Du coup tu fais une fonction. Sauf que du coup si tu veux être propre faut vérifier les arguments…

      Mais bon, on va pas se mentir: en vrai quand j'avais le nez plongé dans mon shell, c'est plus ou moins ce que j'ai fait:

        cd "${SOCK_PATH}"
        for try in $(seq 1 ${MAX_TRY})
        do  
          $CMD && break
          sleep "${DELAY}"
        done
        $CMD || die "failed to connect to ${SOCK_PATH}/${SOCK_NAME} in ${MAX_TRY} attempts"
        cd -
      • [^] # Re: bash

        Posté par . Évalué à 3 (+2/-0).

        Si t'es le seul a utiliser la fonction t'as pas forcement besoin de tester les arguments.

        En tant que j'y suis, ton code exécute 2 fois $CMD quand la commande marche, les 'cd' servent a rien vu que tu utilise $SOCK_PATH, et die… on sais pas ce que ça fait…

    • [^] # Re: bash

      Posté par . Évalué à 5 (+3/-0).

      Si c'est du bash, alors tu peux éviter la sous-commande:

      for i in {1..3} ;do
  • # systemd

    Posté par . Évalué à 9 (+10/-2). Dernière modification le 22/04/20 à 09:51.

    bonjour,
    tu peux utiliser systemd et les options qui vont bien :

    [Service]
    Type=forking
    PIDFile=/toto/pids/delayed_job.pid
    RemainAfterExit=no
    Restart=on-failure
    RestartSec=50s
    StartLimitInterval=400s
    StartLimitBurst=3

    Mais c'est pas du Shell ni du C…

    • [^] # Re: systemd

      Posté par . Évalué à 3 (+1/-0).

      Oups, mon script se lance en userspace sur un bsd ou un windows… et ce retry, c'est juste une partie d'un tout.

      Systemd a son utilité, mais pas ici. Non, parce que hein, sinon j'aurai utilisé runit.

  • # watch

    Posté par (page perso) . Évalué à 3 (+1/-0).

    Ça serait bien d'ajouter une option à"watch" pour ça … C'est le premier endroit où j'aurai cherché ça.

    • [^] # Re: watch

      Posté par . Évalué à 2 (+0/-0).

      Honnêtement, je n'y avais pas pensé. D'un autre côté pour moi, watch c'est plutôt un truc interactif, un peu comme less: pas un truc que je penserais a utiliser dans un script.

    • [^] # Re: watch

      Posté par . Évalué à 2 (+1/-0).

      On peut toujours le faire, mais ça commence a être vraiment tordu:

      watch -n1 -ec "test $(( $(date +%s) + 30 )) -gt \$(date +%s) && ! command " <<< q
  • # fonction

    Posté par . Évalué à 3 (+1/-0). Dernière modification le 22/04/20 à 13:27.

    Ça aurait pu me prendre 5 lignes de shell, mais c'est le genre de trucs que j'aime bien avoir sous le $PATH

    Pourquoi ne pas en faire une fonction bash dans ton profile?

    D'autant plus que ça le rendrait facile à synchroniser sur toute machine qui récupère ton profile depus un dépot git ou autre, portable et que si tu l'écris en bourne shell pur il est portable sur à peu près tous les unix-likes, même ceux tournant avec busybox, ash ou korn shell et ce sans aucune compilation.

    Là dans le genre j'ai l'impression que tu as sorti un lance-flamme pour alumer une cigarette.

    • [^] # Re: fonction

      Posté par . Évalué à 3 (+1/-0). Dernière modification le 22/04/20 à 13:28.

      Et j'ai oublié de dire, sur n'importe quelle archi de processeur.

    • [^] # Re: fonction

      Posté par . Évalué à 2 (+0/-0).

      Pourquoi ne pas en faire une fonction bash dans ton profile?

      Chiant a distribuer ensuite, de mettre ça dans le fichier .profile. Mais c'set vrai que je devrais me faire une lib d'utilitaire shell, c'est lourd de réimplémenter die() a chaque fois, par exemple (c'est que 5 lignes, hein, mais bon).

      une fonction bash dans ton profile […] facile à synchroniser

      Copier un fichier, c'est copier un fichier… le coller dans le $PATH d'une manière ou d'une autre, que ce soit un binaire ou un shell script, c'est pareil.

      sans aucune compilation.

      Certes. Mais bon… ici, c'est littéralement cc retry.c -o retry pour compiler. Ça ne vaut même pas le coup de faire un makefile…

      Là dans le genre j'ai l'impression que tu as sorti un lance-flamme pour alumer une cigarette.

      Honnêtement, c'est quand j'ai vu le code en bash de 160 lignes qui faisait plus ou moins ça que je me suis motivé a m'amuser. Et je venais de me farcir du shell pendant quelques temps, notamment avec jq (pas mon expérience la plus agréable) du coup le code un peu "bourrin" c'est vrai me démangeais.

      Je voulais voir un peu ce que ça donnerait en C, réputé nécessiter beaucoup plus de lignes que la majorité des autres (bon, si je voulais vraiment jouer au NLOC le plus bas, j'utiliserais pas ce style de formatage, certes).
      Je pensais que ça prendrais un peu plus de lignes à la base en vrai.
      Je n'ai pas implémenté a fonctionnalités égales non plus je sais: le code bash n'implémentais pas la fonctionnalité de timeout (logique, autant se baser sur la commande dédiée), et semble implémenter 2-3 autres trucs dont je n'ai pas trop compris l'intérêt.
      Probablement qu'il peut aussi gérer d'autres unités que les secondes.

      Et j'ai oublié de dire, sur n'importe quelle archi de processeur.

      Hum… je vois pas ou ce bout de code ne serais pas compatible sur toute archi? Selon les manpages, ce code nécessite: POSIX.1-2001 et C89. A vue de nez, c'est l'usage de sleep qui empêcherais l'usage de 4.3BSD, mais ça serait trivial de le remplacer par: usleep( 1000*time).

      Franchement, je doute qu'il existe encore tant d'archi pour lesquelles il n'y ait aucun compilo qui ne supporte pas C89 et POSIX.1-2001, et pour lesquelles un bash soit implémenté (1ère version de bash date de 89 selon wikipedia).

      • [^] # Re: fonction

        Posté par . Évalué à 1 (+0/-0).

        Chiant a distribuer ensuite, de mettre ça dans le fichier .profile. Mais c'set vrai que je devrais me faire une lib d'utilitaire shell, c'est lourd de réimplémenter die() a chaque fois, par exemple (c'est que 5 lignes, hein, mais bon).

        T'as juste a faire source ma_lib.sh, ce qui permet d'aller voir le code plus facilement, pour debugué par exemple.
        Ça fait juste 2 fichiers à distribuer.

        Copier un fichier, c'est copier un fichier… le coller dans le $PATH d'une manière ou d'une autre, que ce soit un binaire ou un shell script, c'est pareil.

        Les dossier du $PATH sont protégé par les droits root, c'est pas parreil.
        Tu sacrifie la portabilité et le sécu de ta machine, juste pour ne pas écrire 3 lignes une fois.

        Honnêtement, c'est quand j'ai vu le code en bash de 160 lignes qui faisait plus ou moins ça que je me suis motivé a m'amuser. Et je venais de me farcir du shell pendant quelques temps, notamment avec jq (pas mon expérience la plus agréable) du coup le code un peu "bourrin" c'est vrai me démangeais.

        160 lignes c'est trop long pour du bash.

        Hum… je vois pas ou ce bout de code ne serais pas compatible sur toute archi? Selon les manpages, ce code nécessite: POSIX.1-2001 et C89. A vue de nez, c'est l'usage de sleep qui empêcherais l'usage de 4.3BSD, mais ça serait trivial de le remplacer par: usleep( 1000*time).

        T'es obligé de compiler pour chaque archi.

        Franchement, je doute qu'il existe encore tant d'archi pour lesquelles il n'y ait aucun compilo qui ne supporte pas C89 et POSIX.1-2001, et pour lesquelles un bash soit implémenté (1ère version de bash date de 89 selon wikipedia).

        Avoir un compilateur sur un système élargit sa surface d'attaque, c'est en partie pour ça qu'il n'est généralement par installé par défaut.

        • [^] # Re: fonction

          Posté par . Évalué à 2 (+0/-0).

          Ça fait juste 2 fichiers à distribuer.

          Versus un seul?

          Les dossier du $PATH sont protégé par les droits root, c'est pas parreil.

          Euh… je sais pas pour toi, mais moi, j'ajoute souvent un dossier de mon $HOME à mon $PATH, et j'y colle mes binaires perso… donc non, c'est pas protégé, et c'est pas une question de config perso, parce qu'un programme ça peut modifier l'environnement de ses fils de toute façon.

          Tu sacrifie la portabilité et le sécu de ta machine, juste pour ne pas écrire 3 lignes une fois.

          La sécu? Ou ça?

          160 lignes c'est trop long pour du bash.

          Je me suis dit la même, pour le coup.

          T'es obligé de compiler pour chaque archi.

          pour ça et lautre point, ok.

          • [^] # Re: fonction

            Posté par . Évalué à -1 (+1/-2).

            Versus un seul?

            Un seul + le fichier qui modifie ton PATH

            Euh… je sais pas pour toi, mais moi, j'ajoute souvent un dossier de mon $HOME à mon $PATH, et j'y colle mes binaires perso… donc non, c'est pas protégé, et c'est pas une question de config perso, parce qu'un programme ça peut modifier l'environnement de ses fils de toute façon.

            Bah c'est une mauvaise pratique, tu peux éventuellement le faire pour ton shell courant, mais de manière global (pour une utilisation dans un script) c'est pas une bonne idée.
            Par exemple, si tu cré un fichier "test" exécutable dans ton home, et que tu exécute un script qui utilise la commande test, il va exec ton test a la place et potentiellement faire n’importe-quoi.

            Je vais pas continué a débattre, et t'as bien le droit de faire ce que tu veux, mais si j'ai un conseil a te donner, c'est de rester proche des standards, fait des fonctions, et dans 10 ans, ça marchera peut être toujours :)

            Et généralement on a pas besoin de commande retry, en dehors d'une utilisation pour téster/débuguer. Si t'as une commande qui peux échouer pour de bonne raison, elle doit très certainement avoir une option "retry", "timeout", "wait" ou quelque chose comme ça.

            • [^] # Re: fonction

              Posté par . Évalué à 2 (+0/-1).

              Bah c'est une mauvaise pratique, tu peux éventuellement le faire pour ton shell courant, mais de manière global (pour une utilisation dans un script) c'est pas une bonne idée.

              Une… mauvaise pratique, de montrer mon code a tous, anonymement?

              La, il va falloir que tu m'expliques… parce que tu vois, mon code, ici, il a permis potententiellement pleins de trucs.

              Déjà, il fait le job. Rien que ça, c'est pas dégueu, l'air de rien.
              En plus, il est amélioré par des commentaires, c'est donc utile pour les futurs hackers.
              Ah et… il te reste a démontrer qu'il sert a rien… oups! C'est vrai, il y a 0 pôlitique. C'est de la techique pure, et je remercie ceux qui ont dit que même si c'est mauvais un peu de code ça fait du bien. Ce site fut un repaire de geeks voires nerds, cest devenu un repaire de politiciens, et ça me gonfle.

              Perso, j'entend changer ça, par la pratique. Je code ou je meurs.

              • [^] # Re: fonction

                Posté par . Évalué à 1 (+0/-1).

                Je me réponds a moi-même, mais, malheureusement, je suis français. Comment je fais pour mettre ce que je publie ici en CC0? Et si un jour je veux juste une licence type BSD-2, je fais comment, je fais un double compte ou bien je me tais?

                cette bd me manquais, pardon<<

              • [^] # Re: fonction

                Posté par . Évalué à 2 (+0/-0).

                Une… mauvaise pratique, de montrer mon code a tous, anonymement?

                Il n'a pas remis en question le fait que tu publie du code. Il dit juste que selon lui il faut que ça arrive dans /usr/local/bin sinon c'est pas HFS.

            • [^] # Re: fonction

              Posté par . Évalué à 3 (+1/-0). Dernière modification le 26/04/20 à 13:16.

              Bah c'est une mauvaise pratique, tu peux éventuellement le faire pour ton shell courant, mais de manière global (pour une utilisation dans un script) c'est pas une bonne idée.
              Par exemple, si tu cré un fichier "test" exécutable dans ton home, et que tu exécute un script qui utilise la commande test, il va exec ton test a la place et potentiellement faire n’importe-quoi.

              Ton commentaire semble montrer que tu n'a pas compris sa remarque. Il ne parle pas de mettre le répertoire courant dans son ${PATH}, mais un dossier particulier. C'est une technique très classique et très utilisée (avoir un ${HOME}/bin qui est ajouté dans ${PATH}).

              Le problème que tu décris n'existe que si le dossier en question est ajouté en première position ce qui est rarement fait.

              Et généralement on a pas besoin de commande retry, en dehors d'une utilisation pour téster/débuguer. Si t'as une commande qui peux échouer pour de bonne raison, elle doit très certainement avoir une option "retry", "timeout", "wait" ou quelque chose comme ça.

              Tu considère comme général ta propre vision, mais elle n'est ni unique, ni une généralité. Une logique plus unix serait de laisser les nouvelles tentatives à la charge d'un autre outil. D'où l'existence de la commande timeout dans les coreutils.

  • # Petite review

    Posté par . Évalué à 4 (+2/-0).

    Je ne suis pas un grand connaisseur du C et ça fait longtemps que je n'ai pas pratiqué.
    Mais lire du code c'est toujours amusant :)

    int run_cmd( unsigned int time, unsigned int tsleep, char** cmd )
    {
        sleep( tsleep );
        int status;
        switch( fork() )
        {
            case 0:
                alarm( time );
                execvp( *cmd, cmd );
            case -1:
                CHECK_ERR();
                break;
            default:
                break;
        }
        pid_t child = wait( &status );
        return child != -1 ? WEXITSTATUS( status ) : -1;
    }

    Il y a pleins de subtilité dans ce petit bout code. Faut voir que execvp() ne retourne jamais sauf en cas d'erreur où il positionne errno. Donc la macro CHECK_ERR(), va gérer les cas d'erreur de fork() (ce qui est évident) ou de execvp()` (ce qui est déjà plus subtile).

    La gestion du fils est hors du switch alors que sémantiquement elle devrait être dans le default (amha). Et on a du coup un truc qui est de genre :

    swicth(fork()) {
      case 0: // child
      case -1: // error
      default: // root process
    }

    Bien sûr ce n'est qu'un avis personnel qui est là pour ouvrir une discussion :)

    • [^] # Re: Petite review

      Posté par (page perso) . Évalué à 6 (+3/-0).

      Le code reste quand même assez discutable. Même si cela reste un petit bout de code il y a de quoi améliorer

      Déjà les macros CHECK_ERR et INT_ARG n'ont aucun intérêt, faire des fonctions à la place serait plus lisible et permettrait au compilateur de produire des messages d'erreurs plus sympas.

      D'autant que le second est erroné. Il fait appel à des variables qui ne son présentes que dans main et qui ne sont pas passés en paramètres. Donc en somme cette macro n'est pas réutilisable alors que cela ne coûterait rien de le faire en fonction.

      char* endptr = 0;
      

      Il est préférable d'initialiser un pointeur à NULL plutôt que 0.

          if( !*arg || ( *arg && **arg != '-' ) )
      

      Il vérifie que l'argument débute par un tiret mais ne vérifie pas la taille pour être sûr que l'argument a bien plus d'un caractère ce qui serait je pense pertinent.

      Puis il vérifie deux fois que arg n'est pas nul, c'est inutilement redondant.

      for( ; count && run_cmd( (unsigned)pause_time, (unsigned)sleep_time, cmd ); --count )

      Ce n'est pas une erreur en soi mais la ligne me semble inutilement longue et complexifie la lecture de la boucle. La commande devrait être dans le corps de la boucle quitte à utiliser un do while qui serait plus judicieux ici.

      Globalement le main je le découperais en plein de fonctions encore, il y a moyen.

      Bref, c'était ma revue de code. Elle vaut ce qu'elle vaut.

      • [^] # Re: Petite review

        Posté par . Évalué à 2 (+0/-0).

        Il est préférable d'initialiser un pointeur à NULL plutôt que 0.

        Techniquement, c'est du C, et en C, NULL, c'est 0. Après, oui, c'est plus lisible NULL.

        Il vérifie que l'argument débute par un tiret mais ne vérifie pas la taille pour être sûr que l'argument a bien plus d'un caractère ce qui serait je pense pertinent.

        En même temps, je vérifie le 2nd caractère dans le switch. Du coup, déjà je check si '\0' ou '-', puis je vérifie si le 2nd est connu. Si le 2nd est pas connu, ce qui implique le '\0', je pars en erreur.

        Puis il vérifie deux fois que arg n'est pas nul, c'est inutilement redondant.

        Pas faux.

        Bref, c'était ma revue de code. Elle vaut ce qu'elle vaut.

        Et je vous remercie tous les deux, c'est toujours sympa une revue.
        C'est clair que le code est améliorable, j'ai fini de bricoler ça a tôt hier matin faut dire ^ (bien que ça ne soit qu'une mauvaise excuse… bon, on va faire comme si jétais prof: c'étais pour l'exercice… non?)

      • [^] # Re: Petite review

        Posté par . Évalué à 1 (+0/-1).

        C'est vraiment si moche? Je serais heureux que tu me montre par l'exemple, ça servira potentiellement a plein de gens.

        C'est vrai, qui suis-je au fond, pauvre libriste qui ose publier du code si sale que personne ne publie la version correcte?

        C'est triste, mais ici, soit les gens mettent des liens githubs, dont le côté libre est discutable, soit on se fait limite démolir pour avoir osé ne pas être parfait..

        Pardon mais moi, j'aime pas le libre parce que c'est du code parfait, mais parce que c'est du code que les autres peuvent améliorer. Sans se baser sur une base propriétaire comme github ou gitlab.
        Je veux être libre de filer mon code a qui je veux, c'est a dire: tout le monde, même si c'est mauvais, certains apprendront, et moi je lirais leurs articlcles… techniques, et non politiques, ça me changera!

        • [^] # Re: Petite review

          Posté par . Évalué à 3 (+1/-0).

          Euh… Je comprends qu'ils puisse avoir un ton qui ne te convient pas, mais c'est toute de même une critique constructive. Je ne sais pas trop pourquoi tu le prends à parti comme ça. Il a pris le temps de revoir ton code et d'en exprimer une critique. C'est un comportement précieux dans le libre. Parce que le libre ce n'est pas que du code, c'est aussi de la remonté de bug, de la relecture, du tris de bug, de l'écriture de documentation, du packaging,…

          Il n'a pas remis en cause ton droit d'avoir écris ton code et de l'avoir partagé. Le fait qu'il ai pris le temps de relire et de rédiger remarques montre justement une certaine considération.

        • [^] # Re: Petite review

          Posté par (page perso) . Évalué à 4 (+1/-0).

          Comme barmic l'a dit tu écris et publies ce que tu veux, c'est ton droit.

          Non ton code n'est clairement pas parfait, il ne faut pas le prendre mal, j'ai donné les éléments qui m'ont sauté aux yeux pour que tu puisses faire mieux la prochaine fois. Moi aussi j'ai écrit (et j'écris à l'occasion) du code sale. Et je suis content quand quelqu'un m'explique ce que je pourrais améliorer.

          Bref, ne prends pas la mouche, il n'y a pas de raisons…

    • [^] # Re: Petite review

      Posté par . Évalué à 2 (+0/-0).

      La gestion du fils est hors du switch alors que sémantiquement elle devrait être dans le default (amha).

      Non, c'est la gestion du père. Le fils, c'est dans le cas du 0. Ça doit être une typo compte tenu de la suite cela dit, mais bref, oui, en soit tu as raison.

Envoyer un commentaire

Suivre le flux des commentaires

Note : les commentaires appartiennent à ceux qui les ont postés. Nous n'en sommes pas responsables.