Skip to content

Commit 714c9ee

Browse files
committed
Merge development into main, keeping development changes for conflicts
2 parents 35d7a07 + a60de01 commit 714c9ee

54 files changed

Lines changed: 5368 additions & 1634 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/omnipkg/__main__.py

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,28 @@
11
from __future__ import annotations
2-
32
from omnipkg.common_utils import safe_print
4-
53
try:
64
from .common_utils import safe_print
75
except ImportError:
86
pass
97

108
import sys
9+
import os
1110

1211
from .cli import main
13-
from .core import ConfigManager # ← Import from core, not config_manager
14-
from .i18n import _ # ← Import the translator instance, not setup_i18n
12+
from .core import ConfigManager
13+
from .i18n import _
1514

1615
# Initialize the config manager
1716
config_manager = ConfigManager()
1817

19-
# Set the language from config
20-
# The _ translator has a set_language method
21-
_.set_language(config_manager.config.get("language", "en"))
18+
# Language priority: OMNIPKG_LANG env var > config file > default (en)
19+
language = os.environ.get("OMNIPKG_LANG") or config_manager.config.get("language", "en")
20+
21+
# Set the language in the translator
22+
_.set_language(language)
23+
24+
# ⚠️ CRITICAL: Set in os.environ so subprocesses inherit it!
25+
os.environ["OMNIPKG_LANG"] = language # ← ADD THIS LINE IF MISSING!
2226

2327
# This runs the main function and ensures the script exits with the correct status code.
2428
if __name__ == "__main__":

src/omnipkg/apis/local_bridge.py

Lines changed: 31 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -551,13 +551,13 @@ def telemetry():
551551
def run_bridge_server():
552552
"""The entry point for the background process."""
553553
if not HAS_WEB_DEPS:
554-
print(_('❌ Flask missing. Cannot start server.'))
554+
safe_print(_('❌ Flask missing. Cannot start server.'))
555555
sys.exit(1)
556556

557557
try:
558558
port = find_free_port(5000)
559559
except RuntimeError as e:
560-
print(_('❌ {}').format(e))
560+
safe_print(_('❌ {}').format(e))
561561
sys.exit(1)
562562

563563
print(_('Local Port: {}').format(port), flush=True)
@@ -580,16 +580,16 @@ def __init__(self):
580580
def start(self):
581581
"""Start the web bridge in background."""
582582
if not HAS_WEB_DEPS:
583-
print(_('❌ Dependencies missing. Please run: pip install flask flask-cors'))
583+
safe_print(_('❌ Dependencies missing. Please run: pip install flask flask-cors'))
584584
return 1
585585

586586
if self.is_running():
587587
port = self._get_port()
588-
print(_('✅ Web bridge already running on port {}').format(port))
589-
print(_('🌍 Dashboard: {}#{}').format(PRIMARY_DASHBOARD, port))
588+
safe_print(_('✅ Web bridge already running on port {}').format(port))
589+
safe_print(_('🌍 Dashboard: {}#{}').format(PRIMARY_DASHBOARD, port))
590590
return 0
591591

592-
print(_('🚀 Starting web bridge...'))
592+
safe_print(_('🚀 Starting web bridge...'))
593593
cmd = [sys.executable, "-m", "omnipkg.apis.local_bridge"]
594594

595595
# Cross-platform detachment logic
@@ -616,29 +616,29 @@ def start(self):
616616
port = self._get_port()
617617
url = f"{PRIMARY_DASHBOARD}#{port}"
618618
print("="*60)
619-
print(_('✅ Web bridge started successfully'))
620-
print(_('🔗 Local Port: {}').format(port))
621-
print(_('📊 PID: {}').format(process.pid))
622-
print(_('🌍 Dashboard: {}').format(url))
619+
safe_print(_('✅ Web bridge started successfully'))
620+
safe_print(_('🔗 Local Port: {}').format(port))
621+
safe_print(_('📊 PID: {}').format(process.pid))
622+
safe_print(_('🌍 Dashboard: {}').format(url))
623623
print("="*60)
624624
webbrowser.open(url)
625625
return 0
626626
else:
627-
print(_('❌ Failed to start. Check logs.'))
627+
safe_print(_('❌ Failed to start. Check logs.'))
628628
return 1
629629
except Exception as e:
630-
print(_('❌ Launch error: {}').format(e))
630+
safe_print(_('❌ Launch error: {}').format(e))
631631
return 1
632632

633633
def stop(self):
634634
"""Stop the web bridge safely across platforms."""
635635
if not self.is_running():
636-
print(_('⚠️ Web bridge is not running'))
636+
safe_print(_('⚠️ Web bridge is not running'))
637637
return 0
638638

639639
try:
640640
pid = int(self.pid_file.read_text())
641-
print(_('🛑 Stopping web bridge (PID: {})...').format(pid))
641+
safe_print(_('🛑 Stopping web bridge (PID: {})...').format(pid))
642642

643643
if os.name == 'nt':
644644
subprocess.run(["taskkill", "/PID", str(pid), "/T", "/F"],
@@ -651,33 +651,33 @@ def stop(self):
651651

652652
if self.pid_file.exists():
653653
self.pid_file.unlink()
654-
print(_('✅ Web bridge stopped'))
654+
safe_print(_('✅ Web bridge stopped'))
655655
return 0
656656
except Exception as e:
657-
print(_('❌ Error stopping: {}').format(e))
657+
safe_print(_('❌ Error stopping: {}').format(e))
658658
if self.pid_file.exists():
659659
self.pid_file.unlink()
660660
return 1
661661

662662
def restart(self):
663663
"""Restart the web bridge."""
664-
print(_('🔄 Restarting web bridge...'))
664+
safe_print(_('🔄 Restarting web bridge...'))
665665
self.stop()
666666
time.sleep(1)
667667
return self.start()
668668

669669
def status(self):
670670
"""Check web bridge status."""
671671
if not self.is_running():
672-
print(_('❌ Web bridge is not running'))
673-
print(_('\n💡 Start with: 8pkg web start'))
672+
safe_print(_('❌ Web bridge is not running'))
673+
safe_print(_('\n💡 Start with: 8pkg web start'))
674674
return 1
675675

676676
if not HAS_SYS_DEPS:
677-
print(_("⚠️ 'psutil' not installed. Limited status info available."))
677+
safe_print(_("⚠️ 'psutil' not installed. Limited status info available."))
678678
pid = int(self.pid_file.read_text())
679679
port = self._get_port()
680-
print(_('✅ Running (PID: {}, Port: {})').format(pid, port))
680+
safe_print(_('✅ Running (PID: {}, Port: {})').format(pid, port))
681681
return 0
682682

683683
pid = int(self.pid_file.read_text())
@@ -689,28 +689,28 @@ def status(self):
689689
uptime = time.time() - process.create_time()
690690

691691
print("="*60)
692-
print(_('✅ Web Bridge Status: RUNNING'))
692+
safe_print(_('✅ Web Bridge Status: RUNNING'))
693693
print("="*60)
694-
print(_('🔗 Port: {}').format(port))
695-
print(_('📊 PID: {}').format(pid))
696-
print(f"💾 Memory: {mem_info.rss / 1024 / 1024:.1f} MB")
697-
print(_('⏱️ Uptime: {}').format(self._format_uptime(uptime)))
698-
print(_('🌍 Dashboard: {}#{}').format(PRIMARY_DASHBOARD, port))
694+
safe_print(_('🔗 Port: {}').format(port))
695+
safe_print(_('📊 PID: {}').format(pid))
696+
safe_print(f"💾 Memory: {mem_info.rss / 1024 / 1024:.1f} MB")
697+
safe_print(_('⏱️ Uptime: {}').format(self._format_uptime(uptime)))
698+
safe_print(_('🌍 Dashboard: {}#{}').format(PRIMARY_DASHBOARD, port))
699699
print("="*60)
700700
return 0
701701
except psutil.NoSuchProcess:
702-
print(_('⚠️ PID file exists but process is dead. Cleaning up...'))
702+
safe_print(_('⚠️ PID file exists but process is dead. Cleaning up...'))
703703
self.pid_file.unlink()
704704
return 1
705705

706706
def show_logs(self, follow=False, lines=50):
707707
"""Display web bridge logs."""
708708
if not self.log_file.exists():
709-
print(_('❌ Log file not found: {}').format(self.log_file))
709+
safe_print(_('❌ Log file not found: {}').format(self.log_file))
710710
return 1
711711

712712
if follow:
713-
print(_('📝 Following logs (Ctrl+C to stop)...\n'))
713+
safe_print(_('📝 Following logs (Ctrl+C to stop)...\n'))
714714
try:
715715
subprocess.run(["tail", "-f", str(self.log_file)], check=True)
716716
except (FileNotFoundError, subprocess.CalledProcessError):
@@ -727,7 +727,7 @@ def show_logs(self, follow=False, lines=50):
727727
pass
728728
except KeyboardInterrupt:
729729
pass
730-
print(_('\n✅ Stopped following logs'))
730+
safe_print(_('\n✅ Stopped following logs'))
731731
return 0
732732
else:
733733
try:

src/omnipkg/cli.py

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
from omnipkg.common_utils import safe_print
44

5+
from omnipkg.i18n import _, SUPPORTED_LANGUAGES
56
"""omnipkg CLI - Enhanced with runtime interpreter switching and language support"""
67
try:
78
from .common_utils import safe_print
@@ -33,7 +34,6 @@
3334
from .common_utils import print_header
3435
from .core import ConfigManager
3536
from .core import omnipkg as OmnipkgCore
36-
from omnipkg.i18n import _, SUPPORTED_LANGUAGES
3737

3838
project_root = Path(__file__).resolve().parent.parent
3939
TESTS_DIR = Path(__file__).parent.parent / "tests"
@@ -884,7 +884,7 @@ def main():
884884
sys.argv.insert(2, forced_version)
885885

886886
if os.environ.get("OMNIPKG_DEBUG") == "1":
887-
print(f"[DEBUG-CLI] Detected: {prog_name} -> forcing --python {forced_version}", file=sys.stderr)
887+
print(_('[DEBUG-CLI] Detected: {} -> forcing --python {}').format(prog_name, forced_version), file=sys.stderr)
888888

889889
# 🎪 NORMALIZE FLAGS AND COMMANDS (but not package names)
890890
normalized_argv = [sys.argv[0]]
@@ -917,11 +917,27 @@ def main():
917917
# Always show "omnipkg" - 8pkg is just an alias
918918
safe_print(_("omnipkg {}").format(get_version()))
919919
return 0
920+
# BEFORE creating ConfigManager
921+
os.environ["OMNIPKG_LANG"] = os.environ.get("OMNIPKG_LANG", "")
922+
923+
cm = ConfigManager()
924+
user_lang = global_args.lang or cm.config.get("language") or os.environ.get("OMNIPKG_LANG")
920925

921926
cm = ConfigManager()
922927
user_lang = global_args.lang or cm.config.get("language")
928+
929+
# NEW: Check environment variable first (highest priority)
930+
if not user_lang:
931+
user_lang = os.environ.get("OMNIPKG_LANG")
932+
923933
if user_lang:
934+
# Force re-import to pick up env var
935+
import importlib
936+
from omnipkg import i18n
937+
importlib.reload(i18n)
938+
924939
_.set_language(user_lang)
940+
os.environ["OMNIPKG_LANG"] = user_lang
925941

926942
# --- DECIDE MINIMAL VS FULL INITIALIZATION ---
927943
use_minimal = False
@@ -1238,23 +1254,23 @@ def main():
12381254

12391255
try:
12401256
if os.environ.get("OMNIPKG_DEBUG") == "1":
1241-
safe_print(f"[DEBUG] Spawning shell: {shell}")
1242-
safe_print(f"[DEBUG] Target Python: {python_path}")
1243-
safe_print(f"[DEBUG] OMNIPKG_PYTHON: {version}")
1244-
safe_print(f"[DEBUG] OMNIPKG_VENV_ROOT: {original_venv}")
1245-
safe_print(f"[DEBUG] Shims directory: {shims_dir}")
1246-
safe_print(f"[DEBUG] PATH prefix: {deduped[0]}")
1247-
safe_print(f"[DEBUG] Cleanup script: {cleanup_file}")
1248-
safe_print(f"[DEBUG] CONDA_PREFIX: {new_env.get('CONDA_PREFIX', 'NOT SET')}")
1249-
safe_print(f"[DEBUG] CONDA_DEFAULT_ENV: {new_env.get('CONDA_DEFAULT_ENV', 'NOT SET')}")
1257+
safe_print(_('[DEBUG] Spawning shell: {}').format(shell))
1258+
safe_print(_('[DEBUG] Target Python: {}').format(python_path))
1259+
safe_print(_('[DEBUG] OMNIPKG_PYTHON: {}').format(version))
1260+
safe_print(_('[DEBUG] OMNIPKG_VENV_ROOT: {}').format(original_venv))
1261+
safe_print(_('[DEBUG] Shims directory: {}').format(shims_dir))
1262+
safe_print(_('[DEBUG] PATH prefix: {}').format(deduped[0]))
1263+
safe_print(_('[DEBUG] Cleanup script: {}').format(cleanup_file))
1264+
safe_print(_('[DEBUG] CONDA_PREFIX: {}').format(new_env.get('CONDA_PREFIX', 'NOT SET')))
1265+
safe_print(_('[DEBUG] CONDA_DEFAULT_ENV: {}').format(new_env.get('CONDA_DEFAULT_ENV', 'NOT SET')))
12501266

12511267
safe_print(_("🐚 Spawning new shell... (Type 'exit' to return)"))
12521268
safe_print(f" 🐍 Python {version} context active (via shims)")
1253-
safe_print(f" 💡 Note: Type 'exit' to clean up and return")
1269+
safe_print(_(" 💡 Note: Type 'exit' to clean up and return"))
12541270

12551271
conda_env = os.environ.get("CONDA_DEFAULT_ENV", "")
12561272
if conda_env:
1257-
safe_print(f" 📦 Conda env '{conda_env}' preserved")
1273+
safe_print(_(" 📦 Conda env '{}' preserved").format(conda_env))
12581274

12591275
# Launch interactive shell
12601276
os.execle(

src/omnipkg/commands/run.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2624,6 +2624,11 @@ def execute_run_command(
26242624
# ADD THIS LINE - Propagate verbose flag to subprocesses
26252625
if verbose:
26262626
os.environ["OMNIPKG_VERBOSE"] = "1"
2627+
2628+
# NEW: Ensure language persists to subprocess
2629+
current_lang = config_manager.config.get("language")
2630+
if current_lang:
2631+
os.environ["OMNIPKG_LANG"] = current_lang
26272632

26282633
if not cmd_args:
26292634
safe_print(_("❌ Error: No script or command specified to run."))

0 commit comments

Comments
 (0)