"""Configuration: sedona home lives in `system.properties` next to this file. Same key sedonac itself uses, but written as a plain Windows path: sedona.home=C:\\path\\to\\sedona We only *read* this file, so there is no reason to escape anything. Java's Properties (what sedonac uses) treats `\\` as an escape, so its own files double them up -- `\\\\path\\\\to`. Both parse here: `\\\\` collapses to `\\`, and every other backslash is kept literally, so `C:\\niagara` does not turn into a newline. If the key is missing, or the directory no longer holds `manifests/`, a folder chooser is shown and the answer is written back to `system.properties`. """ import os, sys HERE = os.path.dirname(os.path.abspath(__file__)) PROPS = os.path.join(HERE, "system.properties") KEY = "sedona.home" # ---------- .properties ---------- def _unescape(v): """Collapse `\\\\` to `\\`; leave any other backslash alone. Accepts both our plain paths and java-escaped ones, and never mistakes a path segment for an escape (`C:\\niagara` stays `C:\\niagara`). """ out, i = [], 0 while i < len(v): if v[i] == "\\" and i + 1 < len(v) and v[i + 1] == "\\": i += 1 out.append(v[i]) i += 1 return "".join(out) def read_props(path=PROPS): props = {} if not os.path.exists(path): return props with open(path, "r", encoding="utf-8", errors="replace") as f: for line in f: line = line.strip() if not line or line[0] in "#!" or "=" not in line: continue k, v = line.split("=", 1) props[k.strip()] = _unescape(v.strip()) # last wins return props def write_prop(key, value, path=PROPS): """Set `key`, keeping every other line of the file intact.""" lines = [] if os.path.exists(path): with open(path, "r", encoding="utf-8", errors="replace") as f: lines = f.read().splitlines() new = "%s=%s" % (key, value) done = False for i, line in enumerate(lines): s = line.strip() if s and s[0] not in "#!" and "=" in s and s.split("=", 1)[0].strip() == key: lines[i] = new if not done else "#" + line # comment out later dupes done = True if not done: lines.append(new) with open(path, "w", encoding="utf-8") as f: f.write("\n".join(lines) + "\n") # ---------- dialogs ---------- def _tk(): """A hidden root window, or None when no GUI is available.""" try: import tkinter as tk root = tk.Tk() root.withdraw() return root except Exception: return None def ask_directory(title, initial=None): root = _tk() if root is None: return None try: from tkinter import filedialog return filedialog.askdirectory(title=title, initialdir=initial or HERE) or None finally: root.destroy() def ask_open_file(title, filetypes, initial=None): root = _tk() if root is None: return None try: from tkinter import filedialog return filedialog.askopenfilename(title=title, filetypes=filetypes, initialdir=initial or HERE) or None finally: root.destroy() def ask_save_file(title, filetypes, defaultextension, initialfile=None, initial=None): root = _tk() if root is None: return None try: from tkinter import filedialog return filedialog.asksaveasfilename(title=title, filetypes=filetypes, defaultextension=defaultextension, initialfile=initialfile, initialdir=initial or HERE) or None finally: root.destroy() # ---------- api ---------- def is_sedona_home(path): return bool(path) and os.path.isdir(os.path.join(path, "manifests")) def get_sedona_home(interactive=True): """Path from system.properties, prompting (and saving) when unusable.""" home = read_props().get(KEY) if is_sedona_home(home): return home if not interactive: raise SystemExit("%s not set (or has no manifests/) in %s" % (KEY, PROPS)) why = "not set in" if not home else "invalid (%s), update" % home print("sedona.home %s %s -- please choose the sedona installation folder" % (why, PROPS)) while True: picked = ask_directory("Select Sedona home (the folder containing manifests/)", home if home and os.path.isdir(home) else None) if not picked: raise SystemExit("no sedona home selected") picked = os.path.normpath(picked) if is_sedona_home(picked): write_prop(KEY, picked) print("saved %s=%s to %s" % (KEY, picked, PROPS)) return picked print(" %s has no manifests/ subfolder -- try again" % picked) SAX = ("Sedona app XML", "*.sax") SAB = ("Sedona app binary", "*.sab") ANY = ("All files", "*.*") def choose_input_file(initial=None): """Pick the file to convert -- direction follows its extension.""" return ask_open_file("Select the .sax or .sab application file to convert", [("Sedona app (*.sax, *.sab)", "*.sax *.sab"), SAX, SAB, ANY], initial) def choose_sax_file(initial=None): return ask_open_file("Select the .sax application file", [SAX, ANY], initial) def choose_sab_file(initialfile=None, initial=None): """Save-as for the .sab produced from a .sax.""" return ask_save_file("Save the .sab application file", [SAB, ANY], ".sab", initialfile, initial) def choose_sax_output(initialfile=None, initial=None): """Save-as for the .sax produced from a .sab.""" return ask_save_file("Save the .sax application file", [SAX, ANY], ".sax", initialfile, initial) if __name__ == "__main__": print(get_sedona_home())