feat(windows): Desktop-Symbol und Startmenue-Eintrag — plus --oeffnen
Ampel / ampel (push) Failing after 47s
Ampel / ampel (push) Failing after 47s
WAS: Das Setup legt jetzt eine Verknuepfung auf dem Desktop UND im
Startmenue an, die Deinstallation nimmt beide zurueck, und `--status`
zeigt, ob sie da sind. Abwaehlbar mit --keine-verknuepfungen.
WARUM (Commander-Meldung): "es gibt kein icon aufm desktop und keinen
startmenü eintrag". Zu Recht — ein Hintergrundprogramm ohne Symbol ist
praktisch unauffindbar: Es laeuft, aber es gibt keinen Weg hinein ausser
der Adresse im Kopf.
DIE VERKNUEPFUNG ZEIGT AUF --oeffnen, NICHT AUF --dienst. Ein Doppelklick
soll Rippy OEFFNEN; ob der Dienst laeuft, ist dem Nutzer egal und er kann
es auch nicht wissen. Zeigte das Symbol auf --dienst, startete jeder Klick
einen ZWEITEN Server, der am belegten Port scheitert — das Fenster blitzt
auf, im Browser passiert nichts. Ein Symbol, das beim zweiten Klick nichts
tut, ist schlimmer als keins.
`--oeffnen` sieht deshalb erst NACH, ob jemand antwortet, startet nur wenn
noetig, und wartet dann, bis der Dienst wirklich da ist — statt sofort
einen Browser auf eine tote Adresse zu schicken. Gemessen: erster Aufruf
2 s bis HTTP 200, zweiter Aufruf keine zusaetzlichen Prozesse.
DIE ORDNER KOMMEN AUS DER REGISTRY, nicht aus %USERPROFILE%. Wer OneDrive
benutzt oder seine Ordner verschoben hat, dessen Desktop liegt woanders —
die Verknuepfung landete dann in einem Ordner, den niemand sieht, und der
Nutzer suchte ein Symbol, das es nirgends gibt.
UEBER POWERSHELL statt pywin32: Eine .lnk ist ein binaeres Shell-Objekt.
pywin32 koennte es, waere aber 20 MB fuer vier Zeilen. Denselben Weg geht
der alte Worker-Installer schon ("nativ via PowerShell").
ZWEI FEHLER, DIE DIE TESTS GEFUNDEN HABEN:
- os.makedirs stand AUSSERHALB des try. Auf einem Laufwerk, das es nicht
gibt, wirft es — aus "Verknuepfung konnte nicht angelegt werden" waere
ein Abbruch der ganzen Installation geworden.
- Der Test dafuer nahm fest Z: als "gibt es nicht". Auf dem Commander-PC
ist Z: ein NETZLAUFWERK (X, Y, Z sind belegt). Ein fest verdrahteter
Laufwerksbuchstabe ist eine Annahme ueber eine fremde Maschine; jetzt
wird zur Laufzeit ein freier gesucht.
Und der Apostroph: In PowerShell wird er innerhalb einfacher
Anfuehrungszeichen durch VERDOPPELN maskiert. Ohne das braeche ein Pfad wie
C:\Users\O'Brien\... das Skript entzwei, und der Fehler saehe aus wie ein
Syntaxfehler in Rippy.
GEMESSEN, nach echter Installation nach %LOCALAPPDATA%\Rippy:
Desktop-Symbol -> Rippy.exe --oeffnen, mit Symbol und Beschreibung
Startmenue -> ebenso
Programme+Feat. -> Rippy 2.0.0, 100 MB, Deinstallieren funktioniert
Autostart -> "...\Rippy.exe" --dienst
Start ueber das Symbol: HTTP 200 nach 2 s
Worker: TobisNicerPC, Encoder cpu-x264/x265/av1, vce, vce-av1
GEMESSEN: ruff sauber, 521 Tests gruen + 15 uebersprungen (vorher 512).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
f4a8d77598
commit
99c05865af
@@ -0,0 +1,129 @@
|
||||
"""Verknuepfungen: der Ordner, das Skript, das Zurueckraeumen.
|
||||
|
||||
Das PowerShell-Skript wird als reine Funktion gebaut und geprueft — so faellt
|
||||
ein Zitier-Fehler auf, ohne dass eine .lnk entstehen muss. Die Tests, die
|
||||
wirklich eine anlegen, laufen nur unter Windows und raeumen hinter sich auf.
|
||||
|
||||
Hinweis zu den Pfaden: Windows-Pfade stehen hier in ROHEN Zeichenketten oder
|
||||
werden aus `B` (dem Backslash) zusammengesetzt. In normalen Zeichenketten
|
||||
waeren `C:\\D` und `C:\\Users` ungueltige Escape-Sequenzen — heute eine
|
||||
DeprecationWarning, in einer kuenftigen Python-Version ein harter Fehler.
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
import pytest
|
||||
|
||||
from rippy.platform import verknuepfungen as vk
|
||||
|
||||
nur_windows = pytest.mark.skipif(os.name != "nt", reason="nur unter Windows")
|
||||
|
||||
B = chr(92) # Backslash — haelt jede Escape-Falle aus den Tests raus
|
||||
|
||||
|
||||
# ── Das Skript ──────────────────────────────────────────────────────────
|
||||
def test_skript_setzt_ziel_und_argumente():
|
||||
lnk = "C:" + B + "D" + B + "Rippy.lnk"
|
||||
exe = "C:" + B + "R" + B + "Rippy.exe"
|
||||
s = vk.skript(lnk, exe, "--oeffnen")
|
||||
assert "CreateShortcut('" + lnk + "')" in s
|
||||
assert "$s.TargetPath = '" + exe + "'" in s
|
||||
assert "$s.Arguments = '--oeffnen'" in s
|
||||
assert s.rstrip().endswith("$s.Save()")
|
||||
|
||||
|
||||
def test_apostroph_im_pfad_bricht_das_skript_nicht():
|
||||
"""In PowerShell wird ein Apostroph innerhalb einfacher Anfuehrungszeichen
|
||||
durch VERDOPPELN maskiert. Ohne das bricht ein Pfad mit Apostroph das
|
||||
Skript mitten entzwei — und der Fehler sieht aus wie ein Syntaxfehler in
|
||||
Rippy statt wie ein Pfad, der ein Sonderzeichen enthaelt."""
|
||||
s = vk.skript("C:" + B + "Users" + B + "O'Brien" + B + "Rippy.lnk",
|
||||
"C:" + B + "R" + B + "Rippy.exe")
|
||||
assert "O''Brien" in s
|
||||
# Gerade Zahl von Anfuehrungszeichen — sonst ist ein String offen.
|
||||
assert s.count("'") % 2 == 0
|
||||
|
||||
|
||||
def test_ohne_arbeitsordner_wird_der_ordner_des_ziels_genommen():
|
||||
ordner = "C:" + B + "Programme" + B + "Rippy"
|
||||
s = vk.skript("C:" + B + "D" + B + "R.lnk", ordner + B + "Rippy.exe")
|
||||
assert "$s.WorkingDirectory = '" + ordner + "'" in s
|
||||
|
||||
|
||||
def test_leere_angaben_erzeugen_keine_leeren_zeilen():
|
||||
"""Ein `$s.IconLocation = ''` wuerde das Symbol LOESCHEN statt es
|
||||
unveraendert zu lassen."""
|
||||
s = vk.skript("C:" + B + "D" + B + "R.lnk", "C:" + B + "R" + B + "R.exe")
|
||||
assert "IconLocation" not in s
|
||||
assert "Description" not in s
|
||||
|
||||
|
||||
# ── Die Orte ────────────────────────────────────────────────────────────
|
||||
@nur_windows
|
||||
def test_desktop_und_startmenue_kommen_aus_der_registry():
|
||||
"""Ein fest verdrahtetes %USERPROFILE%/Desktop waere eine ANNAHME. Wer
|
||||
OneDrive benutzt oder seine Ordner verschoben hat, dessen Desktop liegt
|
||||
woanders — die Verknuepfung landete dann in einem Ordner, den niemand
|
||||
sieht, und der Nutzer suchte ein Symbol, das es nirgends gibt."""
|
||||
desktop = vk.shell_ordner("Desktop")
|
||||
programme = vk.shell_ordner("Programs")
|
||||
assert desktop and os.path.isdir(desktop)
|
||||
assert programme and os.path.isdir(programme)
|
||||
assert vk.desktop_pfad().endswith("Rippy.lnk")
|
||||
assert "Start Menu" in vk.startmenue_pfad()
|
||||
|
||||
|
||||
def test_unbekannter_ordner_ergibt_leer_statt_zu_raten():
|
||||
assert vk.shell_ordner("GibtEsNicht") == ""
|
||||
|
||||
|
||||
# ── Wirklich anlegen ────────────────────────────────────────────────────
|
||||
@nur_windows
|
||||
def test_verknuepfung_entsteht_wirklich(tmp_path):
|
||||
"""Nachsehen statt glauben: PowerShell meldet auch dann Erfolg, wenn
|
||||
Save() still scheitert. `anlegen()` prueft deshalb die Datei."""
|
||||
exe = tmp_path / "Rippy.exe"
|
||||
exe.write_bytes(b"x" * 512)
|
||||
lnk = str(tmp_path / "Rippy.lnk")
|
||||
|
||||
assert vk.anlegen(lnk, str(exe), "--oeffnen", beschreibung="Test") is True
|
||||
assert os.path.isfile(lnk)
|
||||
assert os.path.getsize(lnk) > 0
|
||||
|
||||
assert vk.entfernen(lnk) is True
|
||||
assert not os.path.exists(lnk)
|
||||
|
||||
|
||||
def _freier_laufwerksbuchstabe() -> str:
|
||||
"""Ein Buchstabe, den es auf DIESER Maschine wirklich nicht gibt.
|
||||
|
||||
Der erste Anlauf nahm fest `Z:` — auf dem Commander-PC ist das ein
|
||||
NETZLAUFWERK (X, Y und Z sind dort belegt). Der Test legte damit
|
||||
froehlich eine Verknuepfung auf einer Freigabe an und schlug fehl, weil
|
||||
er einen Misserfolg erwartete. Ein fest verdrahteter Laufwerksbuchstabe
|
||||
ist eine Annahme ueber eine fremde Maschine.
|
||||
"""
|
||||
import ctypes
|
||||
|
||||
maske = ctypes.WinDLL("kernel32").GetLogicalDrives()
|
||||
for i in range(25, -1, -1): # von Z rueckwaerts
|
||||
if not (maske & (1 << i)):
|
||||
return chr(ord("A") + i)
|
||||
return ""
|
||||
|
||||
|
||||
@nur_windows
|
||||
def test_anlegen_auf_unmoeglichem_pfad_wirft_nicht(tmp_path):
|
||||
"""Eine fehlende Verknuepfung ist aergerlich, aber kein Grund, eine sonst
|
||||
geglueckte Installation scheitern zu lassen."""
|
||||
buchstabe = _freier_laufwerksbuchstabe()
|
||||
if not buchstabe:
|
||||
pytest.skip("Alle 26 Laufwerksbuchstaben sind belegt")
|
||||
exe = tmp_path / "Rippy.exe"
|
||||
exe.write_bytes(b"x")
|
||||
assert vk.anlegen(buchstabe + ":" + B + "gibt-es-nicht" + B + "R.lnk",
|
||||
str(exe)) is False
|
||||
|
||||
|
||||
def test_entfernen_auf_nichts_ist_kein_fehler():
|
||||
assert vk.entfernen("C:" + B + "gibt-es-nicht" + B + "R.lnk") is False
|
||||
@@ -0,0 +1,171 @@
|
||||
"""Verknüpfungen auf dem Desktop und im Startmenü.
|
||||
|
||||
## Warum über PowerShell und nicht über pywin32
|
||||
|
||||
Eine `.lnk` ist keine Textdatei, sondern ein binäres Shell-Objekt. Sie von
|
||||
Hand zu schreiben ist Bastelei; `pywin32` könnte es, wäre aber eine
|
||||
20-MB-Abhängigkeit für vier Zeilen. Windows bringt die Fähigkeit selbst mit:
|
||||
`WScript.Shell` ist seit Jahrzehnten da und braucht keine Installation.
|
||||
|
||||
Dieses Projekt geht den Weg schon einmal — der alte Worker-Installer legt
|
||||
seine Verknüpfungen ebenfalls „nativ via PowerShell (kein win32com mehr
|
||||
nötig)" an.
|
||||
|
||||
## Warum die Ordner aus der Registry kommen
|
||||
|
||||
`%USERPROFILE%\\Desktop` ist eine ANNAHME. Wer OneDrive benutzt oder seine
|
||||
Ordner verschoben hat, dessen Desktop liegt woanders — die Verknüpfung
|
||||
landete dann in einem Ordner, den niemand sieht, und der Nutzer suchte ein
|
||||
Symbol, das es nirgends gibt.
|
||||
|
||||
Die Wahrheit steht unter `Shell Folders` in der Registry. Auf diesem Rechner
|
||||
am 28.08.2026 nachgesehen:
|
||||
|
||||
Desktop C:\\Users\\…\\Desktop
|
||||
Programs C:\\Users\\…\\AppData\\Roaming\\Microsoft\\Windows\\Start Menu\\Programs
|
||||
|
||||
## Worauf die Verknüpfung zeigt
|
||||
|
||||
Nicht auf `--dienst`. Ein Doppelklick auf ein Desktop-Symbol soll Rippy
|
||||
ÖFFNEN — und dabei ist es dem Nutzer egal, ob der Dienst schon läuft. Die
|
||||
Verknüpfung ruft deshalb `Rippy.exe --oeffnen`: Läuft der Dienst, geht nur
|
||||
der Browser auf; läuft er nicht, wird er zuerst gestartet. Ein Symbol, das
|
||||
beim zweiten Klick einen zweiten Server startet, wäre eine Falle.
|
||||
"""
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
|
||||
def shell_ordner(name: str) -> str:
|
||||
"""Der ECHTE Pfad eines Windows-Sonderordners („Desktop", „Programs").
|
||||
|
||||
Aus der Registry, nicht geraten. Leerer String, wenn er nicht zu
|
||||
ermitteln ist — dann wird eben keine Verknüpfung angelegt, statt eine
|
||||
an einer erfundenen Stelle.
|
||||
"""
|
||||
if os.name != "nt":
|
||||
return ""
|
||||
import winreg
|
||||
|
||||
try:
|
||||
with winreg.OpenKey(
|
||||
winreg.HKEY_CURRENT_USER,
|
||||
r"Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders",
|
||||
) as k:
|
||||
wert, _ = winreg.QueryValueEx(k, name)
|
||||
return os.path.expandvars(str(wert))
|
||||
except OSError:
|
||||
return ""
|
||||
|
||||
|
||||
def _ps_text(wert: str) -> str:
|
||||
"""Text für ein einfach gequotetes PowerShell-Argument.
|
||||
|
||||
In PowerShell wird ein Apostroph innerhalb einfacher Anführungszeichen
|
||||
durch VERDOPPELN maskiert. Ohne das bricht ein Pfad wie
|
||||
`C:\\Users\\O'Brien\\…` das Skript mitten entzwei — und der Fehler sieht
|
||||
aus wie ein Syntaxfehler in Rippy.
|
||||
"""
|
||||
return (wert or "").replace("'", "''")
|
||||
|
||||
|
||||
def skript(lnk: str, ziel: str, argumente: str = "", icon: str = "",
|
||||
beschreibung: str = "", arbeitsordner: str = "") -> str:
|
||||
"""Das PowerShell-Skript, das die Verknüpfung anlegt (reine Funktion)."""
|
||||
zeilen = [
|
||||
"$s = (New-Object -ComObject WScript.Shell).CreateShortcut('%s')" % _ps_text(lnk),
|
||||
"$s.TargetPath = '%s'" % _ps_text(ziel),
|
||||
]
|
||||
if argumente:
|
||||
zeilen.append("$s.Arguments = '%s'" % _ps_text(argumente))
|
||||
if icon:
|
||||
zeilen.append("$s.IconLocation = '%s'" % _ps_text(icon))
|
||||
if beschreibung:
|
||||
zeilen.append("$s.Description = '%s'" % _ps_text(beschreibung))
|
||||
zeilen.append("$s.WorkingDirectory = '%s'"
|
||||
% _ps_text(arbeitsordner or os.path.dirname(ziel)))
|
||||
zeilen.append("$s.Save()")
|
||||
return "; ".join(zeilen)
|
||||
|
||||
|
||||
def anlegen(lnk: str, ziel: str, argumente: str = "", icon: str = "",
|
||||
beschreibung: str = "", arbeitsordner: str = "") -> bool:
|
||||
"""Legt eine Verknüpfung an. False, wenn es nicht geklappt hat.
|
||||
|
||||
Wirft nicht: Eine fehlende Verknüpfung ist ärgerlich, aber kein Grund,
|
||||
eine sonst geglückte Installation scheitern zu lassen. Der Aufrufer
|
||||
sagt es dem Nutzer.
|
||||
"""
|
||||
if os.name != "nt":
|
||||
return False
|
||||
from rippy.platform.winlauf import OHNE_FENSTER
|
||||
|
||||
try:
|
||||
# os.makedirs MUSS mit in den try: Auf einem Laufwerk, das es nicht
|
||||
# gibt, wirft es — und dann waere aus "Verknuepfung konnte nicht
|
||||
# angelegt werden" ein Abbruch der ganzen Installation geworden.
|
||||
os.makedirs(os.path.dirname(lnk), exist_ok=True)
|
||||
ergebnis = subprocess.run(
|
||||
["powershell", "-NoProfile", "-NonInteractive", "-Command",
|
||||
skript(lnk, ziel, argumente, icon, beschreibung, arbeitsordner)],
|
||||
capture_output=True, text=True, timeout=60,
|
||||
creationflags=OHNE_FENSTER,
|
||||
)
|
||||
except (OSError, subprocess.SubprocessError):
|
||||
return False
|
||||
# Nachsehen statt dem Rueckgabewert glauben: PowerShell meldet auch dann
|
||||
# Erfolg, wenn Save() still scheitert.
|
||||
return ergebnis.returncode == 0 and os.path.isfile(lnk)
|
||||
|
||||
|
||||
def entfernen(lnk: str) -> bool:
|
||||
try:
|
||||
os.remove(lnk)
|
||||
return True
|
||||
except OSError:
|
||||
return False
|
||||
|
||||
|
||||
# ── Die beiden Orte ─────────────────────────────────────────────────────
|
||||
def desktop_pfad(name: str = "Rippy") -> str:
|
||||
ordner = shell_ordner("Desktop")
|
||||
return os.path.join(ordner, name + ".lnk") if ordner else ""
|
||||
|
||||
|
||||
def startmenue_pfad(name: str = "Rippy") -> str:
|
||||
ordner = shell_ordner("Programs")
|
||||
return os.path.join(ordner, name + ".lnk") if ordner else ""
|
||||
|
||||
|
||||
def alle_anlegen(programm: str, icon: str = "", desktop: bool = True,
|
||||
startmenue: bool = True) -> dict:
|
||||
"""Legt beide Verknüpfungen an. Gibt zurück, was WIRKLICH entstanden ist.
|
||||
|
||||
Der Rückgabewert ist die Liste der angelegten Dateien — nicht eine
|
||||
Erfolgsmeldung. So kann der Installer sagen, was er getan hat, statt
|
||||
zu behaupten, es sei alles gut gegangen.
|
||||
"""
|
||||
gemacht = {}
|
||||
ziele = []
|
||||
if desktop:
|
||||
ziele.append(("desktop", desktop_pfad()))
|
||||
if startmenue:
|
||||
ziele.append(("startmenue", startmenue_pfad()))
|
||||
|
||||
for schluessel, lnk in ziele:
|
||||
if not lnk:
|
||||
continue
|
||||
if anlegen(lnk, programm, argumente="--oeffnen", icon=icon or programm,
|
||||
beschreibung="Rippy öffnen — automatisches Ripping"):
|
||||
gemacht[schluessel] = lnk
|
||||
return gemacht
|
||||
|
||||
|
||||
def alle_entfernen() -> list:
|
||||
"""Nimmt beide Verknüpfungen zurück. Gibt zurück, was entfernt wurde."""
|
||||
entfernt = []
|
||||
for lnk in (desktop_pfad(), startmenue_pfad()):
|
||||
if lnk and os.path.isfile(lnk) and entfernen(lnk):
|
||||
entfernt.append(lnk)
|
||||
return entfernt
|
||||
@@ -41,6 +41,7 @@ import threading
|
||||
import time
|
||||
import webbrowser
|
||||
|
||||
from rippy.platform import verknuepfungen
|
||||
from rippy.platform import win_registry as reg
|
||||
|
||||
VERSION = os.environ.get("RIPPY_VERSION", "2.0.0")
|
||||
@@ -90,7 +91,7 @@ def melden(text: str) -> None:
|
||||
|
||||
# ═══════════════════════════════════════════════════ Installation ═══════
|
||||
def installieren(ziel: str = None, autostart: bool = True,
|
||||
starten_danach: bool = True) -> str:
|
||||
starten_danach: bool = True, verknuepfen: bool = True) -> str:
|
||||
"""Kopiert Rippy an seinen Platz und meldet es bei Windows an.
|
||||
|
||||
Gibt den Installationsordner zurück. Wirft bei echten Fehlern — eine
|
||||
@@ -129,6 +130,20 @@ def installieren(ziel: str = None, autostart: bool = True,
|
||||
if autostart:
|
||||
reg.autostart_setzen('"%s" --dienst' % programm)
|
||||
|
||||
if verknuepfen:
|
||||
# Ohne Symbol auf dem Desktop und ohne Startmenue-Eintrag ist ein
|
||||
# Hintergrundprogramm praktisch unauffindbar: Es laeuft, aber der
|
||||
# Nutzer hat keinen Weg hinein ausser der Adresse im Kopf.
|
||||
angelegt = verknuepfungen.alle_anlegen(
|
||||
programm, icon=os.path.join(ziel, "rippy.ico"))
|
||||
for ort in ("desktop", "startmenue"):
|
||||
if ort in angelegt:
|
||||
melden(" Verknuepfung angelegt: %s" % angelegt[ort])
|
||||
else:
|
||||
# Sagen, was NICHT geklappt hat — sonst sucht der Nutzer ein
|
||||
# Symbol, das es nie gab.
|
||||
melden(" Verknuepfung (%s) konnte nicht angelegt werden." % ort)
|
||||
|
||||
if starten_danach:
|
||||
starte_hintergrund(programm)
|
||||
|
||||
@@ -153,6 +168,10 @@ def deinstallieren(still: bool = False) -> None:
|
||||
ordner = (reg.gelesene_werte().get("InstallLocation")
|
||||
or reg.standard_installationsordner())
|
||||
|
||||
for lnk in verknuepfungen.alle_entfernen():
|
||||
if not still:
|
||||
melden(" Verknuepfung entfernt: %s" % lnk)
|
||||
|
||||
reg.autostart_entfernen()
|
||||
reg.austragen()
|
||||
laeuft_von_hier = os.path.abspath(_eigene_datei()).lower().startswith(
|
||||
@@ -336,6 +355,42 @@ def dienst_starten(port: int = STANDARD_PORT) -> int:
|
||||
return 0
|
||||
|
||||
|
||||
def oeffnen(port: int = STANDARD_PORT) -> int:
|
||||
"""Rippy oeffnen — Dienst starten, falls noetig, dann den Browser.
|
||||
|
||||
## Warum die Verknuepfungen hierher zeigen und nicht auf --dienst
|
||||
|
||||
Ein Doppelklick auf ein Desktop-Symbol soll Rippy OEFFNEN. Ob der Dienst
|
||||
schon laeuft, ist dem Nutzer egal — und er kann es auch nicht wissen.
|
||||
|
||||
Zeigte die Verknuepfung auf `--dienst`, startete jeder Klick einen
|
||||
ZWEITEN Server. Der zweite scheiterte am belegten Port, das Fenster
|
||||
blitzte auf und verschwand, und im Browser passierte nichts. Ein Symbol,
|
||||
das beim zweiten Klick nichts tut, ist schlimmer als keins.
|
||||
|
||||
Deshalb: erst NACHSEHEN, ob jemand antwortet. Nur wenn nicht, starten —
|
||||
und dann warten, bis er wirklich da ist, statt sofort einen Browser auf
|
||||
eine tote Adresse zu schicken.
|
||||
"""
|
||||
dienst = Dienst(port)
|
||||
|
||||
if not dienst.erreichbar(timeout=1.5):
|
||||
melden("Rippy wird gestartet …")
|
||||
programm = _eigene_datei()
|
||||
starte_hintergrund(programm)
|
||||
# Warten, bis er ANTWORTET — nicht bis der Prozess existiert.
|
||||
for _ in range(60):
|
||||
if dienst.erreichbar(timeout=1.0):
|
||||
break
|
||||
time.sleep(0.5)
|
||||
else:
|
||||
melden("Rippy antwortet nicht. Laeuft schon etwas auf Port %d?" % port)
|
||||
return 1
|
||||
|
||||
webbrowser.open(dienst.adresse)
|
||||
return 0
|
||||
|
||||
|
||||
def tray_bauen(dienst):
|
||||
"""Das Tray-Symbol. None, wenn pystray/Pillow fehlen."""
|
||||
try:
|
||||
@@ -380,6 +435,7 @@ def tray_bauen(dienst):
|
||||
HILFE = """Rippy für Windows
|
||||
|
||||
RippySetup.exe installieren (Doppelklick)
|
||||
Rippy.exe --oeffnen oeffnen (startet den Dienst, falls noetig)
|
||||
Rippy.exe --dienst im Hintergrund laufen lassen
|
||||
Rippy.exe --deinstallieren entfernen
|
||||
Rippy.exe --status nachsehen, was installiert ist
|
||||
@@ -388,6 +444,7 @@ Optionen:
|
||||
--port N Port (Vorgabe: 7788)
|
||||
--ziel PFAD Installationsordner
|
||||
--kein-autostart
|
||||
--keine-verknuepfungen ohne Desktop-Symbol und Startmenue-Eintrag
|
||||
--still ohne Rückmeldungen
|
||||
"""
|
||||
|
||||
@@ -401,6 +458,10 @@ def status() -> int:
|
||||
return 0
|
||||
melden(" In Programme+Features %s" % ("ja" if reg.ist_eingetragen() else "nein"))
|
||||
melden(" Autostart %s" % (reg.autostart_wert() or "nein"))
|
||||
for name, pfad in (("Desktop-Symbol", verknuepfungen.desktop_pfad()),
|
||||
("Startmenue", verknuepfungen.startmenue_pfad())):
|
||||
melden(" %-21s %s" % (name, pfad if pfad and os.path.isfile(pfad)
|
||||
else "nein"))
|
||||
for name, wert in sorted(reg.gelesene_werte().items()):
|
||||
melden(" %-18s %s" % (name, wert))
|
||||
return 0
|
||||
@@ -420,6 +481,8 @@ def main(argv=None) -> int:
|
||||
if "--deinstallieren" in argv:
|
||||
deinstallieren(still="--still" in argv)
|
||||
return 0
|
||||
if "--oeffnen" in argv:
|
||||
return oeffnen(int(wert("--port", STANDARD_PORT)))
|
||||
if "--dienst" in argv:
|
||||
return dienst_starten(int(wert("--port", STANDARD_PORT)))
|
||||
|
||||
@@ -428,6 +491,7 @@ def main(argv=None) -> int:
|
||||
ziel=wert("--ziel"),
|
||||
autostart="--kein-autostart" not in argv,
|
||||
starten_danach="--nicht-starten" not in argv,
|
||||
verknuepfen="--keine-verknuepfungen" not in argv,
|
||||
)
|
||||
melden("Rippy wurde nach %s installiert." % ziel)
|
||||
melden("Die Oberfläche öffnet sich gleich im Browser.")
|
||||
|
||||
Reference in New Issue
Block a user