3030import uuid
3131from distutils .version import StrictVersion
3232import click
33+ from click .shell_completion import CompletionItem
3334import faculty
3435import faculty .config
3536import requests
@@ -402,6 +403,35 @@ def _format_datetime(timestamp):
402403 return timestamp .strftime ("%Y-%m-%d %H:%M" )
403404
404405
406+ def _complete_project_values (ctx , param , incomplete ):
407+ """Complete the values for project names."""
408+ return [
409+ CompletionItem (project .name , help = project .id )
410+ for project in _list_projects ()
411+ if project .name .startswith (incomplete )
412+ ]
413+
414+
415+ def _complete_server_values (ctx , param , incomplete ):
416+ """Complete the values for server name names.
417+
418+ This function relies on having a "project" variable also
419+ requested in the given context, and if there isn't one,
420+ no suggestions are returned.
421+ """
422+ if "project" not in ctx .params :
423+ return []
424+
425+ project_id = _resolve_project (ctx .params ["project" ])
426+ return [
427+ CompletionItem (server .name , help = server .id )
428+ for server in _get_servers (
429+ project_id = project_id , status = ServerStatus .RUNNING
430+ )
431+ if server .name .startswith (incomplete )
432+ ]
433+
434+
405435class FacultyCLIGroup (click .Group ):
406436 def __call__ (self , * args , ** kwargs ):
407437 try :
@@ -501,7 +531,12 @@ def server():
501531
502532
503533@server .command (name = "list" )
504- @click .argument ("project" , required = False , metavar = "PROJECT" )
534+ @click .argument (
535+ "project" ,
536+ required = False ,
537+ metavar = "PROJECT" ,
538+ shell_complete = _complete_project_values ,
539+ )
505540@click .option (
506541 "-a" ,
507542 "--all" ,
@@ -574,7 +609,7 @@ def list_servers(project, all, verbose):
574609
575610
576611@server .command (name = "open" )
577- @click .argument ("project" )
612+ @click .argument ("project" , shell_complete = _complete_project_values )
578613@click .option ("--server" , is_flag = False , help = "Name or ID of server to use." )
579614def open_ (project , server ):
580615 """Open a Faculty server in your browser."""
@@ -599,7 +634,7 @@ def open_(project, server):
599634
600635
601636@server .command ()
602- @click .argument ("project" )
637+ @click .argument ("project" , shell_complete = _complete_project_values )
603638@click .option (
604639 "--cores" ,
605640 type = float ,
@@ -698,8 +733,8 @@ def new(
698733
699734
700735@server .command ()
701- @click .argument ("project" )
702- @click .argument ("server" )
736+ @click .argument ("project" , shell_complete = _complete_project_values )
737+ @click .argument ("server" , shell_complete = _complete_server_values )
703738def terminate (project , server ):
704739 """Terminate a Faculty server."""
705740 _ , server_id = _resolve_server (project , server , ensure_running = False )
@@ -754,8 +789,8 @@ def instance_types(verbose):
754789
755790
756791@server .command ()
757- @click .argument ("project" )
758- @click .argument ("server" )
792+ @click .argument ("project" , shell_complete = _complete_project_values )
793+ @click .argument ("server" , shell_complete = _complete_server_values )
759794def ssh_details (project , server ):
760795 """Echo the username, hostname and SSH port for a Faculty server.
761796
@@ -778,8 +813,8 @@ def ssh_details(project, server):
778813
779814
780815@cli .command (context_settings = {"ignore_unknown_options" : True })
781- @click .argument ("project" )
782- @click .argument ("server" )
816+ @click .argument ("project" , shell_complete = _complete_project_values )
817+ @click .argument ("server" , shell_complete = _complete_server_values )
783818@click .argument ("ssh_opts" , nargs = - 1 , type = click .UNPROCESSED )
784819def shell (project , server , ssh_opts ):
785820 """Open a shell on a Faculty server.
@@ -816,7 +851,7 @@ def environment():
816851
817852
818853@environment .command (name = "list" )
819- @click .argument ("project" )
854+ @click .argument ("project" , shell_complete = _complete_project_values )
820855@click .option (
821856 "-v" ,
822857 "--verbose" ,
@@ -845,8 +880,8 @@ def list_environments(project, verbose):
845880
846881
847882@environment .command ()
848- @click .argument ("project" )
849- @click .argument ("server" )
883+ @click .argument ("project" , shell_complete = _complete_project_values )
884+ @click .argument ("server" , shell_complete = _complete_server_values )
850885@click .argument ("environment" )
851886def apply (project , server , environment ):
852887 """Apply an environment to the server."""
@@ -886,7 +921,7 @@ def _get_hound_url(server):
886921
887922
888923@environment .command ()
889- @click .argument ("project" )
924+ @click .argument ("project" , shell_complete = _complete_project_values )
890925@click .argument ("server" )
891926def status (project , server ):
892927 """Get the execution status for an environment."""
@@ -917,7 +952,7 @@ def status(project, server):
917952
918953
919954@environment .command ()
920- @click .argument ("project" )
955+ @click .argument ("project" , shell_complete = _complete_project_values )
921956@click .argument ("server" )
922957@click .option (
923958 "--step" ,
@@ -966,7 +1001,7 @@ def job():
9661001
9671002
9681003@job .command (name = "list" )
969- @click .argument ("project" )
1004+ @click .argument ("project" , shell_complete = _complete_project_values )
9701005@click .option (
9711006 "-v" , "--verbose" , is_flag = True , help = "Print extra information about jobs."
9721007)
@@ -994,7 +1029,7 @@ def list_jobs(project, verbose):
9941029
9951030
9961031@job .command (name = "list-runs" )
997- @click .argument ("project" )
1032+ @click .argument ("project" , shell_complete = _complete_project_values )
9981033@click .argument ("job" )
9991034@click .option (
10001035 "-v" , "--verbose" , is_flag = True , help = "Print extra information about runs."
@@ -1056,7 +1091,7 @@ def list_runs():
10561091
10571092
10581093@job .command (name = "run" )
1059- @click .argument ("project" )
1094+ @click .argument ("project" , shell_complete = _complete_project_values )
10601095@click .argument ("job" )
10611096@click .argument (
10621097 "parameter_values" ,
@@ -1117,7 +1152,7 @@ def run_job(project, job, parameter_values, num_subruns):
11171152
11181153
11191154@job .command ("logs" )
1120- @click .argument ("project" )
1155+ @click .argument ("project" , shell_complete = _complete_project_values )
11211156@click .argument ("job" )
11221157@click .argument ("run" , type = faculty_cli .parse .parse_run_identifier )
11231158def job_run_logs (project , job , run ):
@@ -1174,7 +1209,7 @@ def file():
11741209
11751210
11761211@file .command ()
1177- @click .argument ("project" )
1212+ @click .argument ("project" , shell_complete = _complete_project_values )
11781213@click .argument ("local" )
11791214@click .argument ("remote" )
11801215@click .option ("--server" , is_flag = False , help = "Name or ID of server to use." )
@@ -1207,7 +1242,7 @@ def put(project, local, remote, server):
12071242
12081243
12091244@file .command ()
1210- @click .argument ("project" )
1245+ @click .argument ("project" , shell_complete = _complete_project_values )
12111246@click .argument ("remote" )
12121247@click .argument ("local" )
12131248@click .option ("--server" , is_flag = False , help = "Name or ID of server to use." )
@@ -1273,7 +1308,7 @@ def _rsync(project, local, remote, server, rsync_opts, up):
12731308@file .command (
12741309 name = "sync-up" , context_settings = {"ignore_unknown_options" : True }
12751310)
1276- @click .argument ("project" )
1311+ @click .argument ("project" , shell_complete = _complete_project_values )
12771312@click .argument ("local" )
12781313@click .argument ("remote" )
12791314@click .argument ("rsync_opts" , nargs = - 1 , type = click .UNPROCESSED )
@@ -1290,7 +1325,7 @@ def sync_up(project, local, remote, server, rsync_opts):
12901325@file .command (
12911326 name = "sync-down" , context_settings = {"ignore_unknown_options" : True }
12921327)
1293- @click .argument ("project" )
1328+ @click .argument ("project" , shell_complete = _complete_project_values )
12941329@click .argument ("remote" )
12951330@click .argument ("local" )
12961331@click .argument ("rsync_opts" , nargs = - 1 , type = click .UNPROCESSED )
@@ -1305,7 +1340,7 @@ def sync_down(project, remote, local, server, rsync_opts):
13051340
13061341
13071342@file .command ()
1308- @click .argument ("project" )
1343+ @click .argument ("project" , shell_complete = _complete_project_values )
13091344@click .argument ("path" )
13101345def ls (project , path ):
13111346 """List files and directories on Faculty workspace."""
@@ -1342,7 +1377,7 @@ def datasets():
13421377
13431378
13441379@datasets .command (name = "get" )
1345- @click .argument ("project" )
1380+ @click .argument ("project" , shell_complete = _complete_project_values )
13461381@click .argument ("project_path" )
13471382@click .argument ("local_path" )
13481383def dataset_get (project , project_path , local_path ):
@@ -1357,7 +1392,7 @@ def dataset_get(project, project_path, local_path):
13571392
13581393
13591394@datasets .command (name = "put" )
1360- @click .argument ("project" )
1395+ @click .argument ("project" , shell_complete = _complete_project_values )
13611396@click .argument ("local_path" )
13621397@click .argument ("project_path" )
13631398def dataset_put (project , local_path , project_path ):
@@ -1370,7 +1405,7 @@ def dataset_put(project, local_path, project_path):
13701405
13711406
13721407@datasets .command ()
1373- @click .argument ("project" )
1408+ @click .argument ("project" , shell_complete = _complete_project_values )
13741409@click .argument ("source_path" )
13751410@click .argument ("destination_path" )
13761411def mv (project , source_path , destination_path ):
@@ -1385,7 +1420,7 @@ def mv(project, source_path, destination_path):
13851420
13861421
13871422@datasets .command ()
1388- @click .argument ("project" )
1423+ @click .argument ("project" , shell_complete = _complete_project_values )
13891424@click .argument ("source_path" )
13901425@click .argument ("destination_path" )
13911426@click .option (
@@ -1411,7 +1446,7 @@ def cp(project, source_path, destination_path, recursive):
14111446
14121447
14131448@datasets .command ()
1414- @click .argument ("project" )
1449+ @click .argument ("project" , shell_complete = _complete_project_values )
14151450@click .argument ("project_path" )
14161451@click .option (
14171452 "--recursive" ,
@@ -1433,7 +1468,7 @@ def rm(project, project_path, recursive):
14331468
14341469
14351470@datasets .command (name = "ls" )
1436- @click .argument ("project" )
1471+ @click .argument ("project" , shell_complete = _complete_project_values )
14371472@click .option (
14381473 "--prefix" ,
14391474 default = "/" ,
0 commit comments