Miamondo

Kronik

Kronik

  • Par miamondo
  • Le 29/07/2020 à 20:25
  • 0 commentaire

Sommaire : Présentation de l'application Le script start.py le script kronik.py Epoch Les itérateurs  Quelques réflexions sur la notion d'infinité

Bonjour

Aujourd'hui, j'ai envie de vous présenter une application codée par mes soins. Je l'ai baptisée Kronik. Il s'agit d'un planificateur de tâches comparable à Cron, mais dotée d'une interface graphique. J'ai commencé à écrire les premières lignes en Bash, mais je trouvais le résultat peu chatoyant. J'ai donc décidé d'emballer tout ça dans du Python et du Tkinter. Vous trouverez une vidéo à la fin de l'article.

Le projet est perfectible, notamment au niveau du redimensionnement des fenêtres, mais je suis tout de même très satisfait du résultat, car il m'a fallu relever plusieurs défis:

  • Des calculs mathématiques et des ajustements temporels à la limite de mes capacités mentales.
  • L'utilisation d'un itérateur qui permet de ne pas s'engouffrer dans une boucle infinie ayant pour irrémédiable conséquence un crash de l'application.

Alors, comment ça fonctionne? Eh bien, grâce à deux scripts Python:

  • start.py lance le programme proprement dit, lequel permet à l'interface chaise/clavier, de sélectionner les applications à planifier.
  • kronik.py est lancé par le fichier openbox/autostart, à chaque démarrage et se charge de gérer les tâches précédemment planifiées.

Voici donc à quoi ressemble la page d'accueil:

 

Kronik

 

On trouve le titre enchâssé dans un widget LabelFrame, avec en dessous, un second cadre étiqueté qui permet de sélectionner une commande ou de renseigner directement le chemin absolu d'un fichier à exécuter (.py, .c, etc...). Le menu déroulant (Listbox) répertorie les commandes de toutes les applications installées sur votre ordinateur. Pour générer cette liste, ce n'est pas bien compliqué. Il suffit de boucler sur le répertoire /usr/share/applications. Ensuite, il faut ouvrir chaque fichier *.desktop pour en extraire la ligne qui commence par exec

Sous ce menu déroulant, on trouve un champ d'entrée qui permet de renseigner le chemin absolu d'une application qui n'est pas présente dans /usr/share/applications. Enfin, on trouve un bouton Applications planifiées. Il ouvre une fenêtre Toplevel qui répertorie toutes les tâches planifiées et permet de supprimer chacune d'entre elles. Je souhaite améliorer cette fonctionnalité, en y incluant la fréquence (tous les jours, toutes les deux heures etc...)

 

Fenêtre surgissante

 

Continuons... Je sélectionne gnome-disks et je valide. Une fenêtre surgissante apparaît et me demande de confirmer en cliquant dessus. Je peux encore changer d'avis mais je décide de confirmer.

 

kronik2

 

J'atterris sur une fenêtre remplie de widgets Scale. Il est à noter que je me suis arrangé pour qu'il ne soit pas possible de déplacer deux curseurs simultanément. Si vous bougez un curseur, les autres sont désactivés ou reviennent à la position 0. Il y a également un widget Entry. Ce dernier permet à l'usager de renseigner une tâche qui va se lancer une seule fois. Pour une précision optimale, il faut que je rajoute les minutes et les secondes. Lorsque vous avez fait votre choix et que vous l'avez confirmé, la planification est lancée.

 

Kronik

 

2020 07 29 204650 788x622 scrot

 

Ça, c'est la partie émergée de l'iceberg. Le travailleur de l'ombre, celui qui gère la planification depuis son repaire situé dans les profondeurs de la chaîne volcanique balafrant les Terres de Volgor, c'est kronik.py. Et on peut dire que sa conception m'a donné du fil à retordre, car elle m'a obligé à manipuler des dates transformées en secondes et paramétrées en prenant pour référence Epoch, c'est-à-dire le 1er Janvier 1970. Je ne suis lancé dans de savants calculs qui ont failli me rendre fou, d'autant plus que je voulais trouver une combine pour prendre en compte le temps écoulé lorsque l'ordinateur n'est plus sous tension. C'est-à dire que lorsque je rallume mon ordinateur après une bonne nuit de sommeil, les paramètres temporels ne sont plus les mêmes qu'au moment de l'extinction. Ils ont été mis à jour grâce à l'intervention d'Epoch. Voici donc le fichier généré par Kronik le bossu. Il s'appelle scheduledApps:

  • /home/miamondo/.config/kronik/start.py:86400:47872:1596000773:1596039301
  • gnome-disks:86400:83624:1596039457:1596042233
  • /home/miamondo/.config/kronik/system_update/system_update.py:86400:86308:1596042147:1596042239

Les paramètres sont séparés par deux petits points. Actuellement, on trouve trois tâches planifiées. Prenons la dernière d'entre elles. Il s'agit d'une petite application que j'ai inclus dans le programme, pour mettre à jour ma distribution Archlinux. Je l'ai codée il y a deux ans.

  1. Chemin de l'application: system_update.py
  2. Fréquence d'exécution du programme: 86400 secondes soit 24 heures
  3. Temps restant avant exécution du programme: 86308 secondes
  4. Précédente exécution du programme (ou premier lancement): 1596042147 secondes après Epoch (01/01/1970)
  5. Tems écoulé depuis Epoch: 1596042239 secondes. C'est l'instant présent. 

Si vous êtes perspicaces, vous aurez remarqué qu'entre le second et le troisième paramètre, l'écart est de 92 secondes. C'est exactement le même nombre qui sépare le quatrième et le cinquième paramètre... Et normalement, si j'éteins mon ordinateur et que je le redémarre  dans deux heures, les écarts seront identiques (évidemment pas forcément 92 secondes!). Je ne vous raconte pas la prise de tête pour configurer tout ça!

 

system_update

 

Deuxième gros défi, il faut que le temps et le programme s'écoulent sans interruption. Il n'est pas possible de créer une boucle infinie du type while 1: go on!. Au bout de 998 tours, elle va se crasher, et le programme avec. Il faut écrire du code itératif ou récursif, mais en prenant soin de définir une condition qui permette théoriquement de sortir de la boucle. J'utilise donc un itérateur, qui tourne tant que la variable d' incrémentation n'a pas atteint Époch, ce qu'elle ne fera jamais... mais elle ne le sait pas... Et il ne faut surtout pas lui dire! Voici le bout de code :

        for i in range(0, int(datetime.datetime.now().timestamp())):
            self
.go_on()

    def go_on(self): ... suite du code.

Ce code de deux lignes, plus philosophique qu'informatique, nous interroge sur la notion d'infinité. Il s'agit bien d'une boucle infinie puisque la variable i ne rattrapera jamais Epoch, condition sine qua non pour arrêter le programme. Epoch est lui-même un itérateur. Et pourtant, si on change la valeur de la variable i en lui affectant Epoch, alors la boucle s'arrête... Et ça, ce n'est pas possible avec une boucle du type while 1 < 2. Celle-ci est réellement une prison infinie, un châtiment mathématique perpétuel que l'on ne peut arrêter puisque 1 sera pour toujours inférieur à 2.    

Voilà donc pour cette petite application qui m'a demandé du temps à coder, mais qui m'a aussi apporté beaucoup de satisfaction. Elle est perfectible, certes, mais elle est déjà opérationnelle. N'hésitez pas à me faire part de vos remarques, notamment au niveau du code itératif. Il n'a pas encore planté mais sait-on jamais... Peut-être y-a-t-il une faiblesse qui m'échappe. 

J'essaierai, dans un prochain billet, d'expliquer la différence entre un itérateur et une fonction récursive mais la vulgarisation de ces théories abstraites n'est pas chose aisée. 

 

Linux Python planificateur de tâches

  • Aucune note. Soyez le premier à attribuer une note !

Ajouter un commentaire