Skip to content

Commit 5095071

Browse files
committed
Better error message
1 parent 19d99ee commit 5095071

1 file changed

Lines changed: 51 additions & 7 deletions

File tree

mpssh

Lines changed: 51 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -120,9 +120,42 @@ async def ssh_connect_and_run_command(
120120
)
121121

122122

123+
def get_hostgroups_help_text(json_file: str) -> str:
124+
"""Get available hostgroups for help text, with warning if config not found."""
125+
try:
126+
json_path = Path(json_file)
127+
if not json_path.exists():
128+
return f"\nWARNING: Config file not found at {json_file}"
129+
130+
with open(json_path, "r") as file:
131+
data = json.load(file)
132+
hostgroups = list(data.keys())
133+
if hostgroups:
134+
return f"\nAvailable hostgroups: {', '.join(sorted(hostgroups))}"
135+
else:
136+
return f"\nWARNING: No hostgroups found in {json_file}"
137+
except json.JSONDecodeError:
138+
return f"\nWARNING: Invalid JSON in config file {json_file}"
139+
except Exception:
140+
return f"\nWARNING: Could not read config file {json_file}"
141+
142+
143+
class CustomArgumentParser(argparse.ArgumentParser):
144+
def error(self, message):
145+
# Show help with hostgroups when arguments are missing
146+
self.print_help()
147+
sys.stderr.write(f"\nerror: {message}\n")
148+
sys.exit(2)
149+
150+
123151
async def main() -> int:
124-
parser = argparse.ArgumentParser(
125-
description="Run a command on multiple hosts via SSH."
152+
# Set default config path
153+
default_json_file = str(Path.home() / ".config" / "ssh_hosts.json")
154+
155+
parser = CustomArgumentParser(
156+
description="Run a command on multiple hosts via SSH.",
157+
formatter_class=argparse.RawDescriptionHelpFormatter,
158+
epilog=get_hostgroups_help_text(default_json_file)
126159
)
127160
parser.add_argument(
128161
"--raw", action="store_true", help="Print raw output without any formatting"
@@ -131,33 +164,44 @@ async def main() -> int:
131164
"--timeout", type=int, default=10, help="SSH connection timeout in seconds"
132165
)
133166
parser.add_argument(
134-
"--json_file",
167+
"--json-file",
135168
type=str,
136169
help="The JSON file containing the list of hosts",
137-
default=str(Path.home() / ".config" / "ssh_hosts.json"),
170+
default=default_json_file,
138171
)
139172
parser.add_argument(
140173
"hostgroup", type=str, help="The hostgroup to run the command on"
141174
)
142175
parser.add_argument(
143176
"command", nargs=argparse.REMAINDER, help="The command to run on each host"
144177
)
178+
179+
# Handle custom json-file for help text
180+
if "--json-file" in sys.argv:
181+
try:
182+
json_file_idx = sys.argv.index("--json-file") + 1
183+
if json_file_idx < len(sys.argv) and not sys.argv[json_file_idx].startswith("-"):
184+
custom_json_file = sys.argv[json_file_idx]
185+
parser.epilog = get_hostgroups_help_text(custom_json_file)
186+
except (IndexError, ValueError):
187+
pass
188+
145189
args = parser.parse_args()
146190

147191
setup_logging(args.raw)
148192

149193
try:
150194
json_path = Path(args.json_file)
151195
if not json_path.exists():
152-
raise FileNotFoundError(f"JSON config file not found: {args.json_file}")
196+
raise FileNotFoundError(f"Config file not found at {args.json_file}")
153197

154198
with open(json_path, "r") as file:
155199
data = json.load(file)
156200
except json.JSONDecodeError as e:
157-
logging.error(f"Invalid JSON file: {e}")
201+
logging.error(f"Invalid JSON in config file {args.json_file}")
158202
return 1
159203
except Exception as e:
160-
logging.error(f"Error reading JSON file: {e}")
204+
logging.error(f"Could not read config file {args.json_file}")
161205
return 1
162206

163207
hostgroup = data.get(args.hostgroup)

0 commit comments

Comments
 (0)