Commit Diff


commit - bccd2a000cccad112dd2bf9d43fb36702492ede1
commit + 7e27284ae5e454afdfe484a1da5c491c5214fcf9
blob - bb88cc5c416c2527558dedae96edea1b6d909576
blob + 70127e81d0c09e320a6bb8292983ecad644caf90
--- diggah/diggah.py
+++ diggah/diggah.py
@@ -98,6 +98,7 @@ class RemoteExecutor:
         start_dt: datetime | None,
         end_dt: datetime | None,
         include_files: bool,
+        port: int | None = None,
     ) -> Iterable[str]:
         """
         Executes a find command on the remote host and yields the results.
@@ -107,6 +108,14 @@ class RemoteExecutor:
         if "@" in host_str:
             username, hostname = host_str.split("@", 1)
 
+        if ":" in hostname:
+            host_part, _, port_part = hostname.rpartition(":")
+            if not port_part.isdigit():
+                raise ValueError(f"invalid port '{port_part}' in host '{host_str}'")
+            hostname = host_part
+            if port is None:
+                port = int(port_part)
+
         # Load SSH config
         ssh_config = paramiko.SSHConfig()
         user_config_file = os.path.expanduser("~/.ssh/config")
@@ -122,7 +131,8 @@ class RemoteExecutor:
         if username is None and "user" in user_config:
             username = user_config["user"]
 
-        port = int(user_config.get("port", 22))
+        if port is None:
+            port = int(user_config.get("port", 22))
         key_filename = user_config.get("identityfile")
 
         cmd_parts = ["find", path]
@@ -198,6 +208,7 @@ class Diggah:
         path: str = ".",
         dry_run: bool = False,
         host: str | None = None,
+        port: int | None = None,
         relative: bool = False,
         output: str | bool = False,
     ):
@@ -215,7 +226,10 @@ class Diggah:
             all: If True, show all finds regardless of time.
             path: Directory to search in (default: ".").
             dry_run: If True, print calculated dates and exit.
-            host: SSH host to run the command on (e.g., user@example.com).
+            host: SSH host to run the command on (e.g., user@example.com
+               or user@example.com:2222).
+            port: SSH port for the remote host (overrides host:port and
+               ssh config; default 22).
             relative: If True, output paths relative to the search root.
             output: If True or a path, write output to file(s) instead of stdout.
                If a path is provided, writes to that file.
@@ -234,10 +248,12 @@ class Diggah:
         for start_dt, end_dt, outfile in ranges:
             if dry_run:
                 self._print_dry_run(
-                    start_dt, end_dt, path, files, host, relative, output, outfile
+                    start_dt, end_dt, path, files, host, port, relative, output, outfile
                 )
             else:
-                self._run_search(start_dt, end_dt, path, files, host, relative, outfile)
+                self._run_search(
+                    start_dt, end_dt, path, files, host, port, relative, outfile
+                )
 
     def _determine_search_ranges(
         self,
@@ -332,6 +348,7 @@ class Diggah:
         path: str,
         include_files: bool,
         host: str | None,
+        port: int | None,
         relative: bool,
         output: str | bool,
         outfile: str | None,
@@ -342,6 +359,8 @@ class Diggah:
         print(f"Include Files: {include_files}")
         if host:
             print(f"Host:          {host}")
+            if port:
+                print(f"Port:          {port}")
             print("Mode:          Remote (find command)")
         else:
             print("Mode:          Local (python walk)")
@@ -357,13 +376,14 @@ class Diggah:
         path: str,
         include_files: bool,
         host: str | None,
+        port: int | None,
         relative: bool,
         outfile: str | None,
     ):
         results: Iterable[str]
         if host:
             results = RemoteExecutor().execute(
-                host, path, start_dt, end_dt, include_files
+                host, path, start_dt, end_dt, include_files, port
             )
         else:
             start_ts = start_dt.timestamp() if start_dt else None