working productgs
This commit is contained in:
parent
31f176e2aa
commit
1ee311e561
1 changed files with 154 additions and 65 deletions
219
checkpkg.py
219
checkpkg.py
|
@ -5,24 +5,33 @@ import json
|
||||||
import signal
|
import signal
|
||||||
import re
|
import re
|
||||||
import shutil
|
import shutil
|
||||||
|
import textwrap
|
||||||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||||
from urllib.error import HTTPError, URLError
|
from urllib.error import HTTPError, URLError
|
||||||
|
|
||||||
# Updated color codes with simpler separator
|
# Color codes
|
||||||
COLORS = {
|
COLORS = {
|
||||||
'reset': '\033[0m',
|
'reset': '\033[0m',
|
||||||
'bold': '\033[1m',
|
'bold': '\033[1m',
|
||||||
'red': '\033[91m',
|
'red': '\033[91m',
|
||||||
'green': '\033[92m',
|
'green': '\033[92m',
|
||||||
'yellow': '\033[93m',
|
'yellow': '\033[93m',
|
||||||
'header': '\033[94m' # Simpler header color
|
'header': '\033[94m'
|
||||||
}
|
}
|
||||||
|
|
||||||
def colorize(text, color):
|
def colorize(text, color):
|
||||||
|
"""Add ANSI color codes if output is a terminal"""
|
||||||
if not hasattr(colorize, 'is_tty'):
|
if not hasattr(colorize, 'is_tty'):
|
||||||
colorize.is_tty = __import__('sys').stdout.isatty()
|
colorize.is_tty = __import__('sys').stdout.isatty()
|
||||||
return f"{COLORS[color]}{text}{COLORS['reset']}" if colorize.is_tty else text
|
return f"{COLORS[color]}{text}{COLORS['reset']}" if colorize.is_tty else text
|
||||||
|
|
||||||
|
# def get_terminal_width(default=80):
|
||||||
|
# """Get terminal width with fallback"""
|
||||||
|
# try:
|
||||||
|
# return shutil.get_terminal_size().columns
|
||||||
|
# except:
|
||||||
|
# return default
|
||||||
|
|
||||||
signal.signal(signal.SIGINT, lambda s, f: exit(1))
|
signal.signal(signal.SIGINT, lambda s, f: exit(1))
|
||||||
|
|
||||||
REQUEST_HEADERS = {
|
REQUEST_HEADERS = {
|
||||||
|
@ -84,6 +93,148 @@ def fetch_package_data(package):
|
||||||
except Exception:
|
except Exception:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def print_table(output, headers, selected_pms, args):
|
||||||
|
"""Print formatted table with consistent alignment"""
|
||||||
|
# Terminal dimensions
|
||||||
|
terminal_width = shutil.get_terminal_size().columns
|
||||||
|
min_col_width = 10
|
||||||
|
padding = 1 # Space on each side of the column content
|
||||||
|
|
||||||
|
# Calculate initial column widths based on content
|
||||||
|
pkg_col_width = max(
|
||||||
|
len(headers[0]),
|
||||||
|
max(len(pkg) for pkg in args.packages) if args.packages else min_col_width
|
||||||
|
) + (padding * 2)
|
||||||
|
|
||||||
|
# Allocate remaining space proportionally to other columns
|
||||||
|
remaining_width = terminal_width - pkg_col_width - (3 * len(selected_pms)) # 3 chars for " | "
|
||||||
|
version_col_width = max(min_col_width, remaining_width // len(selected_pms))
|
||||||
|
|
||||||
|
# Define column widths
|
||||||
|
col_widths = [pkg_col_width] + [version_col_width] * len(selected_pms)
|
||||||
|
|
||||||
|
# Adjust to fit terminal if needed
|
||||||
|
while sum(col_widths) + (3 * (len(col_widths) - 1)) > terminal_width and min(col_widths) > min_col_width:
|
||||||
|
max_idx = col_widths.index(max(col_widths))
|
||||||
|
col_widths[max_idx] -= 1
|
||||||
|
|
||||||
|
# Calculate total table width for separators
|
||||||
|
total_width = sum(col_widths) + (3 * (len(col_widths) - 1))
|
||||||
|
|
||||||
|
# Print headers (centered)
|
||||||
|
header_row = []
|
||||||
|
for idx, header in enumerate(headers):
|
||||||
|
header_text = header.center(col_widths[idx] - (padding * 2))
|
||||||
|
padded_header = " " * padding + colorize(header_text, 'header') + " " * padding
|
||||||
|
header_row.append(padded_header.ljust(col_widths[idx]))
|
||||||
|
|
||||||
|
print(" | ".join(header_row))
|
||||||
|
|
||||||
|
# Print main separator line
|
||||||
|
print("-" * total_width)
|
||||||
|
|
||||||
|
# Process and print each package row
|
||||||
|
for pkg_index, pkg in enumerate(args.packages):
|
||||||
|
versions = output.get(pkg, {pm: 'Not found' for pm in selected_pms})
|
||||||
|
|
||||||
|
# Prepare content for each cell
|
||||||
|
cells_content = []
|
||||||
|
|
||||||
|
# Package name (first column)
|
||||||
|
cells_content.append(colorize(pkg, 'bold'))
|
||||||
|
|
||||||
|
# Version information (remaining columns)
|
||||||
|
for pm in selected_pms:
|
||||||
|
version = versions.get(pm, 'Not found')
|
||||||
|
color = 'green' if version != 'Not found' else 'red'
|
||||||
|
if 'AUR' in version: color = 'yellow'
|
||||||
|
# Apply color to the entire string at once
|
||||||
|
cells_content.append(colorize(version, color))
|
||||||
|
|
||||||
|
# Apply wrapping to each cell based on column width
|
||||||
|
wrapped_cells = []
|
||||||
|
for idx, content in enumerate(cells_content):
|
||||||
|
# Use raw text for wrapping calculation, but keep the colored text for display
|
||||||
|
raw_text = content
|
||||||
|
if colorize.is_tty:
|
||||||
|
# Remove ANSI color codes for length calculation
|
||||||
|
raw_text = re.sub(r'\033\[\d+m', '', content)
|
||||||
|
|
||||||
|
avail_width = col_widths[idx] - (padding * 2)
|
||||||
|
|
||||||
|
# Wrap text without color codes
|
||||||
|
wrapped_lines = textwrap.wrap(
|
||||||
|
raw_text,
|
||||||
|
width=avail_width,
|
||||||
|
break_long_words=False,
|
||||||
|
break_on_hyphens=True
|
||||||
|
) or ['']
|
||||||
|
|
||||||
|
# If we have color codes, we need to re-apply coloring to each wrapped line
|
||||||
|
if colorize.is_tty:
|
||||||
|
color = None
|
||||||
|
if idx == 0: # Package name
|
||||||
|
color = 'bold'
|
||||||
|
else: # Version info
|
||||||
|
if 'Not found' in raw_text:
|
||||||
|
color = 'red'
|
||||||
|
elif 'AUR' in raw_text:
|
||||||
|
color = 'yellow'
|
||||||
|
else:
|
||||||
|
color = 'green'
|
||||||
|
|
||||||
|
# Apply the same color to each wrapped line
|
||||||
|
wrapped_lines = [colorize(line, color) for line in wrapped_lines]
|
||||||
|
|
||||||
|
wrapped_cells.append(wrapped_lines)
|
||||||
|
|
||||||
|
# Determine how many lines this row needs
|
||||||
|
max_lines = max(len(cell) for cell in wrapped_cells)
|
||||||
|
|
||||||
|
# Print each line of the row
|
||||||
|
for line_idx in range(max_lines):
|
||||||
|
row_parts = []
|
||||||
|
for col_idx, cell_lines in enumerate(wrapped_cells):
|
||||||
|
if line_idx < len(cell_lines):
|
||||||
|
content = cell_lines[line_idx]
|
||||||
|
if line_idx > 0: # For continuation lines
|
||||||
|
# Indent continuation lines for better readability
|
||||||
|
# We can't simply add characters to colored text, need to handle differently
|
||||||
|
if colorize.is_tty:
|
||||||
|
# Need to extract the color codes and apply them after indent
|
||||||
|
plain_content = re.sub(r'\033\[\d+m', '', content)
|
||||||
|
color_prefix = content[:content.find(plain_content)]
|
||||||
|
color_suffix = COLORS['reset']
|
||||||
|
content = color_prefix + " " + plain_content + color_suffix
|
||||||
|
else:
|
||||||
|
content = " " + content
|
||||||
|
|
||||||
|
# Calculate proper padding with color codes
|
||||||
|
if colorize.is_tty:
|
||||||
|
plain_content = re.sub(r'\033\[\d+m', '', content)
|
||||||
|
color_parts = content.split(plain_content)
|
||||||
|
padded = " " * padding + content + " " * padding
|
||||||
|
|
||||||
|
# For colored text, we need to calculate padding differently
|
||||||
|
plain_padded = " " * padding + plain_content + " " * padding
|
||||||
|
padding_needed = col_widths[col_idx] - len(plain_padded)
|
||||||
|
if padding_needed > 0:
|
||||||
|
padded += " " * padding_needed
|
||||||
|
else:
|
||||||
|
padded = (" " * padding + content + " " * padding).ljust(col_widths[col_idx])
|
||||||
|
|
||||||
|
row_parts.append(padded)
|
||||||
|
else:
|
||||||
|
# Empty space for this cell in this line
|
||||||
|
row_parts.append(" " * col_widths[col_idx])
|
||||||
|
|
||||||
|
print(" | ".join(row_parts))
|
||||||
|
|
||||||
|
# Add a separator between packages (but not after the last one)
|
||||||
|
if pkg_index < len(args.packages) - 1:
|
||||||
|
# Use a lighter separator for between packages
|
||||||
|
print("·" * total_width)
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = argparse.ArgumentParser(description='Package search tool')
|
parser = argparse.ArgumentParser(description='Package search tool')
|
||||||
parser.add_argument('--all', action='store_true')
|
parser.add_argument('--all', action='store_true')
|
||||||
|
@ -151,69 +302,7 @@ def main():
|
||||||
else:
|
else:
|
||||||
output[pkg][pm] = 'Not found'
|
output[pkg][pm] = 'Not found'
|
||||||
|
|
||||||
headers = ['Package'] + selected_pms
|
print_table(output, ['Package'] + selected_pms, selected_pms, args)
|
||||||
terminal_width = get_terminal_width()
|
|
||||||
|
|
||||||
# Calculate initial column widths
|
|
||||||
col_widths = [len(h) for h in headers]
|
|
||||||
content_widths = {0: max(len(pkg) for pkg in args.packages)}
|
|
||||||
|
|
||||||
for pkg in args.packages:
|
|
||||||
versions = output.get(pkg, {})
|
|
||||||
for i, pm in enumerate(selected_pms, 1):
|
|
||||||
content_widths[i] = max(content_widths.get(i, 0), len(versions.get(pm, '')))
|
|
||||||
|
|
||||||
# Set initial widths
|
|
||||||
for i in range(len(headers)):
|
|
||||||
col_widths[i] = max(len(headers[i]), content_widths.get(i, 0))
|
|
||||||
|
|
||||||
# Adjust for terminal width
|
|
||||||
total_width = sum(col_widths) + 3 * (len(headers) - 1) # 3 chars per separator
|
|
||||||
max_reductions = 5 # Max characters to reduce per column
|
|
||||||
|
|
||||||
if total_width > terminal_width:
|
|
||||||
excess = total_width - terminal_width
|
|
||||||
reducible = [i for i in range(1, len(headers)) if col_widths[i] > 10]
|
|
||||||
|
|
||||||
while excess > 0 and reducible:
|
|
||||||
per_col = max(1, min(max_reductions, excess // len(reducible)))
|
|
||||||
for i in reducible:
|
|
||||||
reduction = min(per_col, col_widths[i] - 10, excess)
|
|
||||||
col_widths[i] -= reduction
|
|
||||||
excess -= reduction
|
|
||||||
if excess <= 0:
|
|
||||||
break
|
|
||||||
|
|
||||||
# Truncate text with ellipsis if needed
|
|
||||||
def truncate(text, width):
|
|
||||||
if len(text) > width and width > 3:
|
|
||||||
return text[:width-3] + '...'
|
|
||||||
return text.ljust(width)
|
|
||||||
|
|
||||||
# Print header
|
|
||||||
header_line = ' | '.join(
|
|
||||||
truncate(colorize(h, 'header'), w)
|
|
||||||
for h, w in zip(headers, col_widths)
|
|
||||||
)
|
|
||||||
print(header_line)
|
|
||||||
|
|
||||||
# Separator line
|
|
||||||
print('-' * min(sum(col_widths) + 3*(len(headers)-1), terminal_width))
|
|
||||||
|
|
||||||
# Print rows
|
|
||||||
for pkg in args.packages:
|
|
||||||
row = [truncate(colorize(pkg, 'bold'), col_widths[0])]
|
|
||||||
versions = output.get(pkg, {pm: 'Not found' for pm in selected_pms})
|
|
||||||
|
|
||||||
for i, pm in enumerate(selected_pms, 1):
|
|
||||||
version = versions.get(pm, 'Not found')
|
|
||||||
color = 'green' if version != 'Not found' else 'red'
|
|
||||||
if 'AUR' in version:
|
|
||||||
color = 'yellow'
|
|
||||||
# Fixed line with proper parenthesis closure
|
|
||||||
row.append(truncate(colorize(version, color), col_widths[i]))
|
|
||||||
|
|
||||||
print(' | '.join(row))
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue