Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
11f86972c5 | ||
|
|
05eb064392 | ||
|
|
1208029c66 |
BIN
CodeBridge.ico
BIN
CodeBridge.ico
Binary file not shown.
|
Before Width: | Height: | Size: 0 B After Width: | Height: | Size: 15 KiB |
74
codebridge/_version.py
Normal file
74
codebridge/_version.py
Normal file
@ -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.6-0-g1208029"
|
||||||
|
GIT_COMMIT_HASH = "1208029c66239b5e9e5356f9643172941e7cfce9"
|
||||||
|
GIT_BRANCH = "master"
|
||||||
|
BUILD_TIMESTAMP = "2025-12-23T13:57:10.904302+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}]"
|
||||||
@ -110,8 +110,11 @@ class DiffViewer(tk.Toplevel):
|
|||||||
# Colors for diff (left: source, right: destination)
|
# Colors for diff (left: source, right: destination)
|
||||||
self.left_text.tag_config("added", background="#d6ffd6")
|
self.left_text.tag_config("added", background="#d6ffd6")
|
||||||
self.left_text.tag_config("changed", background="#fff3bf")
|
self.left_text.tag_config("changed", background="#fff3bf")
|
||||||
|
# inline changed region (more accentuated)
|
||||||
|
self.left_text.tag_config("changed_inline", background="#ffb366")
|
||||||
self.right_text.tag_config("removed", background="#ffd6d6")
|
self.right_text.tag_config("removed", background="#ffd6d6")
|
||||||
self.right_text.tag_config("changed", background="#fff3bf")
|
self.right_text.tag_config("changed", background="#fff3bf")
|
||||||
|
self.right_text.tag_config("changed_inline", background="#ffb366")
|
||||||
# Bind mousewheel to synchronize scrolling between both panes
|
# Bind mousewheel to synchronize scrolling between both panes
|
||||||
self.left_text.bind("<MouseWheel>", self._on_mousewheel)
|
self.left_text.bind("<MouseWheel>", self._on_mousewheel)
|
||||||
self.right_text.bind("<MouseWheel>", self._on_mousewheel)
|
self.right_text.bind("<MouseWheel>", self._on_mousewheel)
|
||||||
@ -347,6 +350,50 @@ class DiffViewer(tk.Toplevel):
|
|||||||
self.right_text.tag_add('changed', start, end)
|
self.right_text.tag_add('changed', start, end)
|
||||||
for k in range(i1, i2):
|
for k in range(i1, i2):
|
||||||
right_lines[k] = 'changed'
|
right_lines[k] = 'changed'
|
||||||
|
# Attempt intraline/highlight of exact differing character ranges
|
||||||
|
try:
|
||||||
|
# pair up lines in the replace block where possible
|
||||||
|
left_block_len = j2 - j1
|
||||||
|
right_block_len = i2 - i1
|
||||||
|
pairs = min(left_block_len, right_block_len)
|
||||||
|
for offset in range(pairs):
|
||||||
|
lidx = j1 + offset
|
||||||
|
ridx = i1 + offset
|
||||||
|
# get raw line text without trailing newline for character offsets
|
||||||
|
try:
|
||||||
|
left_line = src_lines[lidx].rstrip('\n')
|
||||||
|
except Exception:
|
||||||
|
left_line = ''
|
||||||
|
try:
|
||||||
|
right_line = dest_lines[ridx].rstrip('\n')
|
||||||
|
except Exception:
|
||||||
|
right_line = ''
|
||||||
|
# if either line is empty, skip detailed matching
|
||||||
|
if not left_line and not right_line:
|
||||||
|
continue
|
||||||
|
sm = difflib.SequenceMatcher(None, left_line, right_line)
|
||||||
|
for ctag, a1, a2, b1, b2 in sm.get_opcodes():
|
||||||
|
if ctag == 'equal':
|
||||||
|
continue
|
||||||
|
# apply inline tags: left side chars a1..a2, right side b1..b2
|
||||||
|
# left
|
||||||
|
if a2 > a1:
|
||||||
|
try:
|
||||||
|
start_idx = f"{lidx+1}.{a1}"
|
||||||
|
end_idx = f"{lidx+1}.{a2}"
|
||||||
|
self.left_text.tag_add('changed_inline', start_idx, end_idx)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
# right
|
||||||
|
if b2 > b1:
|
||||||
|
try:
|
||||||
|
start_idx = f"{ridx+1}.{b1}"
|
||||||
|
end_idx = f"{ridx+1}.{b2}"
|
||||||
|
self.right_text.tag_add('changed_inline', start_idx, end_idx)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
elif tag == 'delete':
|
elif tag == 'delete':
|
||||||
# lines present in dest (right) but deleted from source -> removed on right
|
# lines present in dest (right) but deleted from source -> removed on right
|
||||||
if i2 > i1:
|
if i2 > i1:
|
||||||
@ -554,9 +601,15 @@ class DiffViewer(tk.Toplevel):
|
|||||||
dst_text = self.left_text if dst == 'left' else self.right_text
|
dst_text = self.left_text if dst == 'left' else self.right_text
|
||||||
if not messagebox.askyesno('Confirm copy all', f'Copy entire content from {src} to {dst}?', parent=self):
|
if not messagebox.askyesno('Confirm copy all', f'Copy entire content from {src} to {dst}?', parent=self):
|
||||||
return
|
return
|
||||||
content = src_text.get('1.0', 'end')
|
# use end-1c to avoid the Text widget's extra trailing newline
|
||||||
|
content = src_text.get('1.0', 'end-1c')
|
||||||
dst_text.delete('1.0', 'end')
|
dst_text.delete('1.0', 'end')
|
||||||
dst_text.insert('1.0', content)
|
# if content is empty, ensure destination becomes empty (no extra newline)
|
||||||
|
if content:
|
||||||
|
dst_text.insert('1.0', content)
|
||||||
|
else:
|
||||||
|
# keep widget empty
|
||||||
|
pass
|
||||||
self._mark_dirty(dst)
|
self._mark_dirty(dst)
|
||||||
self._refresh_diff()
|
self._refresh_diff()
|
||||||
|
|
||||||
|
|||||||
@ -25,6 +25,27 @@ from codebridge.gui.profile_dialog import ProfileManagerDialog, ProfileManagerFr
|
|||||||
import json
|
import json
|
||||||
|
|
||||||
|
|
||||||
|
# --- Import Version Info FOR THE WRAPPER ITSELF ---
|
||||||
|
try:
|
||||||
|
# Use absolute import based on package name
|
||||||
|
from codebridge import _version as wrapper_version
|
||||||
|
|
||||||
|
WRAPPER_APP_VERSION_STRING = f"{wrapper_version.__version__} ({wrapper_version.GIT_BRANCH}/{wrapper_version.GIT_COMMIT_HASH[:7]})"
|
||||||
|
WRAPPER_BUILD_INFO = f"Wrapper Built: {wrapper_version.BUILD_TIMESTAMP}"
|
||||||
|
except ImportError:
|
||||||
|
# This might happen if you run the wrapper directly from source
|
||||||
|
# without generating its _version.py first (if you use that approach for the wrapper itself)
|
||||||
|
WRAPPER_APP_VERSION_STRING = "(Dev Wrapper)"
|
||||||
|
WRAPPER_BUILD_INFO = "Wrapper build time unknown"
|
||||||
|
# --- End Import Version Info ---
|
||||||
|
|
||||||
|
# --- Constants for Version Generation ---
|
||||||
|
DEFAULT_VERSION = "0.0.0+unknown"
|
||||||
|
DEFAULT_COMMIT = "Unknown"
|
||||||
|
DEFAULT_BRANCH = "Unknown"
|
||||||
|
# --- End Constants --
|
||||||
|
|
||||||
|
|
||||||
class MainWindow:
|
class MainWindow:
|
||||||
"""
|
"""
|
||||||
Main GUI class for CodeBridge application.
|
Main GUI class for CodeBridge application.
|
||||||
@ -32,7 +53,7 @@ class MainWindow:
|
|||||||
|
|
||||||
def __init__(self, root: tk.Tk):
|
def __init__(self, root: tk.Tk):
|
||||||
self.root = root
|
self.root = root
|
||||||
self.root.title("CodeBridge - Codebase Synchronizer")
|
self.root.title(f"CodeBridge - Codebase Synchronizer - {WRAPPER_APP_VERSION_STRING}")
|
||||||
# Make the window taller by default so status/log area is visible
|
# Make the window taller by default so status/log area is visible
|
||||||
self.root.geometry("1000x760")
|
self.root.geometry("1000x760")
|
||||||
# Enforce a reasonable minimum size so status bar remains visible
|
# Enforce a reasonable minimum size so status bar remains visible
|
||||||
|
|||||||
@ -43,5 +43,50 @@
|
|||||||
".mk",
|
".mk",
|
||||||
".bak"
|
".bak"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"DevEnv da server svn": {
|
||||||
|
"description": "DevEnv Grifo E",
|
||||||
|
"source": "//tsclient/D/__BACKUP/GrifoE/GRIFO-E_svn/DevEnv",
|
||||||
|
"destination": "C:/src/GRIFO-E - Copia/DevEnv",
|
||||||
|
"ignore_extensions": [
|
||||||
|
".o",
|
||||||
|
".d",
|
||||||
|
".obj",
|
||||||
|
".class",
|
||||||
|
".pyc",
|
||||||
|
".pyo",
|
||||||
|
".log",
|
||||||
|
".tmp",
|
||||||
|
".swp",
|
||||||
|
".DS_Store",
|
||||||
|
".exe",
|
||||||
|
".a",
|
||||||
|
".mk",
|
||||||
|
".bak",
|
||||||
|
".defs",
|
||||||
|
".txt",
|
||||||
|
".pdom"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"REP da server svn": {
|
||||||
|
"description": "REP Grifo E code base",
|
||||||
|
"source": "//tsclient/D/__BACKUP/GrifoE/GRIFO-E_svn/REP",
|
||||||
|
"destination": "C:/src/GRIFO-E - Copia/REP",
|
||||||
|
"ignore_extensions": [
|
||||||
|
".o",
|
||||||
|
".d",
|
||||||
|
".obj",
|
||||||
|
".class",
|
||||||
|
".pyc",
|
||||||
|
".pyo",
|
||||||
|
".log",
|
||||||
|
".tmp",
|
||||||
|
".swp",
|
||||||
|
".DS_Store",
|
||||||
|
".exe",
|
||||||
|
".a",
|
||||||
|
".mk",
|
||||||
|
".bak"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue
Block a user