working product
This commit is contained in:
parent
1ee311e561
commit
903fe0392c
1 changed files with 163 additions and 117 deletions
280
checkpkg.py
280
checkpkg.py
|
@ -94,147 +94,193 @@ def fetch_package_data(package):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def print_table(output, headers, selected_pms, args):
|
def print_table(output, headers, selected_pms, args):
|
||||||
"""Print formatted table with consistent alignment"""
|
"""Print formatted table with consistent alignment or list for small terminals"""
|
||||||
# Terminal dimensions
|
# Terminal dimensions
|
||||||
terminal_width = shutil.get_terminal_size().columns
|
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
|
# Calculate package availability for coloring
|
||||||
pkg_col_width = max(
|
pkg_availability = {}
|
||||||
len(headers[0]),
|
for pkg in args.packages:
|
||||||
max(len(pkg) for pkg in args.packages) if args.packages else min_col_width
|
versions = output.get(pkg, {})
|
||||||
) + (padding * 2)
|
available_count = sum(1 for pm in selected_pms if versions.get(pm, 'Not found') != 'Not found')
|
||||||
|
|
||||||
|
if available_count == 0:
|
||||||
|
pkg_availability[pkg] = 'red' # Not available anywhere
|
||||||
|
elif available_count == len(selected_pms):
|
||||||
|
pkg_availability[pkg] = 'green' # Available everywhere
|
||||||
|
else:
|
||||||
|
pkg_availability[pkg] = 'yellow' # Available in some places
|
||||||
|
|
||||||
# Allocate remaining space proportionally to other columns
|
# Determine minimum required widths
|
||||||
remaining_width = terminal_width - pkg_col_width - (3 * len(selected_pms)) # 3 chars for " | "
|
min_pkg_width = max(len(pkg) for pkg in args.packages) + 2
|
||||||
version_col_width = max(min_col_width, remaining_width // len(selected_pms))
|
min_pm_width = 10
|
||||||
|
min_required_width = min_pkg_width + (min_pm_width * len(selected_pms)) + (3 * len(selected_pms))
|
||||||
|
|
||||||
# Define column widths
|
# If terminal is too narrow for the table, use list format instead
|
||||||
col_widths = [pkg_col_width] + [version_col_width] * len(selected_pms)
|
if terminal_width < min_required_width and len(selected_pms) > 1:
|
||||||
|
print_list_format(output, headers, selected_pms, args, pkg_availability)
|
||||||
|
return
|
||||||
|
|
||||||
# Adjust to fit terminal if needed
|
# Calculate column widths
|
||||||
while sum(col_widths) + (3 * (len(col_widths) - 1)) > terminal_width and min(col_widths) > min_col_width:
|
padding = 1 # Space on each side of content
|
||||||
max_idx = col_widths.index(max(col_widths))
|
|
||||||
col_widths[max_idx] -= 1
|
|
||||||
|
|
||||||
# Calculate total table width for separators
|
# Package column width
|
||||||
|
pkg_col_width = min(min_pkg_width + 4, max(min_pkg_width, terminal_width // (len(selected_pms) + 3)))
|
||||||
|
|
||||||
|
# PM column widths (divide remaining space equally)
|
||||||
|
remaining_width = terminal_width - pkg_col_width - (3 * len(selected_pms))
|
||||||
|
pm_col_width = max(min_pm_width, remaining_width // len(selected_pms))
|
||||||
|
|
||||||
|
col_widths = [pkg_col_width] + [pm_col_width] * len(selected_pms)
|
||||||
|
|
||||||
|
# Print header row
|
||||||
|
header_cells = []
|
||||||
|
for i, header in enumerate(headers):
|
||||||
|
text = header.center(col_widths[i] - (2 * padding))
|
||||||
|
cell = " " * padding + colorize(text, 'header') + " " * padding
|
||||||
|
header_cells.append(cell)
|
||||||
|
|
||||||
|
print(" | ".join(header_cells))
|
||||||
|
|
||||||
|
# Print separator line
|
||||||
total_width = sum(col_widths) + (3 * (len(col_widths) - 1))
|
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)
|
print("-" * total_width)
|
||||||
|
|
||||||
# Process and print each package row
|
# Print each package row
|
||||||
for pkg_index, pkg in enumerate(args.packages):
|
for pkg_idx, pkg in enumerate(args.packages):
|
||||||
versions = output.get(pkg, {pm: 'Not found' for pm in selected_pms})
|
versions = output.get(pkg, {})
|
||||||
|
|
||||||
# Prepare content for each cell
|
# First collect all data for this package
|
||||||
cells_content = []
|
package_data = []
|
||||||
|
|
||||||
# Package name (first column)
|
# Package name (first column)
|
||||||
cells_content.append(colorize(pkg, 'bold'))
|
package_data.append([colorize(pkg, pkg_availability[pkg])])
|
||||||
|
|
||||||
# Version information (remaining columns)
|
# Version data for each package manager
|
||||||
for pm in selected_pms:
|
for pm in selected_pms:
|
||||||
version = versions.get(pm, 'Not found')
|
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)
|
if version == 'Not found':
|
||||||
|
package_data.append([colorize('-', 'red')])
|
||||||
|
continue
|
||||||
|
|
||||||
# Wrap text without color codes
|
# Extract version number and repositories
|
||||||
wrapped_lines = textwrap.wrap(
|
version_parts = []
|
||||||
raw_text,
|
match = re.match(r'(.*?)\s+\((.*)\)$', version)
|
||||||
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 match:
|
||||||
if colorize.is_tty:
|
ver_num, repos = match.groups()
|
||||||
color = None
|
version_parts.append(colorize(ver_num, 'green'))
|
||||||
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
|
# Format repositories
|
||||||
wrapped_lines = [colorize(line, color) for line in wrapped_lines]
|
repo_lines = []
|
||||||
|
repo_text = "(" + repos + ")"
|
||||||
wrapped_cells.append(wrapped_lines)
|
|
||||||
|
# Wrap repository text if needed
|
||||||
# Determine how many lines this row needs
|
avail_width = col_widths[len(package_data)] - (2 * padding)
|
||||||
max_lines = max(len(cell) for cell in wrapped_cells)
|
if len(repo_text) <= avail_width:
|
||||||
|
repo_lines.append(colorize(repo_text, 'green'))
|
||||||
# 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:
|
else:
|
||||||
# Empty space for this cell in this line
|
# Handle wrapping for repositories
|
||||||
row_parts.append(" " * col_widths[col_idx])
|
repo_parts = repos.split(', ')
|
||||||
|
current_line = "("
|
||||||
print(" | ".join(row_parts))
|
|
||||||
|
for repo in repo_parts:
|
||||||
|
if len(current_line) + len(repo) + 2 <= avail_width:
|
||||||
|
if current_line != "(":
|
||||||
|
current_line += ", "
|
||||||
|
current_line += repo
|
||||||
|
else:
|
||||||
|
if current_line != "(":
|
||||||
|
current_line += ")"
|
||||||
|
repo_lines.append(colorize(current_line, 'green'))
|
||||||
|
current_line = " " + repo
|
||||||
|
|
||||||
|
if current_line != "(":
|
||||||
|
current_line += ")" if not current_line.startswith(" ") else ""
|
||||||
|
repo_lines.append(colorize(current_line, 'green'))
|
||||||
|
|
||||||
|
# Combined version and repo lines
|
||||||
|
package_data.append([version_parts[0]] + repo_lines)
|
||||||
|
else:
|
||||||
|
# Simple version string
|
||||||
|
package_data.append([colorize(version, 'green')])
|
||||||
|
|
||||||
# Add a separator between packages (but not after the last one)
|
# Determine max number of lines needed
|
||||||
if pkg_index < len(args.packages) - 1:
|
max_lines = max(len(column) for column in package_data)
|
||||||
# Use a lighter separator for between packages
|
|
||||||
|
# Print all lines for this package
|
||||||
|
for line_idx in range(max_lines):
|
||||||
|
row_cells = []
|
||||||
|
|
||||||
|
for col_idx, col_data in enumerate(package_data):
|
||||||
|
if line_idx < len(col_data):
|
||||||
|
# Actual content
|
||||||
|
content = col_data[line_idx]
|
||||||
|
content_plain = re.sub(r'\033\[\d+m', '', content)
|
||||||
|
|
||||||
|
# Calculate padding
|
||||||
|
left_pad = padding
|
||||||
|
right_pad = max(0, col_widths[col_idx] - len(content_plain) - left_pad)
|
||||||
|
|
||||||
|
cell = " " * left_pad + content + " " * right_pad
|
||||||
|
else:
|
||||||
|
# Empty cell
|
||||||
|
cell = " " * col_widths[col_idx]
|
||||||
|
|
||||||
|
row_cells.append(cell)
|
||||||
|
|
||||||
|
print(" | ".join(row_cells))
|
||||||
|
|
||||||
|
# Add separator between packages
|
||||||
|
if pkg_idx < len(args.packages) - 1:
|
||||||
print("·" * total_width)
|
print("·" * total_width)
|
||||||
|
|
||||||
|
def print_list_format(output, headers, selected_pms, args, pkg_availability):
|
||||||
|
"""Print packages in a vertical list format for narrow terminals"""
|
||||||
|
terminal_width = shutil.get_terminal_size().columns
|
||||||
|
|
||||||
|
for pkg_idx, pkg in enumerate(args.packages):
|
||||||
|
pkg_color = pkg_availability[pkg]
|
||||||
|
versions = output.get(pkg, {})
|
||||||
|
|
||||||
|
# Print package header with color based on availability
|
||||||
|
print(f"\n{colorize('Package:', 'bold')} {colorize(pkg, pkg_color)}")
|
||||||
|
print("-" * min(40, terminal_width - 2))
|
||||||
|
|
||||||
|
# Print versions for each package manager
|
||||||
|
for pm in selected_pms:
|
||||||
|
pm_name = headers[selected_pms.index(pm) + 1] # Get friendly display name
|
||||||
|
version = versions.get(pm, 'Not found')
|
||||||
|
|
||||||
|
if version == 'Not found':
|
||||||
|
print(f"{colorize(pm_name, 'header')}: {colorize('-', 'red')}")
|
||||||
|
else:
|
||||||
|
# Extract version and repo information
|
||||||
|
match = re.match(r'(.*?)\s+\((.*)\)$', version)
|
||||||
|
if match:
|
||||||
|
ver_num, repos = match.groups()
|
||||||
|
|
||||||
|
# Handle long repository lists with wrapping
|
||||||
|
if len(pm_name) + len(ver_num) + len(repos) + 5 > terminal_width:
|
||||||
|
print(f"{colorize(pm_name, 'header')}: {colorize(ver_num, 'green')}")
|
||||||
|
# Wrap repositories with proper indentation
|
||||||
|
wrapper = textwrap.TextWrapper(
|
||||||
|
width=terminal_width - 4,
|
||||||
|
initial_indent=" ",
|
||||||
|
subsequent_indent=" "
|
||||||
|
)
|
||||||
|
wrapped = wrapper.fill(f"({repos})")
|
||||||
|
print(colorize(wrapped, 'green'))
|
||||||
|
else:
|
||||||
|
print(f"{colorize(pm_name, 'header')}: {colorize(ver_num, 'green')} ({repos})")
|
||||||
|
else:
|
||||||
|
print(f"{colorize(pm_name, 'header')}: {colorize(version, 'green')}")
|
||||||
|
|
||||||
|
# Add separator between packages
|
||||||
|
if pkg_idx < len(args.packages) - 1:
|
||||||
|
print("\n" + "-" * min(40, terminal_width - 2))
|
||||||
|
|
||||||
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')
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue