Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "bitssh"
version = "3.2.0"
version = "3.3.0"
description = "A new and modern SSH connector written in Python."
readme = "README.md"
authors = [
Expand Down Expand Up @@ -45,7 +45,7 @@ Issues = "https://github.com/Mr-Sunglasses/bitssh/issues"
bitssh = "bitssh.__main__:main"

[tool.bumpver]
current_version = "3.2.0"
current_version = "3.3.0"
version_pattern = "MAJOR.MINOR.PATCH"
commit_message = "Bump version {old_version} -> {new_version}"
commit = true
Expand Down
2 changes: 1 addition & 1 deletion src/bitssh/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@
pass


__version__ = "3.2.0"
__version__ = "3.3.0"
47 changes: 36 additions & 11 deletions src/bitssh/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,27 +15,51 @@ def _validate_config_file() -> None:

def get_config_content():
_validate_config_file()

with open(CONFIG_FILE_PATH, "r") as file:
with open(CONFIG_FILE_PATH, "r", encoding="utf-8") as file:
lines = file.read()

host_pattern = re.compile(r"Host\s+(\w+)", re.MULTILINE)
hostname_pattern = re.compile(r"(?:HostName|Hostname)\s+(\S+)", re.MULTILINE)
user_pattern = re.compile(r"User\s+(\S+)", re.MULTILINE)
port_pattern = re.compile(r"port\s+(\d+)", re.MULTILINE | re.IGNORECASE)
# Remove commented lines and empty lines
filtered_lines = []
for line in lines.split("\n"):
stripped_line = line.strip()
if stripped_line and not stripped_line.startswith("#"):
filtered_lines.append(line)

filtered_content = "\n".join(filtered_lines)

# Case-insensitive patterns - make sure all are properly case-insensitive
host_pattern = re.compile(r"^Host\s+(\w+)", re.MULTILINE | re.IGNORECASE)
hostname_pattern = re.compile(
r"^\s*(?:HostName|Hostname)\s+(\S+)", re.MULTILINE | re.IGNORECASE
)
user_pattern = re.compile(r"^\s*User\s+(\S+)", re.MULTILINE | re.IGNORECASE)
port_pattern = re.compile(r"^\s*port\s+(\d+)", re.MULTILINE | re.IGNORECASE)

host_dict = {}
for match in host_pattern.finditer(lines):

# Find all host matches first
host_matches = list(host_pattern.finditer(filtered_content))

for i, match in enumerate(host_matches):
host = match.group(1)
host_end = match.end()

hostname_match = hostname_pattern.search(lines, host_end)
# Find the end of this host section (start of next host or end of content)
if i + 1 < len(host_matches):
host_section_end = host_matches[i + 1].start()
else:
host_section_end = len(filtered_content)

# Extract only this host's section (from end of Host line to start of next Host)
host_section = filtered_content[match.end() : host_section_end]

# Search within this host section only
hostname_match = hostname_pattern.search(host_section)
hostname = hostname_match.group(1) if hostname_match else host

user_match = user_pattern.search(lines, host_end)
user_match = user_pattern.search(host_section)
user = user_match.group(1) if user_match else None

port_match = port_pattern.search(lines, host_end)
port_match = port_pattern.search(host_section)
port = port_match.group(1) if port_match else "22"

host_dict[host] = {
Expand All @@ -60,3 +84,4 @@ def get_config_file_row_data():

def get_config_file_host_data() -> List[str]:
return [f"🖥️ -> {row[1]}" for row in get_config_file_row_data()]
return [f"🖥️ -> {row[1]}" for row in get_config_file_row_data()]
Loading