Was macht dieses Script? Teil 2

Schau dir dieses Python-Script an und überlege: Was könnte es tun? Wähle eine der folgenden Antworten:

  1. Es erstellt ein grafisches Dashboard für Taskmanagement.
  2. Es fügt ein Task-Icon zur System-Tray hinzu, das Aufgaben ausführt.
  3. Es überwacht das Dateisystem und führt bestimmte Aktionen bei Änderungen aus.

Hast du deine Vermutung? Schauen wir uns den Code an, um die richtige Antwort zu finden:

Der Code:

import os
import sys
sys.dont_write_bytecode = True
import threading
import importlib.util
from pystray import Icon, MenuItem
from PIL import Image, ImageDraw
import logging

# Logging aktivieren
logging.basicConfig(level=logging.DEBUG, format="%(asctime)s - %(levelname)s - %(message)s")
logging.debug("Taskmanager gestartet")

# Funktion zum Laden von Aufgaben
def load_tasks():
    tasks_path = os.path.join(os.path.dirname(__file__), "tasks")
    task_menu = []

    if not os.path.exists(tasks_path):
        logging.debug(f"Das Verzeichnis {tasks_path} existiert nicht.")
        return []

    # Lädt alle Python-Dateien im Ordner "tasks"
    for task_file in os.listdir(tasks_path):
        if task_file.endswith(".py"):
            task_name = os.path.splitext(task_file)[0]
            task_path = os.path.join(tasks_path, task_file)

            def create_task_runner(task_path):
                def task_runner():
                    try:
                        spec = importlib.util.spec_from_file_location("task", task_path)
                        module = importlib.util.module_from_spec(spec)
                        sys.modules["task"] = module
                        spec.loader.exec_module(module)
                        if hasattr(module, "main"):
                            module.main()
                        else:
                            logging.debug(f"Die Datei {task_path} hat keine 'main'-Funktion.")
                    except Exception as e:
                        logging.debug(f"Fehler beim Ausführen von {task_path}: {e}")

                return lambda icon, item: threading.Thread(target=task_runner).start()

            # Menüpunkt für die Aufgabe erstellen
            task_menu.append(MenuItem(task_name, create_task_runner(task_path)))

    return task_menu

# Funktion zum Beenden der Anwendung
def quit_app(icon, item):
    icon.stop()

# Icon-Bild erstellen
def create_image():
    width, height = 64, 64
    image = Image.new("RGB", (width, height), "white")
    draw = ImageDraw.Draw(image)
    draw.rectangle((0, 0, width - 1, height - 1), fill="white")
    draw.rectangle((2, 2, width - 3, height - 3), fill="black")
    return image

# Kontextmenü für das Tray-Icon erstellen
def create_menu():
    tasks = load_tasks()
    menu = tasks + [MenuItem("Beenden", quit_app)]
    logging.debug(f"Erstelltes Menü: {menu}")
    return menu

# Taskleisten-Icon erstellen und starten
icon = Icon("Taskmanager", create_image(), "Taskmanager", create_menu())
icon.run()


Die Antwort

Das Script entspricht Antwort 2:
„Es fügt ein Task-Icon zur System-Tray hinzu, das Aufgaben ausführt.“


Wie funktioniert das Script?

System-Tray-Icon erstellen
Das Script verwendet die pystray-Bibliothek, um ein Taskleisten-Icon zu erstellen.

Dieses Icon wird mit einem Bild (create_image) und einem Kontextmenü (create_menu) verknüpft.

Laden von Aufgaben
Aufgaben werden aus Python-Dateien im Verzeichnis tasks geladen.

Jede Datei wird dynamisch importiert und überprüft, ob sie eine main-Funktion enthält, die ausgeführt werden kann.

Ein Menüpunkt für jede Aufgabe wird dem Kontextmenü hinzugefügt.

Task-Ausführung
Beim Klick auf eine Aufgabe wird diese in einem separaten Thread gestartet, sodass das Icon und das Menü weiterhin reaktionsfähig bleiben.

Beispiel: ./tasks/system.py


import sys
import subprocess
import tkinter as tk

def main():
    # Erstelle ein neues Fenster
    window = tk.Tk()
    window.title("System Info")

    # Textfeld für die Ausgabe
    output_text = tk.Text(window, wrap=tk.WORD, height=15, width=50)
    output_text.pack(padx=10, pady=10)

    # Python-Version ausgeben
    output_text.insert(tk.END, f"Python-Version: {sys.version}\n\n")
    
    # Installierte Pakete auflisten
    output_text.insert(tk.END, "Installierte Pakete:\n")
    try:
        result = subprocess.run(
            [sys.executable, "-m", "pip", "list"],
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            text=True
        )
        output_text.insert(tk.END, result.stdout)
    except Exception as e:
        output_text.insert(tk.END, f"Fehler beim Abrufen der Paketliste: {e}\n")

    # Scrollbar hinzufügen
    scrollbar = tk.Scrollbar(window, command=output_text.yview)
    scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
    output_text.config(yscrollcommand=scrollbar.set)

    # Fenster anzeigen
    window.mainloop()

if __name__ == "__main__":
    main()

Beenden der Anwendung
Das Kontextmenü enthält eine „Beenden“-Option, die die Anwendung sauber schließt.

Logging für Debugging
Mit logging werden alle Schritte des Scripts protokolliert, sodass Fehler einfach nachverfolgt werden können.


Warum ist das nützlich?

Dieses Script ist ein vielseitiges Tool für:

  • Taskmanagement: Aufgaben können zentral über die System-Tray verwaltet und ausgeführt werden.
  • Erweiterbarkeit: Neue Aufgaben können einfach hinzugefügt werden, indem Python-Dateien im tasks-Verzeichnis abgelegt werden.
  • Benutzerfreundlichkeit: Die Verwendung eines Tray-Icons macht das Tool leicht zugänglich und unaufdringlich.

P.S. taskmanager.bat (Windows User)

@echo off
start "" pythonw.exe "%~dp0taskmanager.py"

Was macht dieses Script? Teil 1

Bevor du dir den Code genauer anschaust, überlege selbst: Was könnte dieses Script tun? Wähle aus den folgenden drei Möglichkeiten:

  1. Es installiert Docker und lädt ein Image aus dem Internet herunter.
  2. Es importiert Docker-Images aus einem bestimmten Verzeichnis und überspringt bereits vorhandene.
  3. Es bereinigt ungenutzte Docker-Images und optimiert den Speicherplatz.

Schau dir den Code an und entscheide dich für eine Antwort:

Der Code:


#!/bin/bash

IMAGES_DIR="/home/vagrant/exported-docker-images"

echo "Starte Import der Docker-Images aus: $IMAGES_DIR"

if [ -d "$IMAGES_DIR" ]; then
  for image in $IMAGES_DIR/*.tar; do
    if [ -f "$image" ]; then
      # Extrahiere die Image-Informationen aus der Datei
      IMAGE_NAME=$(docker load -i "$image" | awk '/Loaded image:/ {print $3}')

      # Überprüfe, ob das Image bereits existiert
      if docker images --format "{{.Repository}}:{{.Tag}}" | grep -q "^$IMAGE_NAME$"; then
        echo "Überspringe $IMAGE_NAME, da es bereits geladen ist."
      else
        echo "Importiere $image..."
        docker load -i "$image"
      fi
    fi
  done
else
  echo "Kein Verzeichnis für Docker-Images gefunden unter: $IMAGES_DIR"
fi

echo "Provisioning abgeschlossen."

Hast du dich entschieden? Überprüfe deine Antwort:

Die Antwort

Das Script entspricht Antwort 2:
„Es importiert Docker-Images aus einem bestimmten Verzeichnis und überspringt bereits vorhandene.“


Wie funktioniert das genau?

Hier ist eine ausführliche Erklärung:

  1. Verzeichnis prüfen:
    Das Script beginnt damit, zu prüfen, ob das festgelegte Verzeichnis IMAGES_DIR (/home/vagrant/exported-docker-images) existiert. Dort sollten .tar-Dateien liegen, die Docker-Images repräsentieren. Falls das Verzeichnis fehlt, bricht das Script ab und gibt eine Fehlermeldung aus.
  2. Alle .tar-Dateien durchgehen:
    Das Script durchläuft alle Dateien im Verzeichnis, die auf .tar enden. Jede Datei wird einzeln verarbeitet.
  3. Image laden:
    Mit docker load -i wird das Docker-Image aus der .tar-Datei in die lokale Docker-Registry geladen.
  4. Überprüfung auf Duplikate:
    Nachdem ein Image geladen wurde, prüft das Script, ob es bereits in der Registry existiert. Dazu wird der Name und die Tag-Version des Images extrahiert und mit der lokalen Liste der Docker-Images verglichen (docker images --format). Wenn das Image bereits existiert, wird es übersprungen.
  5. Abschlussmeldung:
    Sobald alle Dateien geprüft wurden, gibt das Script eine Meldung aus, dass der Import abgeschlossen ist.

Warum ist das nützlich?

Die Nützlichkeit ist an dieser Stelle Fragwürdig, aber ich hatte Bock drauf.
Vor allem weil ich beim wiederholtem Testen gemerkt habe, das ich doch eine ganze Menge Daten durch die Leitung ziehe und vor allem immer die selben.

Nachhaltigkeit war nicht unbedingt mein vordergründiger Gedanke, aber das war es was mich am Ende getrieben hat, und in dieser Umsetzung, weil ich nicht die Muse hatte einen eigenen lokalen Hub aufzusetzen. 

 

Wie hast du abgeschnitten? Wenn du Antwort 2 gewählt hast, warst du genau richtig! 😊

P.S.

#!/bin/bash

# Verzeichnis für die exportierten Images
EXPORT_DIR="/home/vagrant/docker-images"
mkdir -p "$EXPORT_DIR"

# Alle Docker-Images exportieren
echo "Überprüfe und exportiere alle Docker-Images in das Verzeichnis: $EXPORT_DIR"
for image in $(docker images --format "{{.Repository}}:{{.Tag}}"); do
  # Erstelle einen gültigen Dateinamen (ersetze "/" durch "_")
  IMAGE_NAME=$(echo "$image" | tr '/' '_')
  OUTPUT_FILE="$EXPORT_DIR/${IMAGE_NAME}.tar"

  # Überspringe Export, wenn das Image bereits existiert
  if [ -f "$OUTPUT_FILE" ]; then
    echo "Überspringe $image, da $OUTPUT_FILE bereits existiert."
    continue
  fi

  # Exportiere das Image
  echo "Exportiere $image nach $OUTPUT_FILE..."
  docker save -o "$OUTPUT_FILE" "$image"
done

echo "Export abgeschlossen. Alle Docker-Images wurden überprüft."