|
20 | 20 | from aiida.cmdline.params import arguments, options |
21 | 21 | from aiida.cmdline.params.options.commands import computer as options_computer |
22 | 22 | from aiida.cmdline.utils import echo, echo_tabulate |
23 | | -from aiida.cmdline.utils.common import validate_output_filename |
| 23 | +from aiida.cmdline.utils.common import validate_output_filename, tabulate |
24 | 24 | from aiida.cmdline.utils.decorators import with_dbenv |
25 | 25 | from aiida.common.exceptions import EntryPointError, ValidationError |
26 | 26 | from aiida.plugins.entry_point import get_entry_point_names |
@@ -842,214 +842,120 @@ def computer_export_config(computer, output_file, user, overwrite, sort): |
842 | 842 | default='ssh-config', |
843 | 843 | help='Specify the computer source (default: ssh-config)', |
844 | 844 | ) |
845 | | -@click.option( |
846 | | - '--auto-setup', |
847 | | - is_flag=True, |
848 | | - default=True, |
849 | | - help='Automatically run setup and configure commands after saving config files', |
850 | | -) |
851 | 845 | @click.pass_context |
852 | 846 | @with_dbenv() |
853 | | -def computer_search(ctx, pattern, source, auto_setup): |
854 | | - """Search for computers in the AiiDA registries and setup them up in your profile. |
| 847 | +def computer_search(ctx, pattern, source): |
| 848 | + """Search for computers and setup them in your profile. |
855 | 849 |
|
856 | 850 | If PATTERN is provided, search for computers matching that pattern. |
857 | 851 | If no pattern is provided, show all available computers. |
858 | 852 |
|
859 | | - This command allows you to discover and setup computers from:\n |
860 | | - - The community AiiDA code registry at https://github.com/aiidateam/aiida-code-registry/\n |
861 | | - - The AiiDA resource registry at https://github.com/aiidateam/aiida-resource-registry/\n |
862 | | - - Your local SSH configuration at ``~/.ssh/config`` |
| 853 | + This command allows you to discover and setup computers from: |
| 854 | + - The community AiiDA code registry |
| 855 | + - The AiiDA resource registry |
| 856 | + - Your local SSH configuration at ~/.ssh/config |
863 | 857 | """ |
864 | | - |
865 | | - from aiida.cmdline.utils.common import tabulate |
866 | 858 | from aiida.cmdline.utils.registry_helpers import ( |
867 | | - fetch_code_registry_data, |
868 | | - fetch_resource_registry_data, |
869 | | - fetch_ssh_config_data, |
870 | | - get_computer_configure_config, |
871 | | - get_computer_setup_config, |
872 | | - get_computers_table, |
873 | | - interactive_computer_selector, |
874 | | - interactive_variant_selector, |
875 | | - process_template_variables, |
876 | | - save_config_to_file, |
877 | | - ) |
878 | | - |
879 | | - echo.echo_report('Fetching AiiDA registries...') |
880 | | - # NOTE: There is quite some overlap between code registry and resource registry |
881 | | - # code registry: 'daint.cscs.ch', 'imxgesrv1.epfl.ch', 'lsmosrv6', 'fidis.epfl.ch', 'tigu.empa.ch', 'paratera', |
882 | | - # 'merlin.psi.ch', 'eiger.cscs.ch' |
883 | | - # resource registry: 'eiger.cscs.ch', 'daint.cscs.ch', 'merlin.psi.ch', 'merlin7.psi.ch' |
884 | | - # if source == 'both': |
885 | | - # registry_data = fetch_code_registry_data() | fetch_resource_registry_data() |
886 | | - if source == 'ssh-config': |
887 | | - registry_data = fetch_ssh_config_data() |
888 | | - else: |
889 | | - echo.echo_report('Fetching AiiDA registries...') |
890 | | - if source == 'resource-registry': |
891 | | - registry_data = fetch_resource_registry_data() |
892 | | - elif source == 'code-registry': |
893 | | - registry_data = fetch_code_registry_data() |
894 | | - echo.echo_success(f'Successfully fetched AiiDA registry data. Found {len(registry_data)} computers.') |
895 | | - |
896 | | - matching_systems = None |
897 | | - if pattern: |
898 | | - matching_systems = [system for system in registry_data.keys() if pattern in system] |
899 | | - if not matching_systems: |
900 | | - echo.echo_warning(f"No computers found matching pattern '{pattern}'") |
901 | | - if not click.confirm('\nWould you like to show all available systems in the registry?'): |
902 | | - return |
903 | | - table = get_computers_table(registry_data) |
904 | | - echo.echo( |
905 | | - tabulate(table, headers=['System', 'Variants', 'Hostname', 'Codes (default variant)'], tablefmt='grid') |
906 | | - ) |
907 | | - else: |
908 | | - registry_data = {match: registry_data[match] for match in matching_systems} |
909 | | - echo.echo_report(f"Systems in the registry matching the pattern '{pattern}'") |
910 | | - table = get_computers_table(registry_data) |
911 | | - echo.echo( |
912 | | - tabulate(table, headers=['System', 'Variants', 'Hostname', 'Codes (default variant)'], tablefmt='grid') |
913 | | - ) |
914 | | - |
915 | | - else: |
916 | | - echo.echo_report('All available systems in the registries:') |
917 | | - table = get_computers_table(registry_data) |
918 | | - echo.echo( |
919 | | - tabulate(table, headers=['System', 'Variants', 'Hostname', 'Codes (default variant)'], tablefmt='grid') |
920 | | - ) |
| 859 | + ComputerSearchService, |
| 860 | + ComputerSelector, |
| 861 | + ComputerSetupHandler, |
| 862 | + ComputerSource, |
| 863 | + ) # noqa: PLC0415 |
921 | 864 |
|
922 | | - # import ipdb |
| 865 | + # Convert string to enum |
| 866 | + source_enum = ComputerSource(source) |
923 | 867 |
|
924 | | - # ipdb.set_trace() |
925 | | - # if source == 'ssh-config': |
926 | | - # import ipdb |
| 868 | + # Initialize service |
| 869 | + service = ComputerSearchService() |
927 | 870 |
|
928 | | - # ipdb.set_trace() |
| 871 | + # Fetch data |
| 872 | + echo.echo_report('Fetching computer data from sources...') |
| 873 | + registry_data = service.fetch_data(source_enum) |
929 | 874 |
|
930 | | - # Offer to select a computer from the retrieved table |
931 | | - if not click.confirm('\nWould you like to select a computer?', default=True): |
| 875 | + if not registry_data: |
| 876 | + echo.echo_error('No computer data could be fetched from any source.') |
932 | 877 | return |
933 | 878 |
|
934 | | - # TODO: Don't call variant selector for Computer from `ssh-config` |
935 | | - |
936 | | - # Handle computer selection based on pattern matching |
937 | | - if matching_systems and len(matching_systems) == 1: |
938 | | - # Only one match, use it directly and just select variant |
939 | | - selected_computer = matching_systems[0] |
940 | | - echo.echo_report(f'Using the only matching computer: {selected_computer}') |
941 | | - selected_variant = interactive_variant_selector(registry_data, selected_computer) |
942 | | - if not selected_variant: |
943 | | - return |
944 | | - selection = (selected_computer, selected_variant) |
945 | | - else: |
946 | | - # Multiple matches or no pattern, let user choose computer and variant |
947 | | - selected_computer = interactive_computer_selector(registry_data) |
948 | | - if not selected_computer: |
949 | | - return |
950 | | - |
951 | | - selected_variant = interactive_variant_selector(registry_data, selected_computer) |
952 | | - if not selected_variant: |
953 | | - return |
954 | | - |
955 | | - selection = (selected_computer, selected_variant) |
956 | | - |
957 | | - system_name, variant = selection |
958 | | - |
959 | | - # Get the raw configurations |
960 | | - setup_config = get_computer_setup_config(registry_data, system_name, variant) |
961 | | - configure_config = get_computer_configure_config(registry_data, system_name, variant) |
| 879 | + echo.echo_success(f'Total: {len(registry_data)} computers available from all sources.') |
962 | 880 |
|
963 | | - echo.echo_info(f'\n📋 Processing configuration for {system_name} ({variant})') |
964 | | - |
965 | | - # Process template variables for setup config |
966 | | - echo.echo_info('\n🔧 Processing computer setup configuration...') |
967 | | - processed_setup_config = process_template_variables(setup_config) |
968 | | - if processed_setup_config is None: |
969 | | - echo.echo_info('Configuration processing was cancelled.') |
| 881 | + # Filter by pattern if provided |
| 882 | + if pattern: |
| 883 | + matching_data = service.filter_by_pattern(pattern) |
| 884 | + if not matching_data: |
| 885 | + echo.echo_warning(f"No computers found matching pattern '{pattern}'") |
| 886 | + if not click.confirm('\nWould you like to show all available systems?'): |
| 887 | + return |
| 888 | + echo.echo_report('All available systems:') |
| 889 | + else: |
| 890 | + echo.echo_report(f"Systems matching the pattern '{pattern}':") |
| 891 | + registry_data = matching_data |
| 892 | + else: |
| 893 | + echo.echo_report('All available systems:') |
| 894 | + |
| 895 | + # Handle SSH-only source differently |
| 896 | + if source_enum == ComputerSource.SSH_CONFIG: |
| 897 | + # Show table of SSH config computers |
| 898 | + print(tabulate( |
| 899 | + [[i+1, k] for i, k in enumerate(registry_data.keys())], |
| 900 | + headers=['#', 'SSH Config Computer'], |
| 901 | + tablefmt='grid')) |
| 902 | + echo.echo_report('Computers registered in the ~/.ssh/config can be set up using the `core.ssh_async` transport') |
| 903 | + echo.echo_report('This transport plugin automatically uses your OS SSH configuration') |
| 904 | + echo.echo_report('for connection settings including ProxyJump, IdentityFile, and other SSH options.') |
| 905 | + echo.echo_report('For more information, see the AiiDA documentation on SSH transport plugins.') |
970 | 906 | return |
971 | 907 |
|
972 | | - # Process template variables for configure config |
973 | | - echo.echo_info('\n🔐 Processing computer configure configuration...') |
974 | | - processed_configure_config = process_template_variables(configure_config) |
975 | | - if processed_configure_config is None: |
976 | | - echo.echo_info('Configuration processing was cancelled.') |
| 908 | + selector = ComputerSelector(registry_data) |
| 909 | + selection = _get_computer_selection(selector, pattern) |
| 910 | + if not selection: |
977 | 911 | return |
978 | 912 |
|
| 913 | + system_name, variant = selection |
979 | 914 |
|
980 | | - if source == 'ssh-config': |
981 | | - echo.echo_report( |
982 | | - "We recommend running `verdi computer setup` with the `core.ssh_async` transport plugin." |
983 | | - "This will automatically use your operating system (OpenSSH) configuration." |
984 | | - ) |
985 | | - if auto_setup: |
986 | | - echo.echo_warning( |
987 | | - "Automatic setup is not possible as necessary AiiDA options not contained in ssh-config file." |
988 | | - ) |
| 915 | + # Handle SSH config computers differently |
| 916 | + if system_name.startswith('ssh:'): |
| 917 | + hostname = system_name.replace('ssh:', '') |
| 918 | + ComputerSetupHandler.handle_ssh_config_setup(system_name, hostname) |
989 | 919 | return |
990 | 920 |
|
991 | | - # Save both configurations to files |
992 | | - echo.echo_info('Saving configurations to files...') |
993 | | - |
994 | | - setup_file = save_config_to_file(processed_setup_config, 'setup', system_name, variant) |
995 | | - configure_file = save_config_to_file(processed_configure_config, 'configure', system_name, variant) |
996 | | - |
997 | | - # Get the computer label from the setup config for the configure command |
998 | | - computer_label = processed_setup_config.get('label', f'{system_name}_{variant}') |
999 | | - |
1000 | | - # Get the transport type from the setup config for the configure command |
1001 | | - transport_type = processed_setup_config.get('transport', 'core.ssh') |
1002 | | - |
1003 | | - if auto_setup: |
1004 | | - |
1005 | | - echo.echo_report('\n🚀 Automatically setting up computer...') |
1006 | | - |
1007 | | - # Invoke computer setup command |
1008 | | - from aiida.plugins import SchedulerFactory, TransportFactory |
1009 | | - |
1010 | | - # Convert strings to entry point objects (not loaded classes) |
1011 | | - processed_setup_config_copy = processed_setup_config.copy() |
1012 | | - |
1013 | | - # Get the entry point objects (load=False to get the entry point, not the loaded class) |
1014 | | - if 'scheduler' in processed_setup_config_copy: |
1015 | | - scheduler_ep = SchedulerFactory(processed_setup_config_copy['scheduler'], load=False) |
1016 | | - processed_setup_config_copy['scheduler'] = scheduler_ep |
1017 | | - |
1018 | | - if 'transport' in processed_setup_config_copy: |
1019 | | - transport_ep = TransportFactory(processed_setup_config_copy['transport'], load=False) |
1020 | | - processed_setup_config_copy['transport'] = transport_ep |
1021 | | - |
1022 | | - # Now invoke with the entry point objects |
1023 | | - ctx.invoke(computer_setup, non_interactive=False, **processed_setup_config_copy) |
1024 | | - echo.echo_success('✅ Computer setup completed successfully!') |
1025 | | - |
1026 | | - # Invoke computer configure command |
1027 | | - echo.echo_info('\n🔧 Automatically configuring computer...') |
1028 | | - |
1029 | | - # Import the transport CLI to get the configure command |
1030 | | - from aiida.transports import cli as transport_cli |
1031 | | - |
1032 | | - configure_cmd = transport_cli.create_configure_cmd(transport_type) |
1033 | | - |
1034 | | - # Get the computer object to pass to configure command |
1035 | | - from aiida.orm import Computer |
1036 | | - |
1037 | | - computer = Computer.collection.get(label=computer_label) |
| 921 | + # Prompt user before setup |
| 922 | + if not click.confirm(f'Would you like to set up the computer "{system_name}" with variant "{variant}" now?', default=True): |
| 923 | + print('Setup cancelled.') |
| 924 | + return |
1038 | 925 |
|
1039 | | - # Invoke the configure command with the config file |
1040 | | - import ipdb |
| 926 | + # Handle registry computers |
| 927 | + ComputerSetupHandler.handle_registry_setup(ctx, selector, system_name, variant, auto_setup=True) |
1041 | 928 |
|
1042 | | - ipdb.set_trace() |
1043 | | - ctx.invoke( |
1044 | | - configure_cmd, |
1045 | | - computer=computer, |
1046 | | - config_file=configure_file, |
1047 | | - ) |
1048 | | - echo.echo_success('✅ Computer configuration completed successfully!') |
1049 | | - echo.echo_success(f'🎉 Computer "{computer_label}" is now ready to use!') |
1050 | 929 |
|
1051 | | - else: |
1052 | | - echo.echo('To set up the computer, run:') |
1053 | | - echo.echo(f' verdi computer setup --config {setup_file}') |
1054 | | - echo.echo('\nTo configure the computer, run:') |
1055 | | - echo.echo(f' verdi computer configure {transport_type} {computer_label} --config {configure_file}') |
| 930 | +def _get_computer_selection(selector, pattern): |
| 931 | + """Get computer and variant selection from user.""" |
| 932 | + # Check if pattern matches exactly one system |
| 933 | + if pattern: |
| 934 | + matching_systems = [system for system in selector.registry_data.keys() if pattern in system] |
| 935 | + if len(matching_systems) == 1: |
| 936 | + selected_computer = matching_systems[0] |
| 937 | + echo.echo_report(f'Using the only matching computer: {selected_computer}') |
| 938 | + |
| 939 | + # Skip variant selection for SSH config |
| 940 | + if selected_computer.startswith('ssh:'): |
| 941 | + return (selected_computer, 'ssh_config') |
| 942 | + |
| 943 | + selected_variant = selector.select_variant(selected_computer) |
| 944 | + if not selected_variant: |
| 945 | + return None |
| 946 | + return (selected_computer, selected_variant) |
| 947 | + |
| 948 | + # Interactive selection |
| 949 | + selected_computer = selector.select_computer() |
| 950 | + if not selected_computer: |
| 951 | + return None |
| 952 | + |
| 953 | + # Skip variant selection for SSH config |
| 954 | + if selected_computer.startswith('ssh:'): |
| 955 | + return (selected_computer, 'ssh_config') |
| 956 | + |
| 957 | + selected_variant = selector.select_variant(selected_computer) |
| 958 | + if not selected_variant: |
| 959 | + return None |
| 960 | + |
| 961 | + return (selected_computer, selected_variant) |
0 commit comments