Lokalen Rechnungsassistenten mit Vorlagen und PDF-Vorschau ergänzen
This commit is contained in:
1 parent
f447603af4
commit
b9f307fc81
15 files changed
+1423
-26
No files matched your search
@@ -1,4 +1,4 @@
|
||||
"""Checkout maintenance; standard library only, so broken dependencies cannot block rollback."""
|
||||
"""Laufzeiten isoliert aktualisieren; Rollback bleibt ohne Zusatzpakete nutzbar."""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
@@ -61,6 +61,7 @@ class Maintenance:
|
||||
env.pop(key, None)
|
||||
env['JR_EINVOICE_MUSTANG_JAR'] = str(release / 'Mustang-CLI.jar')
|
||||
env['JR_EINVOICE_INTEGRATION'] = '1'
|
||||
env['QT_QPA_PLATFORM'] = 'offscreen'
|
||||
self.log.info('PRÜFUNG: pip check, WeasyPrint, CLI und echte Rechnungs-/Negativtests')
|
||||
self.run([python, '-I', '-m', 'pip', 'check'], env=env)
|
||||
with tempfile.TemporaryDirectory(prefix='einvoice-health-') as folder:
|
||||
@@ -87,7 +88,7 @@ class Maintenance:
|
||||
def activate(self, target: Path):
|
||||
active = self.state / 'current'
|
||||
old = active.resolve() if active.is_symlink() else self.baseline()
|
||||
# Persist rollback target before changing the single runtime pointer.
|
||||
# Rücksprungziel vor dem einzigen aktiven Laufzeitzeiger sichern.
|
||||
point(self.state / 'previous', old)
|
||||
self.log.info('AKTIVIERUNG: %s', target)
|
||||
point(active, target)
|
||||
@@ -99,7 +100,7 @@ class Maintenance:
|
||||
raise
|
||||
self.log.info('ERFOLG: Laufzeit aktiv. Rollback verfügbar: %s', old)
|
||||
|
||||
def update(self, apply=False, version=None):
|
||||
def update(self, apply=False, version=None, gui=False):
|
||||
version = version or get_latest_mustang_version(self.log)
|
||||
if not re.fullmatch(r'\d+(?:\.\d+)+', version):
|
||||
raise ValueError(f'Keine stabile Mustang-Version: {version!r}; --mustang-version verwenden.')
|
||||
@@ -109,9 +110,14 @@ class Maintenance:
|
||||
self.run(['java', '-version'])
|
||||
self.run([sys.executable, '-m', 'venv', release / 'venv'])
|
||||
python = release / 'venv/bin/python'
|
||||
# Eine einmal aktivierte Oberfläche auch bei späteren Updates mitnehmen.
|
||||
current_manifest = self.state / 'current/manifest.json'
|
||||
if current_manifest.is_file():
|
||||
gui = gui or json.loads(current_manifest.read_text()).get('gui', False)
|
||||
extras = 'pdf,gui' if gui else 'pdf'
|
||||
self.run([python, '-m', 'pip', 'install', '--upgrade', 'pip'])
|
||||
self.run([python, '-m', 'pip', 'install', '--upgrade', '--upgrade-strategy', 'eager',
|
||||
'--report', release / 'install-report.json', f'{self.root}[pdf]'])
|
||||
'--report', release / 'install-report.json', f'{self.root}[{extras}]'])
|
||||
install_mustang(version, release / 'Mustang-CLI.jar', self.log)
|
||||
frozen = self.run([python, '-m', 'pip', 'freeze', '--all'])
|
||||
(release / 'requirements.freeze.txt').write_text(frozen)
|
||||
@@ -122,7 +128,7 @@ class Maintenance:
|
||||
before = old.get(package['name'].lower(), '(neu)')
|
||||
if before != package['version']:
|
||||
self.log.info('VERSION: %s: %s -> %s', package['name'], before, package['version'])
|
||||
manifest = {'mustang': version, 'jar_sha256': hashlib.sha256((release / 'Mustang-CLI.jar').read_bytes()).hexdigest(),
|
||||
manifest = {'mustang': version, 'gui': gui, 'jar_sha256': hashlib.sha256((release / 'Mustang-CLI.jar').read_bytes()).hexdigest(),
|
||||
'packages': packages, 'source_commit': self.run(['git', 'rev-parse', 'HEAD']).strip()}
|
||||
(release / 'manifest.json').write_text(json.dumps(manifest, indent=2) + '\n')
|
||||
self.health(release)
|
||||
@@ -147,6 +153,7 @@ def main(argv=None):
|
||||
mode.add_argument('--rollback', action='store_true', help='Vorherigen Stand prüfen und aktivieren')
|
||||
mode.add_argument('--status', action='store_true', help='Aktiven und vorherigen Stand anzeigen, ohne Netzwerk')
|
||||
parser.add_argument('--mustang-version', help='Explizite stabile Version statt Maven-Release')
|
||||
parser.add_argument('--with-gui', action='store_true', help='Desktop-Oberfläche einschließlich PDF-Anzeige installieren')
|
||||
args = parser.parse_args(argv)
|
||||
root = Path(__file__).resolve().parent.parent
|
||||
state = root / '.runtime'
|
||||
@@ -170,7 +177,7 @@ def main(argv=None):
|
||||
elif args.rollback:
|
||||
maintenance.rollback()
|
||||
else:
|
||||
maintenance.update(args.apply, args.mustang_version)
|
||||
maintenance.update(args.apply, args.mustang_version, args.with_gui)
|
||||
except (Exception, KeyboardInterrupt) as exc:
|
||||
logging.getLogger('maintenance').error('FEHLER: %s; nicht aktivierte Kandidaten bleiben zur Diagnose erhalten.', exc)
|
||||
return 1
|
||||
|
||||
Reference in new issue
Block a user