From df6ebec3e2ee18d470e34f5476acd86ee4a3c153 Mon Sep 17 00:00:00 2001 From: VALLONGOL Date: Thu, 27 Nov 2025 13:51:51 +0100 Subject: [PATCH] sistemato la schermata per la differenza dei file --- PyUcc.ico | Bin 0 -> 32954 bytes pyucc/_version.py | 74 +++++++++++++++++++++++++++++++++++ pyucc/core/differ.py | 42 -------------------- pyucc/gui/action_handlers.py | 42 +++++++------------- pyucc/gui/diff_viewer.py | 16 +++++++- 5 files changed, 102 insertions(+), 72 deletions(-) create mode 100644 pyucc/_version.py diff --git a/PyUcc.ico b/PyUcc.ico index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..2c7d1338312ae4a99d833f3ac2107d859efd3af2 100644 GIT binary patch literal 32954 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 U%1>h1Zl4wsP3YMF+hzX0001^aKmY&$ literal 0 HcmV?d00001 diff --git a/pyucc/_version.py b/pyucc/_version.py new file mode 100644 index 0000000..bfe2427 --- /dev/null +++ b/pyucc/_version.py @@ -0,0 +1,74 @@ +# -*- coding: utf-8 -*- +# File generated by PyInstaller GUI Wrapper. DO NOT EDIT MANUALLY. +# Contains build-time information scraped from Git (if available) +# and a helper function to format version strings. + +import re + +# --- Version Data (Generated) --- +__version__ = "v.0.0.0.11-0-g7e0435a-dirty" +GIT_COMMIT_HASH = "7e0435ab7d0316bd2bcf5fdcd33cb84c39efa09c" +GIT_BRANCH = "master" +BUILD_TIMESTAMP = "2025-11-27T12:49:18.815605+00:00" +IS_GIT_REPO = True + +# --- Default Values (for comparison or fallback) --- +DEFAULT_VERSION = "0.0.0+unknown" +DEFAULT_COMMIT = "Unknown" +DEFAULT_BRANCH = "Unknown" + +# --- Helper Function --- +def get_version_string(format_string=None): + """ + Returns a formatted string based on the build version information. + + Args: + format_string (str, optional): A format string using placeholders. + Defaults to "{version} ({branch}/{commit_short})" if None. + Placeholders: + {{version}}: Full version string (e.g., 'v1.0.0-5-gabcdef-dirty') + {{tag}}: Clean tag part if exists (e.g., 'v1.0.0'), else DEFAULT_VERSION. + {{commit}}: Full Git commit hash. + {{commit_short}}: Short Git commit hash (7 chars). + {{branch}}: Git branch name. + {{dirty}}: '-dirty' if the repo was dirty, empty otherwise. + {{timestamp}}: Full build timestamp (ISO 8601 UTC). + {{timestamp_short}}: Build date only (YYYY-MM-DD). + {{is_git}}: 'Git' if IS_GIT_REPO is True, 'Unknown' otherwise. + + Returns: + str: The formatted version string, or an error message if formatting fails. + """ + if format_string is None: + format_string = "{version} ({branch}/{commit_short})" # Default format + + replacements = {} + try: + replacements['version'] = __version__ if __version__ else DEFAULT_VERSION + replacements['commit'] = GIT_COMMIT_HASH if GIT_COMMIT_HASH else DEFAULT_COMMIT + replacements['commit_short'] = GIT_COMMIT_HASH[:7] if GIT_COMMIT_HASH and len(GIT_COMMIT_HASH) >= 7 else DEFAULT_COMMIT + replacements['branch'] = GIT_BRANCH if GIT_BRANCH else DEFAULT_BRANCH + replacements['timestamp'] = BUILD_TIMESTAMP if BUILD_TIMESTAMP else "Unknown" + replacements['timestamp_short'] = BUILD_TIMESTAMP.split('T')[0] if BUILD_TIMESTAMP and 'T' in BUILD_TIMESTAMP else "Unknown" + replacements['is_git'] = "Git" if IS_GIT_REPO else "Unknown" + replacements['dirty'] = "-dirty" if __version__ and __version__.endswith('-dirty') else "" + + tag = DEFAULT_VERSION + if __version__ and IS_GIT_REPO: + match = re.match(r'^(v?([0-9]+(?:\.[0-9]+)*))', __version__) + if match: + tag = match.group(1) + replacements['tag'] = tag + + output_string = format_string + for placeholder, value in replacements.items(): + pattern = re.compile(r'{{\s*' + re.escape(placeholder) + r'\s*}}') + output_string = pattern.sub(str(value), output_string) + + if re.search(r'{\s*\w+\s*}', output_string): + pass # Or log a warning: print(f"Warning: Unreplaced placeholders found: {output_string}") + + return output_string + + except Exception as e: + return f"[Formatting Error: {e}]" diff --git a/pyucc/core/differ.py b/pyucc/core/differ.py index 31ac8d6..deccaea 100644 --- a/pyucc/core/differ.py +++ b/pyucc/core/differ.py @@ -144,9 +144,6 @@ class BaselineManager: if compute_sha1: # also compute for 0-byte files try: sha1 = _sha1_of_file(Path(fpath)) - # Log empty __init__.py files - if st.st_size == 0 and "__init__.py" in fn: - print(f"[BASELINE-SCAN] {rel_unix} (size={st.st_size}) SHA1={sha1}") except Exception: sha1 = None files_meta.append(FileMeta(path=rel_unix, size=st.st_size, mtime=st.st_mtime, sha1=sha1)) @@ -209,16 +206,6 @@ class BaselineManager: os.makedirs(dst_parent, exist_ok=True) try: shutil.copy2(src_file, dst_file) # copy2 preserves metadata - # Verify copy for empty __init__.py files - if fm.size == 0 and "__init__.py" in fm.path: - sha1_src = _sha1_of_file(Path(src_file)) - sha1_dst = _sha1_of_file(Path(dst_file)) - print(f"[BASELINE-COPY] {fm.path}") - print(f" Source SHA1: {sha1_src}") - print(f" Dest SHA1: {sha1_dst}") - print(f" Saved SHA1: {fm.sha1}") - if sha1_src != fm.sha1: - print(f" WARNING: Source file changed after initial scan!") except Exception: pass # skip files that cannot be copied @@ -468,9 +455,6 @@ class Differ: # Compute SHA1 for all files, including 0-byte files try: sha1 = _sha1_of_file(Path(fpath)) - # Log empty __init__.py files - if st.st_size == 0 and "__init__.py" in fn: - print(f"[DIFFER-CURRENT] {rel.replace(chr(92), '/')} (size={st.st_size}) SHA1={sha1}") except Exception: sha1 = None files_meta.append(FileMeta(path=rel.replace("\\", "/"), size=st.st_size, mtime=st.st_mtime, sha1=sha1)) @@ -715,15 +699,6 @@ class Differ: return res def diff(self) -> Dict: - import sys - sys.stdout.flush() - sys.stderr.flush() - print(f"\n{'='*80}", flush=True) - print(f"[DIFFER-START] Using baseline: {self.baseline.baseline_id}", flush=True) - print(f"[DIFFER-START] Baseline files dir: {self.baseline_files_dir}", flush=True) - print(f"[DIFFER-START] Current dir: {self.current_dir}", flush=True) - print(f"{'='*80}\n", flush=True) - baseline_files = self.baseline.files current_files = self.build_current_file_list() pairs = self.match_files(baseline_files, current_files) @@ -742,23 +717,6 @@ class Differ: for a, b in pairs: fa = os.path.join(self.baseline_files_dir, a.path) if a is not None else None fb = os.path.join(self.current_dir, b.path) if b is not None else None - - # DEBUG: Log empty __init__.py comparisons - if a and b and a.size == 0 and "__init__.py" in a.path: - import sys - print(f"\n[DIFFER-COMPARE] {a.path}", flush=True) - print(f" Baseline SHA1 (metadata): {a.sha1}", flush=True) - print(f" Current SHA1 (metadata): {b.sha1}", flush=True) - print(f" Baseline file: {fa}", flush=True) - print(f" Current file: {fb}", flush=True) - if fa and os.path.exists(fa): - sha1_baseline_actual = _sha1_of_file(Path(fa)) - print(f" Baseline SHA1 (actual): {sha1_baseline_actual}", flush=True) - if fb and os.path.exists(fb): - sha1_current_actual = _sha1_of_file(Path(fb)) - print(f" Current SHA1 (actual): {sha1_current_actual}", flush=True) - sys.stdout.flush() - futures.append(ex.submit(self._diff_file_pair, fa, fb)) for (a, b), fut in zip(pairs, futures): res = fut.result() diff --git a/pyucc/gui/action_handlers.py b/pyucc/gui/action_handlers.py index e432d46..4065b76 100644 --- a/pyucc/gui/action_handlers.py +++ b/pyucc/gui/action_handlers.py @@ -340,20 +340,20 @@ class ActionHandlers: rows = (_row_from_pair(p) for p in result.get('pairs', [])) export_rows_to_csv(csv_path, headers, rows) - # Generate text report - profile_config = { - 'name': profile_name, - 'root': project, - 'paths': paths if paths else [project], - 'languages': allowed_exts if allowed_exts else [], - 'exclude_patterns': ignore_patterns - } - generate_differ_report(result, profile_config, baseline_id, report_path) - except Exception: - # non-fatal: continue even if export fails - pass - - # Show summary dialog + # Generate text report + profile_config = { + 'name': profile_name, + 'root': project, + 'paths': paths if paths else [project], + 'languages': allowed_exts if allowed_exts else [], + 'exclude_patterns': ignore_patterns + } + generate_differ_report(result, profile_config, baseline_id, report_path) + self.app.log(f"Differ report saved to: {report_path}", level='INFO') + except Exception as e: + # non-fatal: continue even if export fails + self.app.log(f"Failed to export differ results: {e}", level='WARNING') + pass # Show summary dialog self._show_differ_summary_dialog(result, baseline_id, bdir) except Exception: self.app._set_phase('Idle') @@ -515,25 +515,11 @@ class ActionHandlers: b.sha1 = None # Compare hashes - # DEBUG: Log SHA1 comparison for empty __init__.py files - if a and b and a.size == 0 and "__init__.py" in str(a.path): - import sys - print(f"\n[ACTION_HANDLERS] SHA1 comparison for {a.path}", flush=True) - print(f" a.sha1={getattr(a, 'sha1', 'NO ATTR')}", flush=True) - print(f" b.sha1={getattr(b, 'sha1', 'NO ATTR')}", flush=True) - print(f" hasattr(a, 'sha1')={hasattr(a, 'sha1')}", flush=True) - print(f" a.sha1 is truthy={bool(a.sha1) if hasattr(a, 'sha1') else False}", flush=True) - print(f" b.sha1 is truthy={bool(b.sha1)}", flush=True) - print(f" Match: {a.sha1 == b.sha1 if (hasattr(a, 'sha1') and a.sha1 and b.sha1) else 'N/A'}", flush=True) - sys.stdout.flush() - if hasattr(a, 'sha1') and a.sha1 and b.sha1 and a.sha1 == b.sha1: # Identical files res['counts'] = {'added': 0, 'deleted': 0, 'modified': 0, 'unmodified': 1} else: # Modified file - if a and b and a.size == 0 and "__init__.py" in str(a.path): - print(f" → Marked as MODIFIED!", flush=True) res['counts'] = {'added': 0, 'deleted': 0, 'modified': 1, 'unmodified': 0} else: # Both None (shouldn't happen) diff --git a/pyucc/gui/diff_viewer.py b/pyucc/gui/diff_viewer.py index 0130f76..0656e79 100644 --- a/pyucc/gui/diff_viewer.py +++ b/pyucc/gui/diff_viewer.py @@ -114,6 +114,9 @@ class DiffViewer(tk.Toplevel): highlightbackground='#ccc') self.minimap.grid(row=1, column=1, sticky='nsew', padx=2, pady=0) + # Ridisegna minimap quando il canvas viene ridimensionato + self.minimap.bind('', lambda e: self._draw_minimap()) + # Scrollbar orizzontali scrollbar_h_a = ttk.Scrollbar(main_frame, orient='horizontal', command=self.text_a.xview) scrollbar_h_a.grid(row=2, column=0, sticky='ew', padx=(2, 1)) @@ -413,13 +416,22 @@ class DiffViewer(tk.Toplevel): # Rimuovi rettangolo precedente self.minimap.delete('viewport') - # Calcola posizione viewport + if not hasattr(self, 'minimap_blocks') or not self.minimap_blocks: + return + + # Calcola posizione viewport basandosi sul totale delle linee yview = self.text_a.yview() canvas_height = self.minimap.winfo_height() + canvas_width = self.minimap.winfo_width() + # yview restituisce (frazione_inizio, frazione_fine) del documento + # Usa queste frazioni direttamente sull'altezza del canvas y1 = yview[0] * canvas_height y2 = yview[1] * canvas_height - canvas_width = self.minimap.winfo_width() + + # Assicurati che il viewport sia visibile (minimo 5 pixel) + if y2 - y1 < 5: + y2 = y1 + 5 # Disegna rettangolo viewport self.minimap.create_rectangle(0, y1, canvas_width, y2,