@@ -120,6 +120,15 @@ def parse_args(argv: List[str]) -> argparse.Namespace:
120
120
parser = argparse .ArgumentParser (
121
121
description = description , formatter_class = formatter_class
122
122
)
123
+ parser .add_argument (
124
+ "org-name" ,
125
+ nargs = "?" ,
126
+ action = "store" ,
127
+ default = "" ,
128
+ help = "Enter a unique name for your zulip organization profile. "
129
+ "It can be an acronym or a nickname. This will serve "
130
+ "as a local alias for your organization's configuration profile." ,
131
+ )
123
132
parser .add_argument (
124
133
"-v" ,
125
134
"--version" ,
@@ -132,7 +141,7 @@ def parse_args(argv: List[str]) -> argparse.Namespace:
132
141
"-c" ,
133
142
action = "store" ,
134
143
help = "config file downloaded from your zulip "
135
- "organization (default: ~/.config/zulip/.zuliprc)" ,
144
+ "organization (default: ~/.config/zulip/org-name .zuliprc)" ,
136
145
)
137
146
parser .add_argument (
138
147
"--theme" ,
@@ -265,9 +274,9 @@ def get_api_key(realm_url: str) -> Optional[Tuple[str, str, str]]:
265
274
return None
266
275
267
276
268
- def fetch_zuliprc (zuliprc_path : Path ) -> None :
277
+ def fetch_zuliprc (zuliprc_path : Path , org_name : str ) -> Path :
269
278
print (
270
- f"{ in_color ('red' , f'.zuliprc file was not found at { zuliprc_path } ' )} "
279
+ f"{ in_color ('red' , f'{ zuliprc_path } was not found. ' )} "
271
280
f"\n Please enter your credentials to login into your Zulip organization."
272
281
f"\n "
273
282
f"\n NOTE: The { in_color ('blue' , 'Zulip server URL' )} "
@@ -292,6 +301,9 @@ def fetch_zuliprc(zuliprc_path: Path) -> None:
292
301
login_data = get_api_key (realm_url )
293
302
294
303
preferred_realm_url , login_id , api_key = login_data
304
+ if org_name == "" :
305
+ zuliprc_path = default_zuliprc_path ()
306
+ zuliprc_path = _prompt_org_name_change (zuliprc_path , org_name )
295
307
save_zuliprc_failure = _write_zuliprc (
296
308
zuliprc_path ,
297
309
login_id = login_id ,
@@ -302,32 +314,60 @@ def fetch_zuliprc(zuliprc_path: Path) -> None:
302
314
print (f"Generated API key saved at { zuliprc_path } " )
303
315
else :
304
316
exit_with_error (save_zuliprc_failure )
317
+ return zuliprc_path
318
+
319
+
320
+ def _prompt_org_name_change (zuliprc_path : Path , org_name : str ) -> Path :
321
+ if org_name == "" :
322
+ update_org_name = styled_input (
323
+ "Do you wish to assign an alias to refer to this server? [y/N] "
324
+ )
325
+ else :
326
+ update_org_name = styled_input (
327
+ f"You have set the alias '{ zuliprc_path .stem } ' for this server."
328
+ f" Do you wish to use a different alias? [y/N] "
329
+ )
330
+ if update_org_name .lower () in ["y" , "yes" ]:
331
+ new_org_name = styled_input ("Enter new alias: " )
332
+ zuliprc_path = default_zuliprc_path (new_org_name )
333
+ return zuliprc_path
305
334
306
335
307
336
def _write_zuliprc (
308
- to_path : Path , * , login_id : str , api_key : str , server_url : str
337
+ to_path : Path ,
338
+ * ,
339
+ login_id : Optional [str ] = None ,
340
+ api_key : Optional [str ] = None ,
341
+ server_url : Optional [str ] = None ,
342
+ file_contents : Optional [str ] = None ,
309
343
) -> str :
310
344
"""
311
345
Writes a .zuliprc file, returning a non-empty error string on failure
312
346
Only creates new private files; errors if file already exists
313
347
"""
314
348
try :
349
+ to_path .parent .mkdir (parents = True , exist_ok = True )
315
350
with open (
316
351
os .open (to_path , os .O_CREAT | os .O_WRONLY | os .O_EXCL , 0o600 ), "w"
317
352
) as f :
318
- f .write (f"[api]\n email={ login_id } \n key={ api_key } \n site={ server_url } " )
353
+ if file_contents is not None :
354
+ f .write (file_contents )
355
+ else :
356
+ f .write (f"[api]\n email={ login_id } \n key={ api_key } \n site={ server_url } " )
319
357
return ""
320
358
except FileExistsError :
321
- return f".zuliprc already exists at { to_path } "
359
+ return f"{ to_path } already exists. "
322
360
except OSError as ex :
323
- return f"{ ex .__class__ .__name__ } : .zuliprc could not be created at { to_path } "
361
+ return f"{ ex .__class__ .__name__ } : { to_path } could not be created. "
324
362
325
363
326
- def parse_zuliprc (zuliprc_str : str ) -> Dict [str , SettingData ]:
327
- zuliprc_path = Path (zuliprc_str ).expanduser ()
364
+ def parse_zuliprc (
365
+ zuliprc_path : Path , org_name : str
366
+ ) -> Tuple [Dict [str , SettingData ], Path ]:
367
+ zuliprc_path = zuliprc_path .expanduser ()
328
368
while not path .exists (zuliprc_path ):
329
369
try :
330
- fetch_zuliprc (zuliprc_path )
370
+ zuliprc_path = fetch_zuliprc (zuliprc_path , org_name )
331
371
# Invalid user inputs (e.g. pressing arrow keys) may cause ValueError
332
372
except (OSError , ValueError ):
333
373
# Remove zuliprc file if created.
@@ -345,13 +385,15 @@ def parse_zuliprc(zuliprc_str: str) -> Dict[str, SettingData]:
345
385
print (
346
386
in_color (
347
387
"red" ,
348
- "ERROR: Please ensure your .zuliprc is NOT publicly accessible:\n "
388
+ "ERROR: Please ensure your {2} is NOT publicly accessible:\n "
349
389
" {0}\n "
350
390
"(it currently has permissions '{1}')\n "
351
391
"This can often be achieved with a command such as:\n "
352
392
" chmod og-rwx {0}\n "
353
- "Consider regenerating the [api] part of your .zuliprc to ensure "
354
- "your account is secure." .format (zuliprc_path , stat .filemode (mode )),
393
+ "Consider regenerating the [api] part of your {2} to ensure "
394
+ "your account is secure." .format (
395
+ zuliprc_path , stat .filemode (mode ), zuliprc_path .name
396
+ ),
355
397
)
356
398
)
357
399
sys .exit (1 )
@@ -361,9 +403,13 @@ def parse_zuliprc(zuliprc_str: str) -> Dict[str, SettingData]:
361
403
try :
362
404
res = zuliprc .read (zuliprc_path )
363
405
if len (res ) == 0 :
364
- exit_with_error (f"Could not access .zuliprc file at { zuliprc_path } " )
406
+ exit_with_error (
407
+ f"Could not access { zuliprc_path .name } file at { zuliprc_path .parent } "
408
+ )
365
409
except configparser .MissingSectionHeaderError :
366
- exit_with_error (f"Failed to parse .zuliprc file at { zuliprc_path } " )
410
+ exit_with_error (
411
+ f"Failed to parse { zuliprc_path .name } file at { zuliprc_path .parent } "
412
+ )
367
413
368
414
# Initialize with default settings
369
415
settings = {
@@ -376,7 +422,7 @@ def parse_zuliprc(zuliprc_str: str) -> Dict[str, SettingData]:
376
422
for conf in config :
377
423
settings [conf ] = SettingData (config [conf ], ConfigSource .ZULIPRC )
378
424
379
- return settings
425
+ return settings , zuliprc_path
380
426
381
427
382
428
def list_themes () -> str :
@@ -388,7 +434,7 @@ def list_themes() -> str:
388
434
suffix += "[default theme]"
389
435
text += f" { theme } { suffix } \n "
390
436
return text + (
391
- "Specify theme in .zuliprc file or override "
437
+ "Specify theme in a .zuliprc file or override "
392
438
"using -t/--theme options on command line."
393
439
)
394
440
@@ -402,6 +448,10 @@ def xdg_config_home() -> Path:
402
448
return Path .home () / ".config"
403
449
404
450
451
+ def default_zuliprc_path (org_name : Optional [str ] = "" ) -> Path :
452
+ return xdg_config_home () / "zulip" / f"{ org_name } .zuliprc"
453
+
454
+
405
455
def main (options : Optional [List [str ]] = None ) -> None :
406
456
"""
407
457
Launch Zulip Terminal.
@@ -440,10 +490,13 @@ def main(options: Optional[List[str]] = None) -> None:
440
490
print (list_themes ())
441
491
sys .exit (0 )
442
492
493
+ org_name = getattr (args , "org-name" )
443
494
if args .config_file :
444
- zuliprc_path = args .config_file
495
+ if org_name != "" :
496
+ exit_with_error ("Cannot use --config-file and org-name together" )
497
+ zuliprc_path = Path (args .config_file )
445
498
else :
446
- zuliprc_path = xdg_config_home () / "zulip" / ".zuliprc"
499
+ zuliprc_path = default_zuliprc_path ( org_name )
447
500
448
501
print (
449
502
"Detected:"
@@ -452,7 +505,7 @@ def main(options: Optional[List[str]] = None) -> None:
452
505
)
453
506
454
507
try :
455
- zterm = parse_zuliprc (zuliprc_path )
508
+ zterm , zuliprc_path = parse_zuliprc (zuliprc_path , org_name )
456
509
457
510
### Validate footlinks settings (not from command line)
458
511
if (
@@ -528,7 +581,10 @@ def main(options: Optional[List[str]] = None) -> None:
528
581
helper_text = (
529
582
["Valid values are:" ]
530
583
+ [f" { option } " for option in valid_remaining_values ]
531
- + [f"Specify the { setting } option in .zuliprc file." ]
584
+ + [
585
+ f"Specify the { setting } option "
586
+ f"in { Path (zuliprc_path ).name } file."
587
+ ]
532
588
)
533
589
exit_with_error (
534
590
"Invalid {} setting '{}' was specified {}." .format (
@@ -577,7 +633,7 @@ def print_setting(setting: str, data: SettingData, suffix: str = "") -> None:
577
633
boolean_settings [setting ] = zterm [setting ].value == valid_boolean_values [0 ]
578
634
579
635
Controller (
580
- config_file = zuliprc_path ,
636
+ config_file = str ( zuliprc_path ) ,
581
637
maximum_footlinks = maximum_footlinks ,
582
638
theme_name = theme_to_use .value ,
583
639
theme = theme_data ,
0 commit comments