mtncloud-cli 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.dockerignore +20 -0
- data/.github/pull_request_template.md +14 -0
- data/.github/workflows/ci.yml +56 -0
- data/.github/workflows/release.yml +46 -0
- data/.gitignore +25 -0
- data/CLAUDE.md +24 -0
- data/CONTRIBUTING.md +91 -0
- data/Dockerfile +19 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +23 -0
- data/README.md +187 -0
- data/Rakefile +26 -0
- data/bin/mcs +3 -0
- data/bin/mtncloud +27 -0
- data/lib/mtncloud/api/account_groups_interface.rb +48 -0
- data/lib/mtncloud/api/account_users_interface.rb +68 -0
- data/lib/mtncloud/api/accounts_interface.rb +9 -0
- data/lib/mtncloud/api/activity_interface.rb +9 -0
- data/lib/mtncloud/api/affinity_groups_interface.rb +46 -0
- data/lib/mtncloud/api/api_client.rb +1091 -0
- data/lib/mtncloud/api/appliance_settings_interface.rb +49 -0
- data/lib/mtncloud/api/approvals_interface.rb +32 -0
- data/lib/mtncloud/api/apps_interface.rb +180 -0
- data/lib/mtncloud/api/archive_buckets_interface.rb +116 -0
- data/lib/mtncloud/api/archive_files_interface.rb +173 -0
- data/lib/mtncloud/api/audit_interface.rb +9 -0
- data/lib/mtncloud/api/auth_interface.rb +58 -0
- data/lib/mtncloud/api/backup_jobs_interface.rb +13 -0
- data/lib/mtncloud/api/backup_restores_interface.rb +27 -0
- data/lib/mtncloud/api/backup_results_interface.rb +32 -0
- data/lib/mtncloud/api/backup_service_types_interface.rb +9 -0
- data/lib/mtncloud/api/backup_services_interface.rb +9 -0
- data/lib/mtncloud/api/backup_settings_interface.rb +20 -0
- data/lib/mtncloud/api/backup_types_interface.rb +9 -0
- data/lib/mtncloud/api/backups_interface.rb +21 -0
- data/lib/mtncloud/api/billing_interface.rb +34 -0
- data/lib/mtncloud/api/blueprints_interface.rb +70 -0
- data/lib/mtncloud/api/body_io.rb +22 -0
- data/lib/mtncloud/api/budgets_interface.rb +48 -0
- data/lib/mtncloud/api/catalog_item_types_interface.rb +29 -0
- data/lib/mtncloud/api/certificate_types_interface.rb +14 -0
- data/lib/mtncloud/api/certificates_interface.rb +9 -0
- data/lib/mtncloud/api/clients_interface.rb +41 -0
- data/lib/mtncloud/api/cloud_datastores_interface.rb +48 -0
- data/lib/mtncloud/api/cloud_folders_interface.rb +41 -0
- data/lib/mtncloud/api/cloud_policies_interface.rb +41 -0
- data/lib/mtncloud/api/cloud_resource_pools_interface.rb +66 -0
- data/lib/mtncloud/api/clouds_interface.rb +217 -0
- data/lib/mtncloud/api/clusters_interface.rb +471 -0
- data/lib/mtncloud/api/containers_interface.rb +145 -0
- data/lib/mtncloud/api/credential_types_interface.rb +9 -0
- data/lib/mtncloud/api/credentials_interface.rb +9 -0
- data/lib/mtncloud/api/custom_instance_types_interface.rb +99 -0
- data/lib/mtncloud/api/cypher_interface.rb +51 -0
- data/lib/mtncloud/api/dashboard_interface.rb +14 -0
- data/lib/mtncloud/api/datastores_interface.rb +21 -0
- data/lib/mtncloud/api/deploy_interface.rb +44 -0
- data/lib/mtncloud/api/deployments_interface.rb +79 -0
- data/lib/mtncloud/api/distributed_workers_interface.rb +41 -0
- data/lib/mtncloud/api/email_templates_interface.rb +53 -0
- data/lib/mtncloud/api/environments_interface.rb +48 -0
- data/lib/mtncloud/api/execute_schedules_interface.rb +71 -0
- data/lib/mtncloud/api/execution_request_interface.rb +27 -0
- data/lib/mtncloud/api/file_copy_request_interface.rb +68 -0
- data/lib/mtncloud/api/forgot_password_interface.rb +17 -0
- data/lib/mtncloud/api/group_policies_interface.rb +41 -0
- data/lib/mtncloud/api/groups_interface.rb +73 -0
- data/lib/mtncloud/api/guidance_interface.rb +44 -0
- data/lib/mtncloud/api/guidance_settings_interface.rb +17 -0
- data/lib/mtncloud/api/health_interface.rb +100 -0
- data/lib/mtncloud/api/host_vm_groups_interface.rb +37 -0
- data/lib/mtncloud/api/hub_interface.rb +25 -0
- data/lib/mtncloud/api/image_builder_boot_scripts_interface.rb +41 -0
- data/lib/mtncloud/api/image_builder_image_builds_interface.rb +73 -0
- data/lib/mtncloud/api/image_builder_interface.rb +20 -0
- data/lib/mtncloud/api/image_builder_preseed_scripts_interface.rb +41 -0
- data/lib/mtncloud/api/instance_types_interface.rb +20 -0
- data/lib/mtncloud/api/instances_interface.rb +453 -0
- data/lib/mtncloud/api/integration_types_interface.rb +14 -0
- data/lib/mtncloud/api/integrations_interface.rb +74 -0
- data/lib/mtncloud/api/invoice_line_items_interface.rb +9 -0
- data/lib/mtncloud/api/invoices_interface.rb +28 -0
- data/lib/mtncloud/api/jobs_interface.rb +83 -0
- data/lib/mtncloud/api/key_pairs_interface.rb +57 -0
- data/lib/mtncloud/api/library_cluster_layouts_interface.rb +47 -0
- data/lib/mtncloud/api/library_cluster_packages_interface.rb +60 -0
- data/lib/mtncloud/api/library_container_scripts_interface.rb +43 -0
- data/lib/mtncloud/api/library_container_templates_interface.rb +43 -0
- data/lib/mtncloud/api/library_container_types_interface.rb +59 -0
- data/lib/mtncloud/api/library_container_upgrades_interface.rb +60 -0
- data/lib/mtncloud/api/library_instance_types_interface.rb +74 -0
- data/lib/mtncloud/api/library_layouts_interface.rb +69 -0
- data/lib/mtncloud/api/library_operating_systems_interface.rb +63 -0
- data/lib/mtncloud/api/library_spec_template_types_interface.rb +43 -0
- data/lib/mtncloud/api/library_spec_templates_interface.rb +43 -0
- data/lib/mtncloud/api/license_interface.rb +30 -0
- data/lib/mtncloud/api/load_balancer_monitors_interface.rb +9 -0
- data/lib/mtncloud/api/load_balancer_pool_nodes_interface.rb +8 -0
- data/lib/mtncloud/api/load_balancer_pools_interface.rb +9 -0
- data/lib/mtncloud/api/load_balancer_pools_secondary_interface.rb +9 -0
- data/lib/mtncloud/api/load_balancer_profiles_interface.rb +9 -0
- data/lib/mtncloud/api/load_balancer_types_interface.rb +9 -0
- data/lib/mtncloud/api/load_balancer_virtual_servers_interface.rb +18 -0
- data/lib/mtncloud/api/load_balancers_interface.rb +14 -0
- data/lib/mtncloud/api/log_settings_interface.rb +44 -0
- data/lib/mtncloud/api/logs_interface.rb +37 -0
- data/lib/mtncloud/api/migrations_interface.rb +49 -0
- data/lib/mtncloud/api/monitoring_alerts_interface.rb +39 -0
- data/lib/mtncloud/api/monitoring_apps_interface.rb +69 -0
- data/lib/mtncloud/api/monitoring_checks_interface.rb +103 -0
- data/lib/mtncloud/api/monitoring_contacts_interface.rb +41 -0
- data/lib/mtncloud/api/monitoring_groups_interface.rb +77 -0
- data/lib/mtncloud/api/monitoring_incidents_interface.rb +107 -0
- data/lib/mtncloud/api/monitoring_interface.rb +35 -0
- data/lib/mtncloud/api/monitoring_settings_interface.rb +21 -0
- data/lib/mtncloud/api/network_dhcp_relays_interface.rb +36 -0
- data/lib/mtncloud/api/network_dhcp_servers_interface.rb +36 -0
- data/lib/mtncloud/api/network_domain_records_interface.rb +41 -0
- data/lib/mtncloud/api/network_domains_interface.rb +41 -0
- data/lib/mtncloud/api/network_edge_clusters_interface.rb +26 -0
- data/lib/mtncloud/api/network_floating_ips_interface.rb +40 -0
- data/lib/mtncloud/api/network_groups_interface.rb +41 -0
- data/lib/mtncloud/api/network_pool_ips_interface.rb +41 -0
- data/lib/mtncloud/api/network_pool_server_types_interface.rb +9 -0
- data/lib/mtncloud/api/network_pool_servers_interface.rb +48 -0
- data/lib/mtncloud/api/network_pools_interface.rb +41 -0
- data/lib/mtncloud/api/network_proxies_interface.rb +41 -0
- data/lib/mtncloud/api/network_routers_interface.rb +181 -0
- data/lib/mtncloud/api/network_security_server_types_interface.rb +9 -0
- data/lib/mtncloud/api/network_security_servers_interface.rb +27 -0
- data/lib/mtncloud/api/network_server_groups_interface.rb +7 -0
- data/lib/mtncloud/api/network_server_types_interface.rb +9 -0
- data/lib/mtncloud/api/network_servers_interface.rb +102 -0
- data/lib/mtncloud/api/network_services_interface.rb +63 -0
- data/lib/mtncloud/api/network_static_routes_interface.rb +36 -0
- data/lib/mtncloud/api/network_subnets_interface.rb +42 -0
- data/lib/mtncloud/api/network_types_interface.rb +20 -0
- data/lib/mtncloud/api/networks_interface.rb +48 -0
- data/lib/mtncloud/api/option_type_forms_interface.rb +9 -0
- data/lib/mtncloud/api/option_type_lists_interface.rb +53 -0
- data/lib/mtncloud/api/option_types_interface.rb +41 -0
- data/lib/mtncloud/api/options_interface.rb +17 -0
- data/lib/mtncloud/api/packages_interface.rb +112 -0
- data/lib/mtncloud/api/ping_interface.rb +22 -0
- data/lib/mtncloud/api/plugins_interface.rb +22 -0
- data/lib/mtncloud/api/policies_interface.rb +56 -0
- data/lib/mtncloud/api/power_schedules_interface.rb +71 -0
- data/lib/mtncloud/api/price_sets_interface.rb +39 -0
- data/lib/mtncloud/api/prices_interface.rb +71 -0
- data/lib/mtncloud/api/processes_interface.rb +40 -0
- data/lib/mtncloud/api/projects_interface.rb +33 -0
- data/lib/mtncloud/api/provision_types_interface.rb +24 -0
- data/lib/mtncloud/api/provisioning_license_types_interface.rb +31 -0
- data/lib/mtncloud/api/provisioning_licenses_interface.rb +60 -0
- data/lib/mtncloud/api/provisioning_settings_interface.rb +26 -0
- data/lib/mtncloud/api/read_interface.rb +24 -0
- data/lib/mtncloud/api/reports_interface.rb +70 -0
- data/lib/mtncloud/api/resource_pool_groups_interface.rb +51 -0
- data/lib/mtncloud/api/rest_interface.rb +37 -0
- data/lib/mtncloud/api/roles_interface.rb +151 -0
- data/lib/mtncloud/api/scale_thresholds_interface.rb +9 -0
- data/lib/mtncloud/api/search_interface.rb +13 -0
- data/lib/mtncloud/api/secondary_read_interface.rb +25 -0
- data/lib/mtncloud/api/secondary_rest_interface.rb +42 -0
- data/lib/mtncloud/api/security_group_rules_interface.rb +35 -0
- data/lib/mtncloud/api/security_groups_interface.rb +56 -0
- data/lib/mtncloud/api/security_package_types_interface.rb +9 -0
- data/lib/mtncloud/api/security_packages_interface.rb +9 -0
- data/lib/mtncloud/api/security_scans_interface.rb +9 -0
- data/lib/mtncloud/api/server_devices_interface.rb +30 -0
- data/lib/mtncloud/api/server_types_interface.rb +20 -0
- data/lib/mtncloud/api/servers_interface.rb +230 -0
- data/lib/mtncloud/api/service_catalog_interface.rb +89 -0
- data/lib/mtncloud/api/service_plans_interface.rb +62 -0
- data/lib/mtncloud/api/setup_interface.rb +46 -0
- data/lib/mtncloud/api/snapshots_interface.rb +19 -0
- data/lib/mtncloud/api/storage_datastores_interface.rb +44 -0
- data/lib/mtncloud/api/storage_providers_interface.rb +151 -0
- data/lib/mtncloud/api/storage_server_types_interface.rb +14 -0
- data/lib/mtncloud/api/storage_servers_interface.rb +9 -0
- data/lib/mtncloud/api/storage_volume_types_interface.rb +9 -0
- data/lib/mtncloud/api/storage_volumes_interface.rb +24 -0
- data/lib/mtncloud/api/subnet_types_interface.rb +20 -0
- data/lib/mtncloud/api/subnets_interface.rb +41 -0
- data/lib/mtncloud/api/support_bundles_interface.rb +46 -0
- data/lib/mtncloud/api/system_types_interface.rb +13 -0
- data/lib/mtncloud/api/systems_interface.rb +55 -0
- data/lib/mtncloud/api/task_sets_interface.rb +52 -0
- data/lib/mtncloud/api/tasks_interface.rb +66 -0
- data/lib/mtncloud/api/tokens_interface.rb +39 -0
- data/lib/mtncloud/api/usage_interface.rb +18 -0
- data/lib/mtncloud/api/user_groups_interface.rb +59 -0
- data/lib/mtncloud/api/user_settings_interface.rb +90 -0
- data/lib/mtncloud/api/user_sources_interface.rb +99 -0
- data/lib/mtncloud/api/users_interface.rb +33 -0
- data/lib/mtncloud/api/vdi_allocations_interface.rb +9 -0
- data/lib/mtncloud/api/vdi_apps_interface.rb +9 -0
- data/lib/mtncloud/api/vdi_gateways_interface.rb +9 -0
- data/lib/mtncloud/api/vdi_interface.rb +28 -0
- data/lib/mtncloud/api/vdi_pools_interface.rb +19 -0
- data/lib/mtncloud/api/virtual_images_interface.rb +210 -0
- data/lib/mtncloud/api/virtual_servers_interface.rb +9 -0
- data/lib/mtncloud/api/virtual_switches_interface.rb +9 -0
- data/lib/mtncloud/api/whitelabel_settings_interface.rb +57 -0
- data/lib/mtncloud/api/whoami_interface.rb +13 -0
- data/lib/mtncloud/api/wiki_interface.rb +48 -0
- data/lib/mtncloud/api.rb +12 -0
- data/lib/mtncloud/benchmarking.rb +259 -0
- data/lib/mtncloud/cli/cli_command.rb +2281 -0
- data/lib/mtncloud/cli/cli_registry.rb +337 -0
- data/lib/mtncloud/cli/commands/access_token_command.rb +201 -0
- data/lib/mtncloud/cli/commands/account_groups_command.rb +530 -0
- data/lib/mtncloud/cli/commands/activity_command.rb +149 -0
- data/lib/mtncloud/cli/commands/affinity_groups_command.rb +554 -0
- data/lib/mtncloud/cli/commands/alias_command.rb +278 -0
- data/lib/mtncloud/cli/commands/appliance_settings_command.rb +382 -0
- data/lib/mtncloud/cli/commands/approvals_command.rb +236 -0
- data/lib/mtncloud/cli/commands/apps.rb +2549 -0
- data/lib/mtncloud/cli/commands/archives_command.rb +2161 -0
- data/lib/mtncloud/cli/commands/audit.rb +188 -0
- data/lib/mtncloud/cli/commands/backup_jobs_command.rb +366 -0
- data/lib/mtncloud/cli/commands/backup_restores_command.rb +144 -0
- data/lib/mtncloud/cli/commands/backup_results_command.rb +149 -0
- data/lib/mtncloud/cli/commands/backup_services_command.rb +44 -0
- data/lib/mtncloud/cli/commands/backup_settings_command.rb +184 -0
- data/lib/mtncloud/cli/commands/backup_types_command.rb +53 -0
- data/lib/mtncloud/cli/commands/backups_command.rb +674 -0
- data/lib/mtncloud/cli/commands/benchmark_command.rb +458 -0
- data/lib/mtncloud/cli/commands/blueprints_command.rb +2297 -0
- data/lib/mtncloud/cli/commands/boot_scripts_command.rb +379 -0
- data/lib/mtncloud/cli/commands/budgets_command.rb +754 -0
- data/lib/mtncloud/cli/commands/cat_command.rb +45 -0
- data/lib/mtncloud/cli/commands/catalog_item_types_command.rb +858 -0
- data/lib/mtncloud/cli/commands/certificates_command.rb +575 -0
- data/lib/mtncloud/cli/commands/change_password_command.rb +132 -0
- data/lib/mtncloud/cli/commands/clients_command.rb +331 -0
- data/lib/mtncloud/cli/commands/cloud_datastores_command.rb +543 -0
- data/lib/mtncloud/cli/commands/cloud_folders_command.rb +512 -0
- data/lib/mtncloud/cli/commands/cloud_resource_pools_command.rb +870 -0
- data/lib/mtncloud/cli/commands/clouds.rb +2037 -0
- data/lib/mtncloud/cli/commands/clouds_types.rb +140 -0
- data/lib/mtncloud/cli/commands/cluster_types.rb +179 -0
- data/lib/mtncloud/cli/commands/clusters.rb +5855 -0
- data/lib/mtncloud/cli/commands/coloring_command.rb +82 -0
- data/lib/mtncloud/cli/commands/containers_command.rb +967 -0
- data/lib/mtncloud/cli/commands/credential_types_command.rb +36 -0
- data/lib/mtncloud/cli/commands/credentials_command.rb +124 -0
- data/lib/mtncloud/cli/commands/curl_command.rb +168 -0
- data/lib/mtncloud/cli/commands/cypher_command.rb +587 -0
- data/lib/mtncloud/cli/commands/dashboard_command.rb +300 -0
- data/lib/mtncloud/cli/commands/debug_command.rb +75 -0
- data/lib/mtncloud/cli/commands/deploy.rb +485 -0
- data/lib/mtncloud/cli/commands/deployments.rb +923 -0
- data/lib/mtncloud/cli/commands/deploys.rb +485 -0
- data/lib/mtncloud/cli/commands/distributed_workers_command.rb +282 -0
- data/lib/mtncloud/cli/commands/echo_command.rb +61 -0
- data/lib/mtncloud/cli/commands/edit_profile_command.rb +57 -0
- data/lib/mtncloud/cli/commands/edit_rc_command.rb +77 -0
- data/lib/mtncloud/cli/commands/email_templates_command.rb +373 -0
- data/lib/mtncloud/cli/commands/environments_command.rb +401 -0
- data/lib/mtncloud/cli/commands/execute_schedules_command.rb +735 -0
- data/lib/mtncloud/cli/commands/execution_request_command.rb +333 -0
- data/lib/mtncloud/cli/commands/exit_command.rb +34 -0
- data/lib/mtncloud/cli/commands/file_copy_request_command.rb +352 -0
- data/lib/mtncloud/cli/commands/forgot_password.rb +133 -0
- data/lib/mtncloud/cli/commands/get_prompt_command.rb +36 -0
- data/lib/mtncloud/cli/commands/groups.rb +818 -0
- data/lib/mtncloud/cli/commands/guidance_command.rb +529 -0
- data/lib/mtncloud/cli/commands/guidance_settings.rb +148 -0
- data/lib/mtncloud/cli/commands/health_command.rb +1046 -0
- data/lib/mtncloud/cli/commands/history_command.rb +60 -0
- data/lib/mtncloud/cli/commands/host_vm_groups_command.rb +423 -0
- data/lib/mtncloud/cli/commands/hosts.rb +2986 -0
- data/lib/mtncloud/cli/commands/hub.rb +215 -0
- data/lib/mtncloud/cli/commands/image_builder_command.rb +1197 -0
- data/lib/mtncloud/cli/commands/instance_types.rb +163 -0
- data/lib/mtncloud/cli/commands/instances.rb +5813 -0
- data/lib/mtncloud/cli/commands/integrations_command.rb +1412 -0
- data/lib/mtncloud/cli/commands/invoices_command.rb +1151 -0
- data/lib/mtncloud/cli/commands/jobs_command.rb +998 -0
- data/lib/mtncloud/cli/commands/key_pairs.rb +470 -0
- data/lib/mtncloud/cli/commands/library_cluster_layouts_command.rb +901 -0
- data/lib/mtncloud/cli/commands/library_cluster_packages_command.rb +552 -0
- data/lib/mtncloud/cli/commands/library_container_scripts_command.rb +446 -0
- data/lib/mtncloud/cli/commands/library_container_templates_command.rb +526 -0
- data/lib/mtncloud/cli/commands/library_container_types_command.rb +698 -0
- data/lib/mtncloud/cli/commands/library_forms_command.rb +625 -0
- data/lib/mtncloud/cli/commands/library_instance_types_command.rb +668 -0
- data/lib/mtncloud/cli/commands/library_layouts_command.rb +849 -0
- data/lib/mtncloud/cli/commands/library_operating_systems_command.rb +671 -0
- data/lib/mtncloud/cli/commands/library_option_lists_command.rb +503 -0
- data/lib/mtncloud/cli/commands/library_option_types_command.rb +329 -0
- data/lib/mtncloud/cli/commands/library_spec_templates_command.rb +547 -0
- data/lib/mtncloud/cli/commands/library_upgrades_command.rb +596 -0
- data/lib/mtncloud/cli/commands/license.rb +475 -0
- data/lib/mtncloud/cli/commands/load_balancer_monitors.rb +70 -0
- data/lib/mtncloud/cli/commands/load_balancer_pool_nodes.rb +87 -0
- data/lib/mtncloud/cli/commands/load_balancer_pools.rb +129 -0
- data/lib/mtncloud/cli/commands/load_balancer_profiles.rb +64 -0
- data/lib/mtncloud/cli/commands/load_balancer_types.rb +38 -0
- data/lib/mtncloud/cli/commands/load_balancer_virtual_servers.rb +147 -0
- data/lib/mtncloud/cli/commands/load_balancers.rb +189 -0
- data/lib/mtncloud/cli/commands/log_level_command.rb +54 -0
- data/lib/mtncloud/cli/commands/log_settings_command.rb +443 -0
- data/lib/mtncloud/cli/commands/login.rb +148 -0
- data/lib/mtncloud/cli/commands/logout.rb +63 -0
- data/lib/mtncloud/cli/commands/logs_command.rb +140 -0
- data/lib/mtncloud/cli/commands/man_command.rb +409 -0
- data/lib/mtncloud/cli/commands/migrations.rb +453 -0
- data/lib/mtncloud/cli/commands/monitoring_alerts_command.rb +791 -0
- data/lib/mtncloud/cli/commands/monitoring_apps_command.rb +716 -0
- data/lib/mtncloud/cli/commands/monitoring_checks_command.rb +766 -0
- data/lib/mtncloud/cli/commands/monitoring_contacts_command.rb +339 -0
- data/lib/mtncloud/cli/commands/monitoring_groups_command.rb +674 -0
- data/lib/mtncloud/cli/commands/monitoring_incidents_command.rb +835 -0
- data/lib/mtncloud/cli/commands/monitoring_settings.rb +212 -0
- data/lib/mtncloud/cli/commands/network_dhcp_relays_command.rb +375 -0
- data/lib/mtncloud/cli/commands/network_dhcp_servers_command.rb +366 -0
- data/lib/mtncloud/cli/commands/network_domains_command.rb +896 -0
- data/lib/mtncloud/cli/commands/network_edge_clusters_command.rb +288 -0
- data/lib/mtncloud/cli/commands/network_firewalls_command.rb +783 -0
- data/lib/mtncloud/cli/commands/network_floating_ips.rb +147 -0
- data/lib/mtncloud/cli/commands/network_groups_command.rb +654 -0
- data/lib/mtncloud/cli/commands/network_pool_server_types.rb +20 -0
- data/lib/mtncloud/cli/commands/network_pool_servers_command.rb +318 -0
- data/lib/mtncloud/cli/commands/network_pools_command.rb +903 -0
- data/lib/mtncloud/cli/commands/network_proxies_command.rb +578 -0
- data/lib/mtncloud/cli/commands/network_routers_command.rb +2628 -0
- data/lib/mtncloud/cli/commands/network_security_server_types.rb +20 -0
- data/lib/mtncloud/cli/commands/network_server_groups_command.rb +222 -0
- data/lib/mtncloud/cli/commands/network_server_types_command.rb +20 -0
- data/lib/mtncloud/cli/commands/network_servers_command.rb +398 -0
- data/lib/mtncloud/cli/commands/network_services_command.rb +198 -0
- data/lib/mtncloud/cli/commands/network_static_routes_command.rb +451 -0
- data/lib/mtncloud/cli/commands/network_transport_zones_command.rb +412 -0
- data/lib/mtncloud/cli/commands/networks_command.rb +1692 -0
- data/lib/mtncloud/cli/commands/open_command.rb +30 -0
- data/lib/mtncloud/cli/commands/options.rb +231 -0
- data/lib/mtncloud/cli/commands/packages_command.rb +822 -0
- data/lib/mtncloud/cli/commands/ping.rb +242 -0
- data/lib/mtncloud/cli/commands/plugins.rb +214 -0
- data/lib/mtncloud/cli/commands/policies_command.rb +990 -0
- data/lib/mtncloud/cli/commands/power_schedules_command.rb +731 -0
- data/lib/mtncloud/cli/commands/preseed_scripts_command.rb +378 -0
- data/lib/mtncloud/cli/commands/price_sets_command.rb +557 -0
- data/lib/mtncloud/cli/commands/prices_command.rb +692 -0
- data/lib/mtncloud/cli/commands/processes_command.rb +469 -0
- data/lib/mtncloud/cli/commands/projects_command.rb +537 -0
- data/lib/mtncloud/cli/commands/provisioning_licenses_command.rb +509 -0
- data/lib/mtncloud/cli/commands/provisioning_settings_command.rb +238 -0
- data/lib/mtncloud/cli/commands/recent_activity_command.rb +171 -0
- data/lib/mtncloud/cli/commands/remote.rb +1818 -0
- data/lib/mtncloud/cli/commands/reports_command.rb +724 -0
- data/lib/mtncloud/cli/commands/resource_pool_groups_command.rb +586 -0
- data/lib/mtncloud/cli/commands/rm_command.rb +14 -0
- data/lib/mtncloud/cli/commands/roles.rb +3120 -0
- data/lib/mtncloud/cli/commands/scale_thresholds.rb +103 -0
- data/lib/mtncloud/cli/commands/search_command.rb +184 -0
- data/lib/mtncloud/cli/commands/security_group_rules.rb +230 -0
- data/lib/mtncloud/cli/commands/security_groups.rb +1294 -0
- data/lib/mtncloud/cli/commands/security_package_types.rb +32 -0
- data/lib/mtncloud/cli/commands/security_packages.rb +84 -0
- data/lib/mtncloud/cli/commands/security_scans.rb +107 -0
- data/lib/mtncloud/cli/commands/self_service_command.rb +17 -0
- data/lib/mtncloud/cli/commands/server_devices_command.rb +207 -0
- data/lib/mtncloud/cli/commands/service_catalog_command.rb +1528 -0
- data/lib/mtncloud/cli/commands/service_plans_command.rb +895 -0
- data/lib/mtncloud/cli/commands/set_prompt_command.rb +51 -0
- data/lib/mtncloud/cli/commands/setup.rb +423 -0
- data/lib/mtncloud/cli/commands/shell.rb +717 -0
- data/lib/mtncloud/cli/commands/sleep_command.rb +43 -0
- data/lib/mtncloud/cli/commands/snapshots.rb +156 -0
- data/lib/mtncloud/cli/commands/source_command.rb +30 -0
- data/lib/mtncloud/cli/commands/ssl_verification_command.rb +47 -0
- data/lib/mtncloud/cli/commands/storage_datastores.rb +457 -0
- data/lib/mtncloud/cli/commands/storage_providers_command.rb +1401 -0
- data/lib/mtncloud/cli/commands/storage_server_types.rb +45 -0
- data/lib/mtncloud/cli/commands/storage_servers.rb +116 -0
- data/lib/mtncloud/cli/commands/storage_volume_types.rb +45 -0
- data/lib/mtncloud/cli/commands/storage_volumes.rb +236 -0
- data/lib/mtncloud/cli/commands/subnets_command.rb +819 -0
- data/lib/mtncloud/cli/commands/support_bundles_command.rb +606 -0
- data/lib/mtncloud/cli/commands/systems.rb +1203 -0
- data/lib/mtncloud/cli/commands/tasks.rb +1391 -0
- data/lib/mtncloud/cli/commands/tee_command.rb +14 -0
- data/lib/mtncloud/cli/commands/tenants_command.rb +315 -0
- data/lib/mtncloud/cli/commands/tokens_command.rb +391 -0
- data/lib/mtncloud/cli/commands/update_command.rb +46 -0
- data/lib/mtncloud/cli/commands/usage_command.rb +203 -0
- data/lib/mtncloud/cli/commands/user_groups_command.rb +512 -0
- data/lib/mtncloud/cli/commands/user_settings_command.rb +849 -0
- data/lib/mtncloud/cli/commands/user_sources_command.rb +1065 -0
- data/lib/mtncloud/cli/commands/users.rb +897 -0
- data/lib/mtncloud/cli/commands/vdi_allocations_command.rb +159 -0
- data/lib/mtncloud/cli/commands/vdi_apps_command.rb +317 -0
- data/lib/mtncloud/cli/commands/vdi_command.rb +359 -0
- data/lib/mtncloud/cli/commands/vdi_gateways_command.rb +290 -0
- data/lib/mtncloud/cli/commands/vdi_pools_command.rb +574 -0
- data/lib/mtncloud/cli/commands/version_command.rb +38 -0
- data/lib/mtncloud/cli/commands/view.rb +107 -0
- data/lib/mtncloud/cli/commands/virtual_images.rb +1362 -0
- data/lib/mtncloud/cli/commands/virtual_switches_command.rb +336 -0
- data/lib/mtncloud/cli/commands/whitelabel_settings_command.rb +653 -0
- data/lib/mtncloud/cli/commands/whoami.rb +323 -0
- data/lib/mtncloud/cli/commands/wiki_command.rb +448 -0
- data/lib/mtncloud/cli/commands/workflows.rb +1022 -0
- data/lib/mtncloud/cli/credentials.rb +482 -0
- data/lib/mtncloud/cli/dot_file.rb +180 -0
- data/lib/mtncloud/cli/error_handler.rb +307 -0
- data/lib/mtncloud/cli/errors.rb +53 -0
- data/lib/mtncloud/cli/expression_parser.rb +153 -0
- data/lib/mtncloud/cli/mixins/accounts_helper.rb +484 -0
- data/lib/mtncloud/cli/mixins/affinity_helper.rb +118 -0
- data/lib/mtncloud/cli/mixins/backups_helper.rb +200 -0
- data/lib/mtncloud/cli/mixins/deployments_helper.rb +163 -0
- data/lib/mtncloud/cli/mixins/execution_request_helper.rb +50 -0
- data/lib/mtncloud/cli/mixins/infrastructure_helper.rb +966 -0
- data/lib/mtncloud/cli/mixins/jobs_helper.rb +202 -0
- data/lib/mtncloud/cli/mixins/library_helper.rb +539 -0
- data/lib/mtncloud/cli/mixins/load_balancers_helper.rb +176 -0
- data/lib/mtncloud/cli/mixins/logs_helper.rb +131 -0
- data/lib/mtncloud/cli/mixins/monitoring_helper.rb +876 -0
- data/lib/mtncloud/cli/mixins/networks_helper.rb +62 -0
- data/lib/mtncloud/cli/mixins/operations_helper.rb +41 -0
- data/lib/mtncloud/cli/mixins/option_source_helper.rb +254 -0
- data/lib/mtncloud/cli/mixins/print_helper.rb +1631 -0
- data/lib/mtncloud/cli/mixins/processes_helper.rb +286 -0
- data/lib/mtncloud/cli/mixins/prompt_helper.rb +136 -0
- data/lib/mtncloud/cli/mixins/provisioning_helper.rb +2963 -0
- data/lib/mtncloud/cli/mixins/remote_helper.rb +139 -0
- data/lib/mtncloud/cli/mixins/rest_command.rb +994 -0
- data/lib/mtncloud/cli/mixins/secondary_rest_command.rb +700 -0
- data/lib/mtncloud/cli/mixins/storage_servers_helper.rb +93 -0
- data/lib/mtncloud/cli/mixins/storage_volumes_helper.rb +76 -0
- data/lib/mtncloud/cli/mixins/vdi_helper.rb +246 -0
- data/lib/mtncloud/cli/mixins/whoami_helper.rb +73 -0
- data/lib/mtncloud/cli/option_parser.rb +127 -0
- data/lib/mtncloud/cli/option_types.rb +1622 -0
- data/lib/mtncloud/cli/version.rb +6 -0
- data/lib/mtncloud/cli.rb +105 -0
- data/lib/mtncloud/currency.rb +184 -0
- data/lib/mtncloud/ext/hash.rb +109 -0
- data/lib/mtncloud/ext/nil_class.rb +5 -0
- data/lib/mtncloud/ext/rest_client.rb +37 -0
- data/lib/mtncloud/ext/string.rb +66 -0
- data/lib/mtncloud/formatters.rb +511 -0
- data/lib/mtncloud/logging.rb +185 -0
- data/lib/mtncloud/morpkg.rb +119 -0
- data/lib/mtncloud/rest_client.rb +104 -0
- data/lib/mtncloud/routes.rb +304 -0
- data/lib/mtncloud/terminal.rb +528 -0
- data/lib/mtncloud/util.rb +29 -0
- data/lib/mtncloud.rb +5 -0
- data/mtncloud-cli.gemspec +38 -0
- data/test/api/affinity_groups_interface_test.rb +43 -0
- data/test/api/clients_interface_test.rb +23 -0
- data/test/api/clouds_interface_test.rb +67 -0
- data/test/api/containers_interface_test.rb +68 -0
- data/test/api/host_vm_groups_interface_test.rb +35 -0
- data/test/api/instances_interface_test.rb +22 -0
- data/test/api/network_routers_interface_test.rb +22 -0
- data/test/api/systems_interface_test.rb +26 -0
- data/test/api/whoami_interface_test.rb +14 -0
- data/test/branding_test.rb +160 -0
- data/test/cli/access_token_test.rb +36 -0
- data/test/cli/affinity_groups_cloud_cluster_scope_test.rb +270 -0
- data/test/cli/affinity_groups_cluster_scope_test.rb +171 -0
- data/test/cli/affinity_groups_test.rb +57 -0
- data/test/cli/affinity_groups_violations_scope_test.rb +141 -0
- data/test/cli/affinity_helper_test.rb +367 -0
- data/test/cli/auth_test.rb +88 -0
- data/test/cli/backups_test.rb +212 -0
- data/test/cli/cli_test.rb +48 -0
- data/test/cli/clients_test.rb +45 -0
- data/test/cli/clusters_uuid_test.rb +146 -0
- data/test/cli/containers_test.rb +92 -0
- data/test/cli/distributed_workers_test.rb +68 -0
- data/test/cli/help_test.rb +25 -0
- data/test/cli/host_vm_groups_cluster_scope_test.rb +187 -0
- data/test/cli/host_vm_groups_test.rb +63 -0
- data/test/cli/infrastructure_helper_cluster_resolver_test.rb +250 -0
- data/test/cli/instances_test.rb +37 -0
- data/test/cli/man_test.rb +14 -0
- data/test/cli/migrations_test.rb +39 -0
- data/test/cli/network_routers_test.rb +65 -0
- data/test/cli/remote_test.rb +89 -0
- data/test/cli/roles_test.rb +47 -0
- data/test/cli/shell_test.rb +81 -0
- data/test/cli/storage_volumes_test.rb +79 -0
- data/test/cli/systems_test.rb +206 -0
- data/test/cli/version_test.rb +23 -0
- data/test/cli/view_test.rb +55 -0
- data/test/cli/whoami_test.rb +17 -0
- data/test/mtncloud_test.rb +16 -0
- data/test/test_case.rb +342 -0
- data/test/test_config.rb +137 -0
- data/test/test_data_helper.rb +97 -0
- metadata +807 -0
|
@@ -0,0 +1,1631 @@
|
|
|
1
|
+
require 'uri'
|
|
2
|
+
require 'term/ansicolor'
|
|
3
|
+
require 'json'
|
|
4
|
+
require 'yaml'
|
|
5
|
+
require 'ostruct'
|
|
6
|
+
require 'io/console'
|
|
7
|
+
require 'mtncloud/logging'
|
|
8
|
+
require 'fileutils'
|
|
9
|
+
require 'filesize'
|
|
10
|
+
|
|
11
|
+
module MtnCloud::Cli::PrintHelper
|
|
12
|
+
|
|
13
|
+
def self.included(klass)
|
|
14
|
+
klass.send :include, Term::ANSIColor
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def self.terminal_width
|
|
18
|
+
@@terminal_width ||= 80
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def self.terminal_width=(v)
|
|
22
|
+
if v.nil? || v.to_i == 0
|
|
23
|
+
@@terminal_width = nil
|
|
24
|
+
else
|
|
25
|
+
@@terminal_width = v.to_i
|
|
26
|
+
end
|
|
27
|
+
@@terminal_width
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# for consistancy, maybe..
|
|
31
|
+
unless defined?(ALL_LABELS_UPCASE)
|
|
32
|
+
ALL_LABELS_UPCASE = false
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def current_terminal_width
|
|
36
|
+
return IO.console.winsize[1] rescue 0
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# puts red message to stderr
|
|
40
|
+
# why this not stderr yet? use print_error or if respond_to?(:my_terminal)
|
|
41
|
+
def print_red_alert(msg)
|
|
42
|
+
$stderr.print "#{red}#{msg}#{reset}\n"
|
|
43
|
+
#print_error "#{red}#{msg}#{reset}\n"
|
|
44
|
+
#puts_error "#{red}#{msg}#{reset}"
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# puts green message to stdout
|
|
48
|
+
def print_green_success(msg=nil)
|
|
49
|
+
if msg.nil?
|
|
50
|
+
msg = "success"
|
|
51
|
+
end
|
|
52
|
+
print "#{green}#{msg}#{reset}\n"
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# print_h1 prints a header title and optional subtitles
|
|
56
|
+
# Output:
|
|
57
|
+
#
|
|
58
|
+
# title - subtitle1, subtitle2
|
|
59
|
+
# ==================
|
|
60
|
+
#
|
|
61
|
+
def print_h1(title, subtitles=nil, options=nil, suffix_content="\n")
|
|
62
|
+
# ok, support all these formats for now:
|
|
63
|
+
# print_h1(title, options={})
|
|
64
|
+
# print_h1(title, subtitles, options={})
|
|
65
|
+
# this can go away when we have a dirty @current_options
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
# auto include remote name in h1 titles
|
|
69
|
+
# eg. MTN Cloud Instances [dev]
|
|
70
|
+
# if title && @appliance_name
|
|
71
|
+
# title = "#{title} [#{@appliance_name}]"
|
|
72
|
+
# end
|
|
73
|
+
|
|
74
|
+
if subtitles.is_a?(Hash)
|
|
75
|
+
options = subtitles
|
|
76
|
+
subtitles = (options[:subtitles] || []).flatten
|
|
77
|
+
end
|
|
78
|
+
if subtitles.is_a?(String)
|
|
79
|
+
subtitles = [subtitles]
|
|
80
|
+
end
|
|
81
|
+
subtitles = (subtitles || []).flatten
|
|
82
|
+
options ||= {}
|
|
83
|
+
color = options[:color] || cyan
|
|
84
|
+
out = ""
|
|
85
|
+
out << "\n"
|
|
86
|
+
out << "#{color}#{bold}#{title}#{reset}"
|
|
87
|
+
if !subtitles.empty?
|
|
88
|
+
out << "#{color} | #{subtitles.join(', ')}#{reset}"
|
|
89
|
+
end
|
|
90
|
+
out << "\n"
|
|
91
|
+
if options[:border_style] == :thin
|
|
92
|
+
|
|
93
|
+
else
|
|
94
|
+
out << "#{color}#{bold}==================#{reset}\n"
|
|
95
|
+
end
|
|
96
|
+
# Default suffix_content is typically one extra newline
|
|
97
|
+
if !suffix_content.to_s.empty?
|
|
98
|
+
out << suffix_content.to_s
|
|
99
|
+
end
|
|
100
|
+
print out
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def print_h2(title, subtitles=nil, options=nil, suffix_content="\n")
|
|
104
|
+
# ok, support all these formats for now:
|
|
105
|
+
# print_h2(title={})
|
|
106
|
+
# print_h2(title, options={})
|
|
107
|
+
# print_h2(title, subtitles, options={})
|
|
108
|
+
# this can go away when we have a dirty @current_options
|
|
109
|
+
if subtitles.is_a?(Hash)
|
|
110
|
+
options = subtitles
|
|
111
|
+
subtitles = (options[:subtitles] || []).flatten
|
|
112
|
+
end
|
|
113
|
+
subtitles = (subtitles || []).flatten
|
|
114
|
+
options ||= {}
|
|
115
|
+
color = options[:color] || cyan
|
|
116
|
+
out = ""
|
|
117
|
+
out << "\n"
|
|
118
|
+
out << "#{color}#{bold}#{title}#{reset}"
|
|
119
|
+
if !subtitles.empty?
|
|
120
|
+
out << "#{color} - #{subtitles.join(', ')}#{reset}"
|
|
121
|
+
end
|
|
122
|
+
out << "\n"
|
|
123
|
+
if options[:border_style] == :thin
|
|
124
|
+
|
|
125
|
+
else
|
|
126
|
+
out << "#{color}---------------------#{reset}\n"
|
|
127
|
+
end
|
|
128
|
+
# Default suffix_content is typically one extra newline
|
|
129
|
+
if !suffix_content.to_s.empty?
|
|
130
|
+
out << suffix_content.to_s
|
|
131
|
+
end
|
|
132
|
+
print out
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def print_rest_exception(e, options={})
|
|
136
|
+
if respond_to?(:my_terminal)
|
|
137
|
+
MtnCloud::Cli::ErrorHandler.new(my_terminal.stderr).print_rest_exception(e, options)
|
|
138
|
+
else
|
|
139
|
+
MtnCloud::Cli::ErrorHandler.new.print_rest_exception(e, options)
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def print_rest_errors(errors, options={})
|
|
144
|
+
if respond_to?(:my_terminal)
|
|
145
|
+
MtnCloud::Cli::ErrorHandler.new(my_terminal.stderr).print_rest_errors(errors, options)
|
|
146
|
+
else
|
|
147
|
+
MtnCloud::Cli::ErrorHandler.new.print_rest_errors(errors, options)
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def parse_rest_exception(e, options={})
|
|
152
|
+
data = {}
|
|
153
|
+
begin
|
|
154
|
+
data = JSON.parse(e.response.to_s)
|
|
155
|
+
rescue
|
|
156
|
+
# MtnCloud::Logging::DarkPrinter.puts "Failed to parse error response as JSON: #{ex}" if MtnCloud::Logging.debug?
|
|
157
|
+
end
|
|
158
|
+
return data
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def print_dry_run(api_request, options={})
|
|
162
|
+
# 2nd argument used to be command_string (String)
|
|
163
|
+
command_string = nil
|
|
164
|
+
if options.is_a?(String)
|
|
165
|
+
command_string = options
|
|
166
|
+
options = {}
|
|
167
|
+
end
|
|
168
|
+
options ||= {}
|
|
169
|
+
# api client injects common command options here
|
|
170
|
+
if api_request[:command_options]
|
|
171
|
+
options = options.merge(api_request[:command_options])
|
|
172
|
+
end
|
|
173
|
+
options ||= {}
|
|
174
|
+
# parse params request arguments
|
|
175
|
+
http_method = api_request[:method]
|
|
176
|
+
url = api_request[:url]
|
|
177
|
+
headers = api_request[:headers]
|
|
178
|
+
params = nil
|
|
179
|
+
if api_request[:params] && !api_request[:params].empty?
|
|
180
|
+
params = api_request[:params]
|
|
181
|
+
elsif headers && headers[:params]
|
|
182
|
+
# params inside headers for restclient reasons..
|
|
183
|
+
params = headers[:params]
|
|
184
|
+
elsif api_request[:query] && !api_request[:query].empty?
|
|
185
|
+
params = api_request[:query]
|
|
186
|
+
end
|
|
187
|
+
query_string = params
|
|
188
|
+
if query_string.respond_to?(:map)
|
|
189
|
+
query_string = URI.encode_www_form(query_string)
|
|
190
|
+
end
|
|
191
|
+
if query_string && !query_string.empty?
|
|
192
|
+
url = "#{url}?#{query_string}"
|
|
193
|
+
end
|
|
194
|
+
request_string = "#{http_method.to_s.upcase} #{url}".strip
|
|
195
|
+
payload = api_request[:payload] || api_request[:body]
|
|
196
|
+
#MtnCloud::Logging::DarkPrinter.puts "API payload is: (#{payload.class}) #{payload.inspect}"
|
|
197
|
+
content_type = (headers && headers['Content-Type']) ? headers['Content-Type'] : 'application/x-www-form-urlencoded'
|
|
198
|
+
# build output, either CURL or REQUEST
|
|
199
|
+
output = ""
|
|
200
|
+
if api_request[:curl] || options[:curl]
|
|
201
|
+
output = format_curl_command(http_method, url, headers, payload, options)
|
|
202
|
+
elsif options[:json]
|
|
203
|
+
# --dry --json should print the payload only
|
|
204
|
+
payload_object = payload.is_a?(String) ? JSON.parse(payload) : payload
|
|
205
|
+
output = as_json(payload_object, options)
|
|
206
|
+
elsif options[:yaml]
|
|
207
|
+
# --dry --yaml should print the payload only as yaml
|
|
208
|
+
payload_object = payload.is_a?(String) ? JSON.parse(payload) : payload
|
|
209
|
+
output = as_yaml(payload_object, options)
|
|
210
|
+
else
|
|
211
|
+
# default format is
|
|
212
|
+
# DRY RUN
|
|
213
|
+
# REQUEST
|
|
214
|
+
# GET https://server/api/things
|
|
215
|
+
#
|
|
216
|
+
# JSON
|
|
217
|
+
# {
|
|
218
|
+
# "thing": { ... }
|
|
219
|
+
# }
|
|
220
|
+
output = format_api_request(http_method, url, headers, payload, options)
|
|
221
|
+
end
|
|
222
|
+
# this is an extra scrub, should remove
|
|
223
|
+
if options[:scrub]
|
|
224
|
+
output = MtnCloud::Logging.scrub_message(output)
|
|
225
|
+
end
|
|
226
|
+
# write to a file?
|
|
227
|
+
if options[:outfile]
|
|
228
|
+
print_result = print_to_file(output, options[:outfile], options[:overwrite])
|
|
229
|
+
# with_stdout_to_file(options[:outfile], options[:overwrite]) { print output }
|
|
230
|
+
print "#{cyan}Wrote output to file #{options[:outfile]} (#{format_bytes(File.size(options[:outfile]))})\n" unless options[:quiet]
|
|
231
|
+
#return print_result
|
|
232
|
+
return
|
|
233
|
+
end
|
|
234
|
+
# print output
|
|
235
|
+
if api_request[:curl] || options[:curl]
|
|
236
|
+
print "\n"
|
|
237
|
+
print "#{cyan}#{bold}#{dark}CURL COMMAND#{reset}\n"
|
|
238
|
+
print output
|
|
239
|
+
print reset, "\n"
|
|
240
|
+
print reset
|
|
241
|
+
elsif options[:json] || options[:yaml]
|
|
242
|
+
# print just the just payload
|
|
243
|
+
print output, "\n"
|
|
244
|
+
else
|
|
245
|
+
print "\n"
|
|
246
|
+
print "#{cyan}#{bold}#{dark}REQUEST#{reset}\n"
|
|
247
|
+
print output
|
|
248
|
+
print reset, "\n"
|
|
249
|
+
print reset
|
|
250
|
+
end
|
|
251
|
+
return output
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
def print_system_command_dry_run(cmd, options={})
|
|
255
|
+
print "\n"
|
|
256
|
+
print "#{cyan}#{bold}#{dark}SYSTEM COMMAND#{reset}\n"
|
|
257
|
+
print cmd
|
|
258
|
+
print reset, "\n"
|
|
259
|
+
return
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
def format_api_request(http_method, url, headers, payload=nil, options={})
|
|
263
|
+
out = ""
|
|
264
|
+
# out << "\n"
|
|
265
|
+
# out << "#{cyan}#{bold}#{dark}REQUEST#{reset}\n"
|
|
266
|
+
request_string = "#{http_method.to_s.upcase} #{url}".strip
|
|
267
|
+
out << request_string + "\n"
|
|
268
|
+
out << cyan
|
|
269
|
+
if payload
|
|
270
|
+
out << "\n"
|
|
271
|
+
is_multipart = (payload.is_a?(Hash) && payload[:multipart] == true)
|
|
272
|
+
content_type = (headers && headers['Content-Type']) ? headers['Content-Type'] : (is_multipart ? 'multipart/form-data' : 'application/x-www-form-urlencoded')
|
|
273
|
+
if content_type == 'application/json'
|
|
274
|
+
if payload.is_a?(String)
|
|
275
|
+
begin
|
|
276
|
+
payload = JSON.parse(payload)
|
|
277
|
+
rescue => e
|
|
278
|
+
#payload = "(unparsable) #{payload}"
|
|
279
|
+
end
|
|
280
|
+
end
|
|
281
|
+
out << "#{cyan}#{bold}#{dark}JSON#{reset}\n"
|
|
282
|
+
if options[:scrub]
|
|
283
|
+
out << MtnCloud::Logging.scrub_message(JSON.pretty_generate(payload))
|
|
284
|
+
else
|
|
285
|
+
out << JSON.pretty_generate(payload)
|
|
286
|
+
end
|
|
287
|
+
else
|
|
288
|
+
out << "Content-Type: #{content_type}" + "\n"
|
|
289
|
+
out << reset
|
|
290
|
+
if payload.is_a?(File)
|
|
291
|
+
#pretty_size = "#{payload.size} B"
|
|
292
|
+
pretty_size = format_bytes(payload.size)
|
|
293
|
+
out << "File: #{payload.path} (#{pretty_size})"
|
|
294
|
+
elsif payload.is_a?(String)
|
|
295
|
+
if options[:scrub]
|
|
296
|
+
out << MtnCloud::Logging.scrub_message(payload)
|
|
297
|
+
else
|
|
298
|
+
out << payload
|
|
299
|
+
end
|
|
300
|
+
else
|
|
301
|
+
if content_type == 'application/x-www-form-urlencoded' || content_type.to_s.include?('multipart')
|
|
302
|
+
body_str = payload.to_s
|
|
303
|
+
begin
|
|
304
|
+
payload.delete(:multipart) if payload.is_a?(Hash)
|
|
305
|
+
# puts "grailsifying it!"
|
|
306
|
+
payload = MtnCloud::RestClient.grails_params(payload)
|
|
307
|
+
payload.each do |k,v|
|
|
308
|
+
if v.is_a?(File)
|
|
309
|
+
payload[k] = "@#{v.path}"
|
|
310
|
+
payload[k] = v.path
|
|
311
|
+
end
|
|
312
|
+
end
|
|
313
|
+
body_str = URI.encode_www_form(payload)
|
|
314
|
+
rescue => ex
|
|
315
|
+
raise ex
|
|
316
|
+
end
|
|
317
|
+
if options[:scrub]
|
|
318
|
+
out << MtnCloud::Logging.scrub_message(body_str)
|
|
319
|
+
else
|
|
320
|
+
out << body_str
|
|
321
|
+
end
|
|
322
|
+
else
|
|
323
|
+
if options[:scrub]
|
|
324
|
+
out << MtnCloud::Logging.scrub_message(payload)
|
|
325
|
+
else
|
|
326
|
+
out << payload.to_s
|
|
327
|
+
end
|
|
328
|
+
end
|
|
329
|
+
end
|
|
330
|
+
end
|
|
331
|
+
out << "\n"
|
|
332
|
+
end
|
|
333
|
+
# out << "\n"
|
|
334
|
+
out << reset
|
|
335
|
+
return out
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
# format_curl_command generates a valid curl command for the given api request
|
|
339
|
+
# @param api_request [Hash] api request, typically returned from api_client.dry.execute()
|
|
340
|
+
# @param options [Hash] common cli options
|
|
341
|
+
# formats command like:
|
|
342
|
+
#
|
|
343
|
+
# curl -XPOST "https://api.gomorpheus.com/api/cypher" \
|
|
344
|
+
# -H "Authorization: BEARER ******************" \
|
|
345
|
+
# -H "Content-Type: application/json" \
|
|
346
|
+
# -d '{
|
|
347
|
+
# "value": "mysecret"
|
|
348
|
+
# }'
|
|
349
|
+
def format_curl_command(http_method, url, headers, payload=nil, options={})
|
|
350
|
+
options ||= {}
|
|
351
|
+
# build curl [options]
|
|
352
|
+
out = ""
|
|
353
|
+
out << "curl -X#{http_method.to_s.upcase} \"#{url}\""
|
|
354
|
+
if headers
|
|
355
|
+
headers.each do |k,v|
|
|
356
|
+
# avoid weird [:headers][:params]
|
|
357
|
+
unless k == :params
|
|
358
|
+
header_value = v
|
|
359
|
+
out << ' \\' + "\n"
|
|
360
|
+
header_line = " -H \"#{k.is_a?(Symbol) ? k.to_s.capitalize : k.to_s}: #{v}\""
|
|
361
|
+
out << header_line
|
|
362
|
+
end
|
|
363
|
+
end
|
|
364
|
+
end
|
|
365
|
+
if payload #&& !payload.empty?
|
|
366
|
+
out << + ' \\' + "\n"
|
|
367
|
+
if headers && headers['Content-Type'] == 'application/json'
|
|
368
|
+
if payload.is_a?(String)
|
|
369
|
+
begin
|
|
370
|
+
payload = JSON.parse(payload)
|
|
371
|
+
rescue => e
|
|
372
|
+
#payload = "(unparsable) #{payload}"
|
|
373
|
+
end
|
|
374
|
+
end
|
|
375
|
+
if payload.is_a?(Hash)
|
|
376
|
+
out << " -d '#{as_json(payload, options)}'"
|
|
377
|
+
else
|
|
378
|
+
out << " -d '#{payload}'"
|
|
379
|
+
end
|
|
380
|
+
out << "\n"
|
|
381
|
+
else
|
|
382
|
+
is_multipart = (payload.is_a?(Hash) && payload[:multipart] == true)
|
|
383
|
+
content_type = headers['Content-Type'] || 'application/x-www-form-urlencoded'
|
|
384
|
+
|
|
385
|
+
if payload.is_a?(File)
|
|
386
|
+
# pretty_size = Filesize.from("#{payload.size} B").pretty.strip
|
|
387
|
+
pretty_size = "#{payload.size} B"
|
|
388
|
+
# print "File: #{payload.path} (#{payload.size} bytes)"
|
|
389
|
+
out << " --data-binary @#{payload.path}"
|
|
390
|
+
elsif payload.is_a?(String)
|
|
391
|
+
out << " -d '#{payload}'"
|
|
392
|
+
elsif payload.respond_to?(:map)
|
|
393
|
+
payload.delete(:multipart) if payload.is_a?(Hash)
|
|
394
|
+
# puts "grailsifying it!"
|
|
395
|
+
payload = MtnCloud::RestClient.grails_params(payload)
|
|
396
|
+
payload.each do |k,v|
|
|
397
|
+
if v.is_a?(File)
|
|
398
|
+
out << " -F '#{k}=@#{v.path}"
|
|
399
|
+
else
|
|
400
|
+
out << " -d '#{URI.encode_www_form({(k) => v})}'"
|
|
401
|
+
end
|
|
402
|
+
out << "\n"
|
|
403
|
+
end
|
|
404
|
+
#body_str = URI.encode_www_form(payload)
|
|
405
|
+
# out << " -d '#{body_str}'"
|
|
406
|
+
end
|
|
407
|
+
end
|
|
408
|
+
else
|
|
409
|
+
out << "\n"
|
|
410
|
+
end
|
|
411
|
+
if options[:scrub]
|
|
412
|
+
out = MtnCloud::Logging.scrub_message(out)
|
|
413
|
+
end
|
|
414
|
+
return out
|
|
415
|
+
|
|
416
|
+
end
|
|
417
|
+
def print_results_pagination(json_response, options={})
|
|
418
|
+
# print cyan,"\nViewing #{json_response['meta']['offset'].to_i + 1}-#{json_response['meta']['offset'].to_i + json_response['meta']['size'].to_i} of #{json_response['meta']['total']}\n", reset
|
|
419
|
+
print format_results_pagination(json_response, options)
|
|
420
|
+
end
|
|
421
|
+
|
|
422
|
+
def format_results_pagination(json_response, options={})
|
|
423
|
+
# no output for strange, empty data
|
|
424
|
+
if json_response.nil? || json_response.empty?
|
|
425
|
+
return ""
|
|
426
|
+
end
|
|
427
|
+
color = options.key?(:color) ? options[:color] : cyan
|
|
428
|
+
label = options[:label]
|
|
429
|
+
n_label = options[:n_label] || (label ? label.to_s.pluralize : nil)
|
|
430
|
+
message = options[:message] || "Viewing %{start_index}-%{end_index} of %{total} %{label}"
|
|
431
|
+
blank_message = options[:blank_message] || nil # "No %{label} found"
|
|
432
|
+
|
|
433
|
+
# support lazy passing of common list json_response {"meta": {"size": 25, "total": 56} }
|
|
434
|
+
# priority is:
|
|
435
|
+
# 1. "meta" that api response contains for list endpoints
|
|
436
|
+
# 2. "total" and "size" values if passed explicitely by the cli (pretty sure symbols are no longer used)
|
|
437
|
+
# 3. examine the first array found in the response
|
|
438
|
+
meta = nil
|
|
439
|
+
records = nil
|
|
440
|
+
# assume records is the first array in the response
|
|
441
|
+
records_key = json_response.keys.find { |k| json_response[k].is_a?(Array) }
|
|
442
|
+
if records_key
|
|
443
|
+
records = json_response[records_key]
|
|
444
|
+
meta = {'offset' => 0, 'size' => records.size, 'total' => records.size}
|
|
445
|
+
end
|
|
446
|
+
if json_response[:meta] || json_response["meta"]
|
|
447
|
+
meta = json_response[:meta] || json_response["meta"]
|
|
448
|
+
elsif json_response.key?('size') || json_response.key?('total')
|
|
449
|
+
meta = json_response
|
|
450
|
+
elsif json_response.key?(:size) || json_response.key?(:total)
|
|
451
|
+
meta = {'size' => json_response[:size], 'total' => json_response[:total], 'offset' => json_response[:offset]}
|
|
452
|
+
elsif records
|
|
453
|
+
# just use the first key in the response
|
|
454
|
+
meta = {'size' => records.size, 'total' => records.size}
|
|
455
|
+
end
|
|
456
|
+
# did not find pagination meta info?
|
|
457
|
+
if meta.nil?
|
|
458
|
+
return ""
|
|
459
|
+
end
|
|
460
|
+
# api should not need to return the size, just use records.size
|
|
461
|
+
if meta["size"].nil? && records
|
|
462
|
+
meta["size"] = records.size
|
|
463
|
+
end
|
|
464
|
+
offset = meta['offset'].to_i
|
|
465
|
+
size = meta['size'].to_i
|
|
466
|
+
total = meta['total'].to_i
|
|
467
|
+
# perhaps no total count returned, let total be equal to size of list
|
|
468
|
+
if total == 0 && size > 0
|
|
469
|
+
total = size
|
|
470
|
+
end
|
|
471
|
+
# plural label?
|
|
472
|
+
if total != 1
|
|
473
|
+
label = n_label
|
|
474
|
+
end
|
|
475
|
+
out_str = ""
|
|
476
|
+
string_key_values = {start_index: format_number(offset + 1), end_index: format_number(offset + size),
|
|
477
|
+
total: format_number(total), size: format_number(size), offset: format_number(offset), label: label}
|
|
478
|
+
if size > 0
|
|
479
|
+
if message
|
|
480
|
+
out_str << message % string_key_values
|
|
481
|
+
end
|
|
482
|
+
else
|
|
483
|
+
if blank_message
|
|
484
|
+
out_str << blank_message % string_key_values
|
|
485
|
+
else
|
|
486
|
+
#out << "No records"
|
|
487
|
+
end
|
|
488
|
+
end
|
|
489
|
+
out = ""
|
|
490
|
+
out << "\n"
|
|
491
|
+
out << color if color
|
|
492
|
+
out << out_str.strip
|
|
493
|
+
out << reset if color
|
|
494
|
+
out << "\n"
|
|
495
|
+
out
|
|
496
|
+
end
|
|
497
|
+
|
|
498
|
+
def required_blue_prompt
|
|
499
|
+
"#{cyan}|#{reset}"
|
|
500
|
+
end
|
|
501
|
+
|
|
502
|
+
|
|
503
|
+
# shows cyan, yellow, red progress bar where 50% looks like [||||| ]
|
|
504
|
+
# todo: render units used / available here too maybe
|
|
505
|
+
def generate_usage_bar(used_value, max_value, opts={})
|
|
506
|
+
opts[:bar_color] ||= :rainbow # :rainbow, :solid, or a color eg. cyan
|
|
507
|
+
max_bars = opts[:max_bars] || 50
|
|
508
|
+
out = ""
|
|
509
|
+
bars = []
|
|
510
|
+
percent = 0
|
|
511
|
+
percent_sigdig = opts[:percent_sigdig] || 2
|
|
512
|
+
if max_value.nil?
|
|
513
|
+
percent = 0
|
|
514
|
+
elsif max_value == 0
|
|
515
|
+
percent = used_value.to_f == 0 ? 0 : 100
|
|
516
|
+
else
|
|
517
|
+
percent = ((used_value.to_f / max_value.to_f) * 100)
|
|
518
|
+
end
|
|
519
|
+
unlimited_label = opts[:unlimited_label] || "n/a"
|
|
520
|
+
percent_label = (max_value.nil? ? unlimited_label : "#{percent.round(percent_sigdig)}%").rjust(6, ' ')
|
|
521
|
+
bar_display = ""
|
|
522
|
+
if percent > 100
|
|
523
|
+
max_bars.times { bars << "|" }
|
|
524
|
+
# percent = 100
|
|
525
|
+
else
|
|
526
|
+
n_bars = ((percent / 100.0) * max_bars).ceil
|
|
527
|
+
n_bars.times { bars << "|" }
|
|
528
|
+
end
|
|
529
|
+
|
|
530
|
+
if opts[:bar_color] == :rainbow
|
|
531
|
+
rainbow_bar = ""
|
|
532
|
+
cur_rainbow_color = reset # default terminal color
|
|
533
|
+
rainbow_bar << cur_rainbow_color
|
|
534
|
+
bars.each_with_index {|bar, i|
|
|
535
|
+
reached_percent = (i / max_bars.to_f) * 100
|
|
536
|
+
new_bar_color = cur_rainbow_color
|
|
537
|
+
if reached_percent > 80
|
|
538
|
+
new_bar_color = red
|
|
539
|
+
elsif reached_percent > 50
|
|
540
|
+
new_bar_color = yellow
|
|
541
|
+
elsif reached_percent > 10
|
|
542
|
+
new_bar_color = cyan
|
|
543
|
+
else
|
|
544
|
+
new_bar_color = reset
|
|
545
|
+
end
|
|
546
|
+
if cur_rainbow_color != new_bar_color
|
|
547
|
+
cur_rainbow_color = new_bar_color
|
|
548
|
+
rainbow_bar << cur_rainbow_color
|
|
549
|
+
end
|
|
550
|
+
rainbow_bar << bar
|
|
551
|
+
}
|
|
552
|
+
padding = max_bars - bars.size
|
|
553
|
+
if padding > 0
|
|
554
|
+
padding.times { rainbow_bar << " " }
|
|
555
|
+
#rainbow_bar << " " * padding
|
|
556
|
+
end
|
|
557
|
+
rainbow_bar << reset
|
|
558
|
+
bar_display = cyan + "[" + rainbow_bar + cyan + "]" + " #{cur_rainbow_color}#{percent_label}#{reset}"
|
|
559
|
+
out << bar_display
|
|
560
|
+
elsif opts[:bar_color] == :solid
|
|
561
|
+
bar_color = cyan
|
|
562
|
+
if percent > 80
|
|
563
|
+
bar_color = red
|
|
564
|
+
elsif percent > 50
|
|
565
|
+
bar_color = yellow
|
|
566
|
+
elsif percent > 10
|
|
567
|
+
bar_color = cyan
|
|
568
|
+
else
|
|
569
|
+
bar_color = reset
|
|
570
|
+
end
|
|
571
|
+
bar_display = cyan + "[" + bar_color + bars.join.ljust(max_bars, ' ') + cyan + "]" + " #{percent_label}" + reset
|
|
572
|
+
out << bar_display
|
|
573
|
+
else
|
|
574
|
+
bar_color = opts[:bar_color] || reset
|
|
575
|
+
bar_display = cyan + "[" + bar_color + bars.join.ljust(max_bars, ' ') + cyan + "]" + " #{percent_label}" + reset
|
|
576
|
+
out << bar_display
|
|
577
|
+
end
|
|
578
|
+
return out
|
|
579
|
+
end
|
|
580
|
+
|
|
581
|
+
def print_stats_usage(stats, opts={})
|
|
582
|
+
label_width = opts[:label_width] || 10
|
|
583
|
+
out = ""
|
|
584
|
+
if stats.nil? || stats.empty?
|
|
585
|
+
out << cyan + "No data." + "\n" + reset
|
|
586
|
+
print out
|
|
587
|
+
return
|
|
588
|
+
end
|
|
589
|
+
opts[:include] ||= [:cpu, :memory, :storage]
|
|
590
|
+
if opts[:include].include?(:max_cpu)
|
|
591
|
+
cpu_usage = stats['cpuUsagePeak']
|
|
592
|
+
out << cyan + "Max CPU".rjust(label_width, ' ') + ": " + generate_usage_bar(cpu_usage.to_f, 100) + "\n"
|
|
593
|
+
end
|
|
594
|
+
if opts[:include].include?(:avg_cpu)
|
|
595
|
+
cpu_usage = stats['cpuUsageAvg'] || stats['cpuUsageAverage']
|
|
596
|
+
out << cyan + "Avg. CPU".rjust(label_width, ' ') + ": " + generate_usage_bar(cpu_usage.to_f, 100) + "\n"
|
|
597
|
+
end
|
|
598
|
+
if opts[:include].include?(:cpu)
|
|
599
|
+
cpu_usage = stats['cpuUsage'] || stats['usedCpu']
|
|
600
|
+
out << cyan + "CPU".rjust(label_width, ' ') + ": " + generate_usage_bar(cpu_usage.to_f, 100) + "\n"
|
|
601
|
+
end
|
|
602
|
+
if opts[:include].include?(:memory)
|
|
603
|
+
out << cyan + "Memory".rjust(label_width, ' ') + ": " + generate_usage_bar(stats['usedMemory'], stats['maxMemory']) + cyan + Filesize.from("#{stats['usedMemory']} B").pretty.strip.rjust(15, ' ') + " / " + Filesize.from("#{stats['maxMemory']} B").pretty.strip.ljust(15, ' ') + "\n"
|
|
604
|
+
end
|
|
605
|
+
if opts[:include].include?(:storage)
|
|
606
|
+
out << cyan + "Storage".rjust(label_width, ' ') + ": " + generate_usage_bar(stats['usedStorage'], stats['maxStorage']) + cyan + Filesize.from("#{stats['usedStorage']} B").pretty.strip.rjust(15, ' ') + " / " + Filesize.from("#{stats['maxStorage']} B").pretty.strip.ljust(15, ' ') + "\n"
|
|
607
|
+
end
|
|
608
|
+
print out
|
|
609
|
+
end
|
|
610
|
+
|
|
611
|
+
def format_available_options(option_types)
|
|
612
|
+
option_lines = option_types.collect {|it| "\t-O #{it['fieldContext'] ? it['fieldContext'] + '.' : ''}#{it['fieldName']}=\"value\"" }.join("\n")
|
|
613
|
+
return "Available Options:\n#{option_lines}\n\n"
|
|
614
|
+
end
|
|
615
|
+
|
|
616
|
+
def format_dt_dd(label, value, label_width=10, justify="right", do_wrap=true)
|
|
617
|
+
# JD: uncomment next line to do away with justified labels
|
|
618
|
+
# label_width, justify = 0, "none"
|
|
619
|
+
out = ""
|
|
620
|
+
value = value.to_s
|
|
621
|
+
if do_wrap && value && value.include?(" ") && MtnCloud::Cli::PrintHelper.terminal_width
|
|
622
|
+
value_width = MtnCloud::Cli::PrintHelper.terminal_width - label_width
|
|
623
|
+
if value_width > 0 && value.gsub(/\e\[(\d+)m/, '').to_s.size > value_width
|
|
624
|
+
wrap_indent = label_width + 1
|
|
625
|
+
value = wrap(value, value_width, wrap_indent)
|
|
626
|
+
end
|
|
627
|
+
end
|
|
628
|
+
if justify == "right"
|
|
629
|
+
out << "#{label}:".rjust(label_width, ' ') + " #{value}"
|
|
630
|
+
elsif justify == "left"
|
|
631
|
+
out << "#{label}:".ljust(label_width, ' ') + " #{value}"
|
|
632
|
+
else
|
|
633
|
+
# default is none
|
|
634
|
+
out << "#{label}:" + " #{value}"
|
|
635
|
+
end
|
|
636
|
+
out
|
|
637
|
+
end
|
|
638
|
+
|
|
639
|
+
# truncate_string truncates a string and appends the suffix "..."
|
|
640
|
+
# @param value [String] the string to pad
|
|
641
|
+
# @param width [Integer] the length to truncate to
|
|
642
|
+
# @param suffix [String] the character to pad right side with. Default is '...'
|
|
643
|
+
def truncate_string(value, width, suffix="...")
|
|
644
|
+
value = value.to_s
|
|
645
|
+
if !width
|
|
646
|
+
return value
|
|
647
|
+
end
|
|
648
|
+
# JD: hack alerty.. this sux, but it's a best effort to preserve values containing ascii coloring codes
|
|
649
|
+
# it stops working when there are words separated by ascii codes, eg. two diff colors
|
|
650
|
+
# plus this is probably pretty slow...
|
|
651
|
+
uncolored_value = Term::ANSIColor.coloring? ? Term::ANSIColor.uncolored(value.to_s) : value.to_s
|
|
652
|
+
if uncolored_value != value
|
|
653
|
+
trimmed_value = nil
|
|
654
|
+
if uncolored_value.size > width
|
|
655
|
+
if suffix
|
|
656
|
+
trimmed_value = uncolored_value[0..width-(suffix.size+1)] + suffix
|
|
657
|
+
else
|
|
658
|
+
trimmed_value = uncolored_value[0..width-1]
|
|
659
|
+
end
|
|
660
|
+
return value.gsub(uncolored_value, trimmed_value)
|
|
661
|
+
else
|
|
662
|
+
return value
|
|
663
|
+
end
|
|
664
|
+
else
|
|
665
|
+
if value.size > width
|
|
666
|
+
if suffix
|
|
667
|
+
return value[0..width-(suffix.size+1)] + suffix
|
|
668
|
+
else
|
|
669
|
+
return value[0..width-1]
|
|
670
|
+
end
|
|
671
|
+
else
|
|
672
|
+
return value
|
|
673
|
+
end
|
|
674
|
+
end
|
|
675
|
+
end
|
|
676
|
+
|
|
677
|
+
# truncate_string truncates a string and appends the prefix "..."
|
|
678
|
+
# @param value [String] the string to pad
|
|
679
|
+
# @param width [Integer] the length to truncate to
|
|
680
|
+
# @param prefix [String] the character to pad left side with. Default is '...'
|
|
681
|
+
def truncate_string_right(value, width, prefix="...")
|
|
682
|
+
value = value.to_s
|
|
683
|
+
# JD: hack alerty.. this sux, but it's a best effort to preserve values containing ascii coloring codes
|
|
684
|
+
# it stops working when there are words separated by ascii codes, eg. two diff colors
|
|
685
|
+
# plus this is probably pretty slow...
|
|
686
|
+
uncolored_value = Term::ANSIColor.coloring? ? Term::ANSIColor.uncolored(value.to_s) : value.to_s
|
|
687
|
+
if uncolored_value != value
|
|
688
|
+
trimmed_value = nil
|
|
689
|
+
if uncolored_value.size > width
|
|
690
|
+
if prefix
|
|
691
|
+
trimmed_value = prefix + uncolored_value[(uncolored_value.size - width - prefix.size)..-1]
|
|
692
|
+
else
|
|
693
|
+
trimmed_value = uncolored_value[(uncolored_value.size - width)..-1]
|
|
694
|
+
end
|
|
695
|
+
return value.gsub(uncolored_value, trimmed_value)
|
|
696
|
+
else
|
|
697
|
+
return value
|
|
698
|
+
end
|
|
699
|
+
else
|
|
700
|
+
if value.size > width
|
|
701
|
+
if prefix
|
|
702
|
+
return prefix + value[(value.size - width - prefix.size)..-1]
|
|
703
|
+
else
|
|
704
|
+
return value[(value.size - width)..-1]
|
|
705
|
+
end
|
|
706
|
+
else
|
|
707
|
+
return value
|
|
708
|
+
end
|
|
709
|
+
end
|
|
710
|
+
end
|
|
711
|
+
|
|
712
|
+
# justified returns a left, center, or right aligned string.
|
|
713
|
+
# @param value [String] the string to pad
|
|
714
|
+
# @param width [Integer] the length to truncate to
|
|
715
|
+
# @param pad_char [String] the character to pad with. Default is ' '
|
|
716
|
+
# @return [String]
|
|
717
|
+
def justify_string(value, width, justify="left", pad_char=" ")
|
|
718
|
+
# JD: hack alert! this sux, but it's a best effort to preserve values containing ascii coloring codes
|
|
719
|
+
value = value.to_s
|
|
720
|
+
uncolored_value = Term::ANSIColor.coloring? ? Term::ANSIColor.uncolored(value.to_s) : value.to_s
|
|
721
|
+
if value.size != uncolored_value.size
|
|
722
|
+
width = width + (value.size - uncolored_value.size)
|
|
723
|
+
end
|
|
724
|
+
if justify == "right"
|
|
725
|
+
return "#{value}".rjust(width, pad_char)
|
|
726
|
+
elsif justify == "center"
|
|
727
|
+
return "#{value}".center(width, pad_char)
|
|
728
|
+
else
|
|
729
|
+
return "#{value}".ljust(width, pad_char)
|
|
730
|
+
end
|
|
731
|
+
end
|
|
732
|
+
|
|
733
|
+
def format_table_cell(value, width, justify="left", pad_char=" ", suffix="...")
|
|
734
|
+
#puts "format_table_cell(#{value}, #{width}, #{justify}, #{pad_char.inspect})"
|
|
735
|
+
cell = value.to_s
|
|
736
|
+
cell = truncate_string(cell, width, suffix)
|
|
737
|
+
cell = justify_string(cell, width, justify, pad_char)
|
|
738
|
+
cell
|
|
739
|
+
end
|
|
740
|
+
|
|
741
|
+
# as_pretty_table generates a table with aligned columns and truncated values.
|
|
742
|
+
# This can be used in place of TablePrint.tp()
|
|
743
|
+
# @param data [Array] A list of objects to extract the data from.
|
|
744
|
+
# @param columns - [Array of Objects] list of column definitions, A column definition can be a String, Symbol, or Hash
|
|
745
|
+
# @return [String]
|
|
746
|
+
# Usage: puts as_pretty_table(my_objects, [:id, :name])
|
|
747
|
+
# puts as_pretty_table(my_objects, ["id", "name", {"plan" => "plan.name" }], {color: white})
|
|
748
|
+
#
|
|
749
|
+
def as_pretty_table(data, columns, options={})
|
|
750
|
+
data = [data].flatten
|
|
751
|
+
if options[:reverse]
|
|
752
|
+
if data.is_a?(Array)
|
|
753
|
+
data.reverse!
|
|
754
|
+
elsif data.is_a?(Hash)
|
|
755
|
+
data.values.each {|v| v.reverse! if v.is_a?(Array) }
|
|
756
|
+
end
|
|
757
|
+
end
|
|
758
|
+
# support --fields x,y,z and --all-fields or --fields all
|
|
759
|
+
all_fields = data.first ? data.first.keys : []
|
|
760
|
+
#todo: support --raw-fields meh, not really needed..
|
|
761
|
+
# if options[:include_fields] && options[:raw_fields]
|
|
762
|
+
# data = transform_data_for_field_options(data, options)
|
|
763
|
+
# data = data[options[:include_fields_context]] if options[:include_fields_context]
|
|
764
|
+
# elsif options[:include_fields]
|
|
765
|
+
if options[:include_fields]
|
|
766
|
+
if (options[:include_fields].is_a?(Array) && options[:include_fields].size == 1 && options[:include_fields][0] == 'all') || options[:include_fields] == 'all'
|
|
767
|
+
columns = all_fields
|
|
768
|
+
else
|
|
769
|
+
# so let's use the passed in column definitions instead of the raw data properties
|
|
770
|
+
# columns = options[:include_fields]
|
|
771
|
+
new_columns = {}
|
|
772
|
+
options[:include_fields].each do |f|
|
|
773
|
+
matching_column = nil
|
|
774
|
+
# column definitions vary right now, array of symbols/strings/hashes or perhaps a single hash
|
|
775
|
+
if columns.is_a?(Array) && columns[0] && columns[0].is_a?(Hash)
|
|
776
|
+
matching_column = columns.find {|c|
|
|
777
|
+
if c.is_a?(Hash)
|
|
778
|
+
c.keys[0].to_s.downcase == f.to_s.downcase
|
|
779
|
+
else
|
|
780
|
+
c && c.to_s.downcase == f.to_s.downcase
|
|
781
|
+
end
|
|
782
|
+
}
|
|
783
|
+
elsif columns.is_a?(Hash)
|
|
784
|
+
matching_key = columns.keys.find {|k| k.to_s.downcase == f.to_s.downcase }
|
|
785
|
+
if matching_key
|
|
786
|
+
matching_column = columns[matching_key]
|
|
787
|
+
end
|
|
788
|
+
end
|
|
789
|
+
new_columns[f] = matching_column ? matching_column : f
|
|
790
|
+
end
|
|
791
|
+
columns = new_columns
|
|
792
|
+
end
|
|
793
|
+
elsif options[:all_fields]
|
|
794
|
+
columns = all_fields
|
|
795
|
+
else
|
|
796
|
+
columns = columns
|
|
797
|
+
end
|
|
798
|
+
|
|
799
|
+
columns = build_column_definitions(columns)
|
|
800
|
+
|
|
801
|
+
table_color = options[:color] || cyan
|
|
802
|
+
cell_delim = options[:delim] || " | "
|
|
803
|
+
|
|
804
|
+
header_row = []
|
|
805
|
+
|
|
806
|
+
columns.each do |column_def|
|
|
807
|
+
header_row << column_def.label
|
|
808
|
+
end
|
|
809
|
+
|
|
810
|
+
# generate rows matrix data for the specified columns
|
|
811
|
+
rows = []
|
|
812
|
+
data.each do |row_data|
|
|
813
|
+
row = []
|
|
814
|
+
columns.each do |column_def|
|
|
815
|
+
# r << column_def.display_method.respond_to?(:call) ? column_def.display_method.call(row_data) : get_object_value(row_data, column_def.display_method)
|
|
816
|
+
value = column_def.display_method.call(row_data)
|
|
817
|
+
value = JSON.fast_generate(value) if value.is_a?(Hash) || value.is_a?(Array)
|
|
818
|
+
row << value
|
|
819
|
+
end
|
|
820
|
+
rows << row
|
|
821
|
+
end
|
|
822
|
+
|
|
823
|
+
# all rows (pre-formatted)
|
|
824
|
+
data_matrix = [header_row] + rows
|
|
825
|
+
|
|
826
|
+
# determine column meta info i.e. width
|
|
827
|
+
columns.each_with_index do |column_def, column_index|
|
|
828
|
+
# column_def.meta = {
|
|
829
|
+
# max_value_size: (header_row + rows).max {|row| row[column_index] ? row[column_index].to_s.size : 0 }.size
|
|
830
|
+
# }
|
|
831
|
+
if column_def.fixed_width
|
|
832
|
+
column_def.width = column_def.fixed_width.to_i
|
|
833
|
+
else
|
|
834
|
+
max_value_size = 0
|
|
835
|
+
data_matrix.each do |row|
|
|
836
|
+
v = row[column_index].to_s
|
|
837
|
+
v_size = Term::ANSIColor.coloring? ? Term::ANSIColor.uncolored(v).size : v.size
|
|
838
|
+
if v_size > max_value_size
|
|
839
|
+
max_value_size = v_size
|
|
840
|
+
end
|
|
841
|
+
end
|
|
842
|
+
|
|
843
|
+
max_width = (column_def.max_width.to_i > 0) ? column_def.max_width.to_i : nil
|
|
844
|
+
min_width = (column_def.min_width.to_i > 0) ? column_def.min_width.to_i : nil
|
|
845
|
+
if min_width && max_value_size < min_width
|
|
846
|
+
column_def.width = min_width
|
|
847
|
+
elsif max_width && max_value_size > max_width
|
|
848
|
+
column_def.width = max_width
|
|
849
|
+
else
|
|
850
|
+
# expand / contract to size of the value by default
|
|
851
|
+
column_def.width = max_value_size
|
|
852
|
+
end
|
|
853
|
+
#puts "DEBUG: #{column_index} column_def.width: #{column_def.width}"
|
|
854
|
+
end
|
|
855
|
+
end
|
|
856
|
+
|
|
857
|
+
# responsive tables
|
|
858
|
+
# pops columns off end until they all fit on the terminal
|
|
859
|
+
# could use some options[:preferred_columns] logic here to throw away in some specified order
|
|
860
|
+
# --all fields disables this
|
|
861
|
+
trimmed_columns = []
|
|
862
|
+
if options[:wrap] != true # && options[:include_fields].nil? && options[:all_fields] != true
|
|
863
|
+
|
|
864
|
+
begin
|
|
865
|
+
term_width = current_terminal_width()
|
|
866
|
+
table_width = columns.inject(0) {|acc, column_def| acc + (column_def.width || 0) }
|
|
867
|
+
table_width += ((columns.size-0) * (3)) # col border width
|
|
868
|
+
if term_width && table_width
|
|
869
|
+
# leave 1 column always...
|
|
870
|
+
while table_width > term_width && columns.size > 1
|
|
871
|
+
column_index = columns.size - 1
|
|
872
|
+
removed_column = columns.pop
|
|
873
|
+
trimmed_columns << removed_column
|
|
874
|
+
if removed_column.width
|
|
875
|
+
table_width -= removed_column.width
|
|
876
|
+
table_width -= 3 # col border width
|
|
877
|
+
end
|
|
878
|
+
|
|
879
|
+
# clear from data_matrix
|
|
880
|
+
# wel, nvm it just gets regenerated
|
|
881
|
+
|
|
882
|
+
end
|
|
883
|
+
end
|
|
884
|
+
rescue => ex
|
|
885
|
+
MtnCloud::Logging::DarkPrinter.puts "Encountered error while applying responsive table sizing: (#{ex.class}) #{ex}"
|
|
886
|
+
end
|
|
887
|
+
|
|
888
|
+
if trimmed_columns.size > 0
|
|
889
|
+
# data_matrix = generate_table_data(data, columns, options)
|
|
890
|
+
header_row = []
|
|
891
|
+
columns.each do |column_def|
|
|
892
|
+
header_row << column_def.label
|
|
893
|
+
end
|
|
894
|
+
rows = []
|
|
895
|
+
data.each do |row_data|
|
|
896
|
+
row = []
|
|
897
|
+
columns.each do |column_def|
|
|
898
|
+
# r << column_def.display_method.respond_to?(:call) ? column_def.display_method.call(row_data) : get_object_value(row_data, column_def.display_method)
|
|
899
|
+
value = column_def.display_method.call(row_data)
|
|
900
|
+
value = JSON.fast_generate(value) if value.is_a?(Hash) || value.is_a?(Array)
|
|
901
|
+
row << value
|
|
902
|
+
end
|
|
903
|
+
rows << row
|
|
904
|
+
end
|
|
905
|
+
data_matrix = [header_row] + rows
|
|
906
|
+
end
|
|
907
|
+
end
|
|
908
|
+
|
|
909
|
+
# format header row
|
|
910
|
+
header_cells = []
|
|
911
|
+
columns.each_with_index do |column_def, column_index|
|
|
912
|
+
value = header_row[column_index] # column_def.label
|
|
913
|
+
header_cells << format_table_cell(value, column_def.width, column_def.justify)
|
|
914
|
+
end
|
|
915
|
+
|
|
916
|
+
# format header spacer row
|
|
917
|
+
if options[:border_style] == :thin
|
|
918
|
+
# a simpler looking table
|
|
919
|
+
cell_delim = " "
|
|
920
|
+
h_line = header_cells.collect {|cell| ("-" * cell.strip.size).ljust(cell.size, ' ') }.join(cell_delim)
|
|
921
|
+
else
|
|
922
|
+
# default border style
|
|
923
|
+
h_line = header_cells.collect {|cell| ("-" * cell.size) }.join(cell_delim.gsub(" ", "-"))
|
|
924
|
+
end
|
|
925
|
+
|
|
926
|
+
# format data rows
|
|
927
|
+
formatted_rows = []
|
|
928
|
+
rows.each_with_index do |row, row_index|
|
|
929
|
+
formatted_row = []
|
|
930
|
+
row.each_with_index do |value, column_index|
|
|
931
|
+
column_def = columns[column_index]
|
|
932
|
+
formatted_row << format_table_cell(value, column_def.width, column_def.justify)
|
|
933
|
+
end
|
|
934
|
+
formatted_rows << formatted_row
|
|
935
|
+
end
|
|
936
|
+
|
|
937
|
+
|
|
938
|
+
|
|
939
|
+
table_str = ""
|
|
940
|
+
table_str << header_cells.join(cell_delim) + "\n"
|
|
941
|
+
table_str << h_line + "\n"
|
|
942
|
+
formatted_rows.each do |row|
|
|
943
|
+
table_str << row.join(cell_delim) + "\n"
|
|
944
|
+
end
|
|
945
|
+
|
|
946
|
+
out = ""
|
|
947
|
+
out << table_color if table_color
|
|
948
|
+
out << table_str
|
|
949
|
+
out << reset if table_color
|
|
950
|
+
out
|
|
951
|
+
end
|
|
952
|
+
|
|
953
|
+
|
|
954
|
+
# as_description_list() prints a a two column table containing
|
|
955
|
+
# the name and value of a list of descriptions
|
|
956
|
+
# @param columns - [Hash or Array or Hashes] list of column definitions, A column defintion can be a String, Symbol, Hash or Proc
|
|
957
|
+
# @param obj [Object] an object to extract the data from, it is treated like a Hash.
|
|
958
|
+
# @param opts [Map] rendering options for label :justify, :wrap
|
|
959
|
+
# Usage:
|
|
960
|
+
# print_description_list([:id, :name, :status], my_instance, {})
|
|
961
|
+
#
|
|
962
|
+
def as_description_list(obj, columns, opts={})
|
|
963
|
+
|
|
964
|
+
columns = build_column_definitions(columns)
|
|
965
|
+
|
|
966
|
+
#label_width = opts[:label_width] || 10
|
|
967
|
+
max_label_width = 0
|
|
968
|
+
justify = opts.key?(:justify) ? opts[:justify] : "right"
|
|
969
|
+
do_wrap = opts.key?(:wrap) ? !!opts[:wrap] : true
|
|
970
|
+
color = opts.key?(:color) ? opts[:color] : cyan
|
|
971
|
+
rows = []
|
|
972
|
+
|
|
973
|
+
columns.flatten.each do |column_def|
|
|
974
|
+
label = column_def.label
|
|
975
|
+
label = label.upcase if ALL_LABELS_UPCASE
|
|
976
|
+
# value = get_object_value(obj, column_def.display_method)
|
|
977
|
+
value = column_def.display_method.call(obj)
|
|
978
|
+
value = JSON.fast_generate(value) if value.is_a?(Hash) || value.is_a?(Array)
|
|
979
|
+
if label.size > max_label_width
|
|
980
|
+
max_label_width = label.size
|
|
981
|
+
end
|
|
982
|
+
rows << {label: label, value: value}
|
|
983
|
+
end
|
|
984
|
+
label_width = max_label_width + 1 # for a leading space ' ' ..ew
|
|
985
|
+
value_width = nil
|
|
986
|
+
if MtnCloud::Cli::PrintHelper.terminal_width
|
|
987
|
+
value_width = MtnCloud::Cli::PrintHelper.terminal_width - label_width
|
|
988
|
+
end
|
|
989
|
+
|
|
990
|
+
out = ""
|
|
991
|
+
out << color if color
|
|
992
|
+
rows.each do |row|
|
|
993
|
+
value = row[:value].to_s
|
|
994
|
+
out << format_dt_dd(row[:label], value, label_width, justify, do_wrap) + "\n"
|
|
995
|
+
end
|
|
996
|
+
out << reset if color
|
|
997
|
+
return out
|
|
998
|
+
end
|
|
999
|
+
|
|
1000
|
+
# print_description_list() is an alias for `print generate_description_list()`
|
|
1001
|
+
def print_description_list(columns, obj, opts={})
|
|
1002
|
+
# raise "oh no.. replace with as_description_list()"
|
|
1003
|
+
print as_description_list(obj, columns, opts)
|
|
1004
|
+
end
|
|
1005
|
+
|
|
1006
|
+
def print_pretty_details(obj, opts={})
|
|
1007
|
+
print as_pretty_details(obj, opts)
|
|
1008
|
+
end
|
|
1009
|
+
|
|
1010
|
+
def as_pretty_details(obj, opts={})
|
|
1011
|
+
print as_pretty_details(obj, opts.merge({pretty: true}))
|
|
1012
|
+
end
|
|
1013
|
+
|
|
1014
|
+
def print_details(obj, opts={})
|
|
1015
|
+
print as_details(obj, opts)
|
|
1016
|
+
end
|
|
1017
|
+
|
|
1018
|
+
def as_details(obj, opts={})
|
|
1019
|
+
#return "" if obj.nil?
|
|
1020
|
+
columns = {}
|
|
1021
|
+
keys = obj.keys
|
|
1022
|
+
if opts[:sort]
|
|
1023
|
+
keys.sort!
|
|
1024
|
+
end
|
|
1025
|
+
keys.each do |key|
|
|
1026
|
+
display_proc = nil
|
|
1027
|
+
if opts[:column_format] && opts[:column_format].key?(key.to_sym)
|
|
1028
|
+
display_proc = opts[:column_format][key.to_sym]
|
|
1029
|
+
else
|
|
1030
|
+
display_proc = lambda {|it| format_detail_value(it[key]) }
|
|
1031
|
+
end
|
|
1032
|
+
label = opts[:pretty] ? key.to_s.titleize : key.to_s
|
|
1033
|
+
columns[label] = display_proc
|
|
1034
|
+
end
|
|
1035
|
+
as_description_list(obj, columns, opts)
|
|
1036
|
+
end
|
|
1037
|
+
|
|
1038
|
+
def format_detail_value(value)
|
|
1039
|
+
rtn = value
|
|
1040
|
+
if value.is_a?(Array)
|
|
1041
|
+
# show the first three objects
|
|
1042
|
+
rtn = value.first(3).collect { |row| format_abbreviated_value(row) }.join(", ")
|
|
1043
|
+
elsif value.is_a?(Hash)
|
|
1044
|
+
# show the first three properties
|
|
1045
|
+
keys = values.keys.select { |key| value[key].is_a?(Numeric) || value[key].is_a?(String) }.first(3)
|
|
1046
|
+
rtn = keys.collect { |key|
|
|
1047
|
+
"#{key.to_s.titleize}: #{format_abbreviated_value(value[key])}"
|
|
1048
|
+
}.join(", ")
|
|
1049
|
+
elsif value.is_a?(TrueClass) || value.is_a?(FalseClass)
|
|
1050
|
+
rtn = format_boolean(value)
|
|
1051
|
+
else
|
|
1052
|
+
rtn = value.to_s
|
|
1053
|
+
end
|
|
1054
|
+
return rtn
|
|
1055
|
+
end
|
|
1056
|
+
|
|
1057
|
+
def format_abbreviated_value(value)
|
|
1058
|
+
if value.is_a?(Hash)
|
|
1059
|
+
if value.keys.size == 0
|
|
1060
|
+
"{}"
|
|
1061
|
+
else
|
|
1062
|
+
# show the first three properties
|
|
1063
|
+
keys = value.keys.select { |key| value[key].is_a?(Numeric) || value[key].is_a?(String) }.first(3)
|
|
1064
|
+
keys.collect { |key|
|
|
1065
|
+
"#{key.to_s.titleize}: #{value[key]}"
|
|
1066
|
+
}.join(", ")
|
|
1067
|
+
end
|
|
1068
|
+
elsif value.is_a?(Array)
|
|
1069
|
+
if value.size == 0
|
|
1070
|
+
return "[]"
|
|
1071
|
+
elsif obj.size == 1
|
|
1072
|
+
"[(#{obj.size})]"
|
|
1073
|
+
else
|
|
1074
|
+
"[(#{obj.size})]"
|
|
1075
|
+
end
|
|
1076
|
+
elsif value.is_a?(TrueClass) || value.is_a?(FalseClass)
|
|
1077
|
+
format_boolean(value)
|
|
1078
|
+
else
|
|
1079
|
+
value.to_s
|
|
1080
|
+
end
|
|
1081
|
+
end
|
|
1082
|
+
|
|
1083
|
+
# build_column_definitions constructs an Array of column definitions (OpenStruct)
|
|
1084
|
+
# Each column is defined by a label (String), and a display_method (Proc)
|
|
1085
|
+
#
|
|
1086
|
+
# @columns [Array] list of definitions. A column definition can be a String, Symbol, Proc or Hash
|
|
1087
|
+
# @return [Array of OpenStruct] list of column definitions (OpenStruct) like:
|
|
1088
|
+
# [{label: "ID", display_method: 'id'}, {label: "Name", display_method: Proc}]
|
|
1089
|
+
# Usage:
|
|
1090
|
+
# build_column_definitions(:id, :name)
|
|
1091
|
+
# build_column_definitions({"Object Id" => 'id'}, :name)
|
|
1092
|
+
# build_column_definitions({"ID" => 'id'}, "name", "plan.name", {status: lambda {|data| data['status'].upcase } })
|
|
1093
|
+
#
|
|
1094
|
+
def build_column_definitions(*columns)
|
|
1095
|
+
# allow passing a single hash instead of an array of hashes
|
|
1096
|
+
if columns.size == 1 && columns[0].is_a?(Hash)
|
|
1097
|
+
columns = columns[0].collect {|k,v| {(k) => v} }
|
|
1098
|
+
else
|
|
1099
|
+
columns = columns.flatten.compact
|
|
1100
|
+
end
|
|
1101
|
+
results = []
|
|
1102
|
+
columns.each do |col|
|
|
1103
|
+
# determine label
|
|
1104
|
+
if col.is_a?(String)
|
|
1105
|
+
# supports "field as Label"
|
|
1106
|
+
field_key, field_label = col.split(/\s+as\s+/)
|
|
1107
|
+
if field_key && field_label
|
|
1108
|
+
k = field_label.strip
|
|
1109
|
+
v = field_key.strip
|
|
1110
|
+
else
|
|
1111
|
+
k = col.strip
|
|
1112
|
+
v = col.strip
|
|
1113
|
+
end
|
|
1114
|
+
build_column_definitions([{(k) => v}]).each do |r|
|
|
1115
|
+
results << r if r
|
|
1116
|
+
end
|
|
1117
|
+
elsif col.is_a?(Symbol)
|
|
1118
|
+
k = col.to_s.upcase #.capitalize
|
|
1119
|
+
v = col.to_s
|
|
1120
|
+
build_column_definitions([{(k) => v}]).each do |r|
|
|
1121
|
+
results << r if r
|
|
1122
|
+
end
|
|
1123
|
+
elsif col.is_a?(Hash)
|
|
1124
|
+
column_def = OpenStruct.new
|
|
1125
|
+
k, v = col.keys[0], col.values[0]
|
|
1126
|
+
if k.is_a?(String)
|
|
1127
|
+
column_def.label = k
|
|
1128
|
+
elsif k.is_a?(Symbol)
|
|
1129
|
+
column_def.label = k
|
|
1130
|
+
else
|
|
1131
|
+
column_def.label = k.to_s
|
|
1132
|
+
# raise "invalid column definition label (#{k.class}) #{k.inspect}. Should be a String or Symbol."
|
|
1133
|
+
end
|
|
1134
|
+
|
|
1135
|
+
# determine display_method
|
|
1136
|
+
if v.is_a?(String)
|
|
1137
|
+
column_def.display_method = lambda {|data| get_object_value(data, v) }
|
|
1138
|
+
elsif v.is_a?(Symbol)
|
|
1139
|
+
column_def.display_method = lambda {|data| get_object_value(data, v) }
|
|
1140
|
+
elsif v.is_a?(Proc)
|
|
1141
|
+
column_def.display_method = v
|
|
1142
|
+
elsif v.is_a?(Hash) || v.is_a?(OpenStruct)
|
|
1143
|
+
if v[:display_name] || v[:label]
|
|
1144
|
+
column_def.label = v[:display_name] || v[:label]
|
|
1145
|
+
end
|
|
1146
|
+
if v[:display_method]
|
|
1147
|
+
if v[:display_method].is_a?(Proc)
|
|
1148
|
+
column_def.display_method = v[:display_method]
|
|
1149
|
+
else
|
|
1150
|
+
# assume v[:display_method] is a String, Symbol
|
|
1151
|
+
column_def.display_method = lambda {|data| get_object_value(data, v[:display_method]) }
|
|
1152
|
+
end
|
|
1153
|
+
else
|
|
1154
|
+
# the default behavior is to use the key (undoctored) to find the data
|
|
1155
|
+
# column_def.display_method = k
|
|
1156
|
+
column_def.display_method = lambda {|data| get_object_value(data, k) }
|
|
1157
|
+
end
|
|
1158
|
+
|
|
1159
|
+
# other column rendering options
|
|
1160
|
+
column_def.justify = v[:justify]
|
|
1161
|
+
if v[:max_width]
|
|
1162
|
+
column_def.max_width = v[:max_width]
|
|
1163
|
+
end
|
|
1164
|
+
if v[:min_width]
|
|
1165
|
+
column_def.min_width = v[:min_width]
|
|
1166
|
+
end
|
|
1167
|
+
# tp uses width to behave like max_width, but tp() is gone, remove this?
|
|
1168
|
+
if v[:width]
|
|
1169
|
+
column_def.width = v[:width]
|
|
1170
|
+
column_def.max_width = v[:width]
|
|
1171
|
+
end
|
|
1172
|
+
column_def.wrap = v[:wrap].nil? ? true : v[:wrap] # only utlized in as_description_list() right now
|
|
1173
|
+
|
|
1174
|
+
else
|
|
1175
|
+
raise "invalid column definition value (#{v.class}) #{v.inspect}. Should be a String, Symbol, Proc or Hash"
|
|
1176
|
+
end
|
|
1177
|
+
|
|
1178
|
+
# only upcase label for symbols, this is silly anyway,
|
|
1179
|
+
# just pass the exact label (key) that you want printed..
|
|
1180
|
+
if column_def.label.is_a?(Symbol)
|
|
1181
|
+
column_def.label = column_def.label.to_s.upcase
|
|
1182
|
+
end
|
|
1183
|
+
|
|
1184
|
+
results << column_def
|
|
1185
|
+
|
|
1186
|
+
else
|
|
1187
|
+
raise "invalid column definition (#{column_def.class}) #{column_def.inspect}. Should be a String, Symbol or Hash"
|
|
1188
|
+
end
|
|
1189
|
+
|
|
1190
|
+
end
|
|
1191
|
+
|
|
1192
|
+
return results
|
|
1193
|
+
end
|
|
1194
|
+
|
|
1195
|
+
def wrap(s, width, indent=0)
|
|
1196
|
+
out = s
|
|
1197
|
+
if s.size > width
|
|
1198
|
+
if indent > 0
|
|
1199
|
+
out = s.gsub(/(.{1,#{width}})(\s+|\Z)/, "#{' ' * indent}\\1\n").strip
|
|
1200
|
+
else
|
|
1201
|
+
out = s.gsub(/(.{1,#{width}})(\s+|\Z)/, "\\1\n")
|
|
1202
|
+
end
|
|
1203
|
+
else
|
|
1204
|
+
return s
|
|
1205
|
+
end
|
|
1206
|
+
end
|
|
1207
|
+
|
|
1208
|
+
def format_boolean(v)
|
|
1209
|
+
if v == true || v == "true" || v == "on"
|
|
1210
|
+
"Yes"
|
|
1211
|
+
else
|
|
1212
|
+
"No"
|
|
1213
|
+
end
|
|
1214
|
+
end
|
|
1215
|
+
|
|
1216
|
+
def quote_csv_value(v)
|
|
1217
|
+
'"' + v.to_s.gsub('"', '""') + '"'
|
|
1218
|
+
end
|
|
1219
|
+
|
|
1220
|
+
def as_csv(data, default_columns=nil, options={}, object_key=nil)
|
|
1221
|
+
out = ""
|
|
1222
|
+
delim = options[:csv_delim] || options[:delim] || ","
|
|
1223
|
+
newline = options[:csv_newline] || options[:newline] || "\n"
|
|
1224
|
+
include_header = options[:csv_no_header] ? false : true
|
|
1225
|
+
do_quotes = options[:csv_quotes] || options[:quotes]
|
|
1226
|
+
if options[:reverse]
|
|
1227
|
+
if data.is_a?(Array)
|
|
1228
|
+
data.reverse!
|
|
1229
|
+
elsif data.is_a?(Hash)
|
|
1230
|
+
data.values.each {|v| v.reverse! if v.is_a?(Array) }
|
|
1231
|
+
end
|
|
1232
|
+
end
|
|
1233
|
+
if options[:include_fields]
|
|
1234
|
+
data = transform_data_for_field_options(data, options, object_key)
|
|
1235
|
+
if data.is_a?(Hash)
|
|
1236
|
+
if options[:raw_fields]
|
|
1237
|
+
if options[:include_fields_context]
|
|
1238
|
+
data = data[options[:include_fields_context]]
|
|
1239
|
+
else
|
|
1240
|
+
# todo: could use a dynamic object_key, first Array or Hash in the data, can probably always do this...
|
|
1241
|
+
# if object_key.nil?
|
|
1242
|
+
# object_key = data.keys.find {|k| data[k].is_a?(Array) || data[k].is_a?(Hash) }
|
|
1243
|
+
# end
|
|
1244
|
+
# if object_key && data[object_key]
|
|
1245
|
+
# data = data[object_key]
|
|
1246
|
+
# end
|
|
1247
|
+
end
|
|
1248
|
+
else
|
|
1249
|
+
if object_key
|
|
1250
|
+
data = data[object_key]
|
|
1251
|
+
end
|
|
1252
|
+
end
|
|
1253
|
+
end
|
|
1254
|
+
else
|
|
1255
|
+
# need array of records, so always select the object/array here
|
|
1256
|
+
if object_key
|
|
1257
|
+
if data.is_a?(Hash)
|
|
1258
|
+
data = data[object_key]
|
|
1259
|
+
else
|
|
1260
|
+
MtnCloud::Logging::DarkPrinter.puts "as_csv() expects data as an to fetch object key '#{object_key}' from, #{data.class}." if MtnCloud::Logging.debug?
|
|
1261
|
+
end
|
|
1262
|
+
end
|
|
1263
|
+
end
|
|
1264
|
+
|
|
1265
|
+
|
|
1266
|
+
records = data
|
|
1267
|
+
|
|
1268
|
+
# allow records as Array and Hash only..
|
|
1269
|
+
if records.is_a?(Array)
|
|
1270
|
+
# records = records
|
|
1271
|
+
elsif records.is_a?(Hash)
|
|
1272
|
+
records = [records]
|
|
1273
|
+
else
|
|
1274
|
+
#raise "records_as_csv expects records as an Array of objects to render"
|
|
1275
|
+
MtnCloud::Logging::DarkPrinter.puts "as_csv() expects data as an Array of objects to render, got a #{records.class} instead" if MtnCloud::Logging.debug?
|
|
1276
|
+
# return ""
|
|
1277
|
+
return out
|
|
1278
|
+
end
|
|
1279
|
+
|
|
1280
|
+
# build column definitions, by default use all properties for the first record (Hash) in the array
|
|
1281
|
+
columns = []
|
|
1282
|
+
all_fields = records.first.is_a?(Hash) ? records.first.keys : []
|
|
1283
|
+
if options[:include_fields]
|
|
1284
|
+
if (options[:include_fields].is_a?(Array) && options[:include_fields].size == 1 && options[:include_fields][0] == 'all') || options[:include_fields] == 'all'
|
|
1285
|
+
columns = all_fields
|
|
1286
|
+
else
|
|
1287
|
+
columns = options[:include_fields]
|
|
1288
|
+
end
|
|
1289
|
+
elsif options[:all_fields]
|
|
1290
|
+
columns = all_fields
|
|
1291
|
+
elsif default_columns
|
|
1292
|
+
columns = default_columns
|
|
1293
|
+
else
|
|
1294
|
+
columns = all_fields
|
|
1295
|
+
end
|
|
1296
|
+
|
|
1297
|
+
column_defs = build_column_definitions(columns)
|
|
1298
|
+
|
|
1299
|
+
if include_header
|
|
1300
|
+
headers = column_defs.collect {|column_def| column_def.label }
|
|
1301
|
+
if do_quotes
|
|
1302
|
+
headers = headers.collect {|it| quote_csv_value(it) }
|
|
1303
|
+
end
|
|
1304
|
+
out << headers.join(delim)
|
|
1305
|
+
out << newline
|
|
1306
|
+
end
|
|
1307
|
+
lines = []
|
|
1308
|
+
records.each do |obj|
|
|
1309
|
+
if obj
|
|
1310
|
+
cells = []
|
|
1311
|
+
column_defs.each do |column_def|
|
|
1312
|
+
label = column_def.label
|
|
1313
|
+
value = column_def.display_method.call(obj)
|
|
1314
|
+
value = value.is_a?(String) ? value : JSON.fast_generate(value)
|
|
1315
|
+
# value = get_object_value(obj, column_def)
|
|
1316
|
+
if do_quotes
|
|
1317
|
+
cells << quote_csv_value(value)
|
|
1318
|
+
else
|
|
1319
|
+
cells << value.to_s
|
|
1320
|
+
end
|
|
1321
|
+
end
|
|
1322
|
+
end
|
|
1323
|
+
line = cells.join(delim)
|
|
1324
|
+
lines << line
|
|
1325
|
+
end
|
|
1326
|
+
out << lines.join(newline)
|
|
1327
|
+
#out << delim
|
|
1328
|
+
out
|
|
1329
|
+
|
|
1330
|
+
end
|
|
1331
|
+
|
|
1332
|
+
# deprecated, replaced by as_csv(records, columns, options, object_key)
|
|
1333
|
+
def records_as_csv(records, options={}, default_columns=nil)
|
|
1334
|
+
as_csv(records, default_columns, options)
|
|
1335
|
+
end
|
|
1336
|
+
|
|
1337
|
+
def as_json(data, options={}, object_key=nil)
|
|
1338
|
+
out = ""
|
|
1339
|
+
if !data
|
|
1340
|
+
return "null" # "No data"
|
|
1341
|
+
end
|
|
1342
|
+
if options[:reverse]
|
|
1343
|
+
if data.is_a?(Array)
|
|
1344
|
+
data.reverse!
|
|
1345
|
+
elsif data.is_a?(Hash)
|
|
1346
|
+
data.values.each {|v| v.reverse! if v.is_a?(Array) }
|
|
1347
|
+
end
|
|
1348
|
+
end
|
|
1349
|
+
if options[:include_fields]
|
|
1350
|
+
data = transform_data_for_field_options(data, options, object_key)
|
|
1351
|
+
end
|
|
1352
|
+
|
|
1353
|
+
do_pretty = options.key?(:pretty_json) ? options[:pretty_json] : true
|
|
1354
|
+
if do_pretty
|
|
1355
|
+
out << JSON.pretty_generate(data)
|
|
1356
|
+
else
|
|
1357
|
+
out << JSON.fast_generate(data)
|
|
1358
|
+
end
|
|
1359
|
+
#out << "\n"
|
|
1360
|
+
out
|
|
1361
|
+
end
|
|
1362
|
+
|
|
1363
|
+
def as_yaml(data, options={}, object_key=nil)
|
|
1364
|
+
out = ""
|
|
1365
|
+
if !data
|
|
1366
|
+
return "null" # "No data"
|
|
1367
|
+
end
|
|
1368
|
+
if options[:reverse]
|
|
1369
|
+
if data.is_a?(Array)
|
|
1370
|
+
data.reverse!
|
|
1371
|
+
elsif data.is_a?(Hash)
|
|
1372
|
+
data.values.each {|v| v.reverse! if v.is_a?(Array) }
|
|
1373
|
+
end
|
|
1374
|
+
end
|
|
1375
|
+
if options[:include_fields]
|
|
1376
|
+
data = transform_data_for_field_options(data, options, object_key)
|
|
1377
|
+
end
|
|
1378
|
+
begin
|
|
1379
|
+
out << data.to_yaml
|
|
1380
|
+
rescue => err
|
|
1381
|
+
puts "failed to render YAML from data: #{data.inspect}"
|
|
1382
|
+
puts err.message
|
|
1383
|
+
end
|
|
1384
|
+
#out << "\n"
|
|
1385
|
+
out
|
|
1386
|
+
end
|
|
1387
|
+
|
|
1388
|
+
|
|
1389
|
+
# transform data for options --fields id,authority and --select id,authority
|
|
1390
|
+
# support traversing records with --raw-fields and the list command. Example: roles list --raw-fields roles.id,roles.authority
|
|
1391
|
+
def transform_data_for_field_options(data, options, object_key=nil)
|
|
1392
|
+
if options[:include_fields] && data.is_a?(Hash)
|
|
1393
|
+
if options[:raw_fields]
|
|
1394
|
+
row = (object_key && !options[:raw_fields]) ? data[object_key] : data
|
|
1395
|
+
records = [row].flatten()
|
|
1396
|
+
# look for an array in the first field only now...
|
|
1397
|
+
field_parts = options[:include_fields][0].to_s.split(".")
|
|
1398
|
+
field_context = field_parts[0]
|
|
1399
|
+
context_data = data[field_context]
|
|
1400
|
+
if field_parts.size > 1 && context_data.is_a?(Array)
|
|
1401
|
+
# inject all the root level properties to be selectable too..
|
|
1402
|
+
context_data = data.delete(field_context)
|
|
1403
|
+
# records = context_data
|
|
1404
|
+
records = context_data.collect {|it| it.is_a?(Hash) ? data.merge(it) : data }
|
|
1405
|
+
# hacky modifying options in place
|
|
1406
|
+
options[:include_fields_context] = field_context
|
|
1407
|
+
options[:include_fields] = options[:include_fields].collect {|it| it.sub(field_context+'.', '')}
|
|
1408
|
+
# data = filter_data(records, options[:include_fields])
|
|
1409
|
+
# data[field_context] = filter_data(records, options[:include_fields])
|
|
1410
|
+
data = {(field_context) => filter_data(records, options[:include_fields])}
|
|
1411
|
+
else
|
|
1412
|
+
data = filter_data(data, options[:include_fields])
|
|
1413
|
+
end
|
|
1414
|
+
else
|
|
1415
|
+
# By default, fields are relative to the object_key, so you can use -F id instead of requiring -F instance.id
|
|
1416
|
+
# So ironically it is the 'raw' options (:raw_fields == true) that has to do all this funny stuff to filter intuitively.
|
|
1417
|
+
if object_key
|
|
1418
|
+
# this removes everything but the object, makes sense when using --fields
|
|
1419
|
+
data = {(object_key) => filter_data(data[object_key], options[:include_fields])}
|
|
1420
|
+
# this preserves other fields eg. meta...
|
|
1421
|
+
# data[object_key] = filter_data(data[object_key], options[:include_fields])
|
|
1422
|
+
else
|
|
1423
|
+
data = filter_data(data, options[:include_fields])
|
|
1424
|
+
end
|
|
1425
|
+
end
|
|
1426
|
+
end
|
|
1427
|
+
return data
|
|
1428
|
+
end
|
|
1429
|
+
|
|
1430
|
+
def sleep_with_dots(sleep_seconds, dots=3, dot_chr=".")
|
|
1431
|
+
dot_interval = (sleep_seconds.to_f / dots.to_i)
|
|
1432
|
+
dots.to_i.times do |dot_index|
|
|
1433
|
+
sleep dot_interval
|
|
1434
|
+
print dot_chr
|
|
1435
|
+
end
|
|
1436
|
+
end
|
|
1437
|
+
|
|
1438
|
+
def print_to_file(txt, filename, overwrite=false, access_mode = 'w+')
|
|
1439
|
+
MtnCloud::Logging::DarkPrinter.puts "Writing #{txt.to_s.bytesize} bytes to file #{filename}" if MtnCloud::Logging.debug?
|
|
1440
|
+
outfile = nil
|
|
1441
|
+
begin
|
|
1442
|
+
full_filename = File.expand_path(filename)
|
|
1443
|
+
if File.exist?(full_filename)
|
|
1444
|
+
if !overwrite
|
|
1445
|
+
print "#{red}Output file '#{filename}' already exists.#{reset}\n"
|
|
1446
|
+
print "#{red}Use --overwrite to overwrite the existing file.#{reset}\n"
|
|
1447
|
+
return 1
|
|
1448
|
+
end
|
|
1449
|
+
end
|
|
1450
|
+
if Dir.exist?(full_filename)
|
|
1451
|
+
print "#{red}Output file '#{filename}' is invalid. It is the name of an existing directory.#{reset}\n"
|
|
1452
|
+
return 1
|
|
1453
|
+
end
|
|
1454
|
+
target_dir = File.dirname(full_filename)
|
|
1455
|
+
if !Dir.exist?(target_dir)
|
|
1456
|
+
FileUtils.mkdir_p(target_dir)
|
|
1457
|
+
end
|
|
1458
|
+
outfile = File.open(full_filename, access_mode)
|
|
1459
|
+
outfile.print(txt)
|
|
1460
|
+
return 0
|
|
1461
|
+
rescue => ex
|
|
1462
|
+
# puts_error "Error writing to outfile '#{filename}'. Error: #{ex}"
|
|
1463
|
+
print "#{red}Error writing to file '#{filename}'. Error: #{ex}#{reset}\n"
|
|
1464
|
+
return 1
|
|
1465
|
+
ensure
|
|
1466
|
+
outfile.close if outfile
|
|
1467
|
+
end
|
|
1468
|
+
end
|
|
1469
|
+
|
|
1470
|
+
def with_stdout_to_file(filename, overwrite=false, access_mode = 'w+', &block)
|
|
1471
|
+
MtnCloud::Logging::DarkPrinter.puts "Writing output to file #{filename}" if MtnCloud::Logging.debug?
|
|
1472
|
+
previous_stdout = my_terminal.stdout
|
|
1473
|
+
outfile = nil
|
|
1474
|
+
begin
|
|
1475
|
+
full_filename = File.expand_path(filename)
|
|
1476
|
+
if File.exist?(full_filename)
|
|
1477
|
+
if !overwrite
|
|
1478
|
+
print "#{red}Output file '#{filename}' already exists.#{reset}\n"
|
|
1479
|
+
print "#{red}Use --overwrite to overwrite the existing file.#{reset}\n"
|
|
1480
|
+
return 1
|
|
1481
|
+
end
|
|
1482
|
+
end
|
|
1483
|
+
if Dir.exist?(full_filename)
|
|
1484
|
+
print "#{red}Output file '#{filename}' is invalid. It is the name of an existing directory.#{reset}\n"
|
|
1485
|
+
return 1
|
|
1486
|
+
end
|
|
1487
|
+
target_dir = File.dirname(full_filename)
|
|
1488
|
+
if !Dir.exist?(target_dir)
|
|
1489
|
+
FileUtils.mkdir_p(target_dir)
|
|
1490
|
+
end
|
|
1491
|
+
outfile = File.open(full_filename, access_mode)
|
|
1492
|
+
# outfile.print(txt)
|
|
1493
|
+
# ok just redirect stdout to the file
|
|
1494
|
+
my_terminal.set_stdout(outfile)
|
|
1495
|
+
result = yield
|
|
1496
|
+
outfile.close if outfile
|
|
1497
|
+
my_terminal.set_stdout(previous_stdout)
|
|
1498
|
+
my_terminal.stdout.flush if my_terminal.stdout
|
|
1499
|
+
# this does not work here.. i dunno why yet, it works in ensure though...
|
|
1500
|
+
# print "#{cyan}Wrote #{File.size(full_filename)} bytes to file #{filename}\n"
|
|
1501
|
+
if result
|
|
1502
|
+
return result
|
|
1503
|
+
else
|
|
1504
|
+
return 0
|
|
1505
|
+
end
|
|
1506
|
+
rescue => ex
|
|
1507
|
+
# puts_error "Error writing to outfile '#{filename}'. Error: #{ex}"
|
|
1508
|
+
print_error "#{red}Error writing to file '#{filename}'. Error: #{ex}#{reset}\n"
|
|
1509
|
+
return 1
|
|
1510
|
+
ensure
|
|
1511
|
+
outfile.close if outfile
|
|
1512
|
+
my_terminal.set_stdout(previous_stdout) if previous_stdout != my_terminal.stdout
|
|
1513
|
+
end
|
|
1514
|
+
end
|
|
1515
|
+
|
|
1516
|
+
def format_percent(val, sig_dig=2, hide_zero=false)
|
|
1517
|
+
if val.nil?
|
|
1518
|
+
return ""
|
|
1519
|
+
end
|
|
1520
|
+
percent_value = val.to_f
|
|
1521
|
+
if percent_value == 0
|
|
1522
|
+
if hide_zero
|
|
1523
|
+
""
|
|
1524
|
+
else
|
|
1525
|
+
return "0%"
|
|
1526
|
+
end
|
|
1527
|
+
else
|
|
1528
|
+
return percent_value.round(sig_dig).to_s + "%"
|
|
1529
|
+
end
|
|
1530
|
+
end
|
|
1531
|
+
|
|
1532
|
+
# returns 0.50 / s ie {{value}} / {{unit}}
|
|
1533
|
+
def format_rate(amount, unit='s', sig_dig=2)
|
|
1534
|
+
if amount.to_f == 0
|
|
1535
|
+
return "0.00" + " / " + unit.to_s
|
|
1536
|
+
else
|
|
1537
|
+
rtn = amount.to_f.round(2).to_s
|
|
1538
|
+
parts = rtn.split('.')
|
|
1539
|
+
# number_str = format_number(parts[0])
|
|
1540
|
+
number_str = parts[0].to_s
|
|
1541
|
+
decimal_str = "#{parts[1]}".ljust(sig_dig, "0")
|
|
1542
|
+
number_str + "." + decimal_str
|
|
1543
|
+
return number_str + "." + decimal_str + " / " + unit.to_s
|
|
1544
|
+
end
|
|
1545
|
+
end
|
|
1546
|
+
|
|
1547
|
+
# convert JSON or YAML string to a map
|
|
1548
|
+
def parse_json_or_yaml(config, parsers = [:json, :yaml])
|
|
1549
|
+
rtn = {success: false, data: nil, error: nil}
|
|
1550
|
+
error = nil
|
|
1551
|
+
config = config.strip
|
|
1552
|
+
if config[0..2] == "---"
|
|
1553
|
+
parsers = [:yaml]
|
|
1554
|
+
end
|
|
1555
|
+
# ok only parse json for strings that start with {, consolidated yaml can look like json and cause issues}
|
|
1556
|
+
if config[0] && config[0].chr == "{" && config[-1] && config[-1].chr == "}"
|
|
1557
|
+
parsers = [:json]
|
|
1558
|
+
end
|
|
1559
|
+
parsers.each do |parser|
|
|
1560
|
+
if parser == :yaml
|
|
1561
|
+
begin
|
|
1562
|
+
# todo: one method to parse and return Hash
|
|
1563
|
+
# load does not raise an exception, it just returns the bad string
|
|
1564
|
+
#YAML.parse(config)
|
|
1565
|
+
config_map = YAML.load(config)
|
|
1566
|
+
if !config_map.is_a?(Hash)
|
|
1567
|
+
raise "Failed to parse config as YAML"
|
|
1568
|
+
end
|
|
1569
|
+
rtn[:data] = config_map
|
|
1570
|
+
rtn[:success] = true
|
|
1571
|
+
break
|
|
1572
|
+
rescue => ex
|
|
1573
|
+
rtn[:error] = ex if rtn[:error].nil?
|
|
1574
|
+
end
|
|
1575
|
+
elsif parser == :json
|
|
1576
|
+
begin
|
|
1577
|
+
config_map = JSON.parse(config)
|
|
1578
|
+
rtn[:data] = config_map
|
|
1579
|
+
rtn[:success] = true
|
|
1580
|
+
break
|
|
1581
|
+
rescue => ex
|
|
1582
|
+
rtn[:error] = ex if rtn[:error].nil?
|
|
1583
|
+
end
|
|
1584
|
+
end
|
|
1585
|
+
end
|
|
1586
|
+
return rtn
|
|
1587
|
+
end
|
|
1588
|
+
|
|
1589
|
+
def parse_yaml_or_json(config, parsers = [:yaml, :json])
|
|
1590
|
+
parse_json_or_yaml(config, parsers)
|
|
1591
|
+
end
|
|
1592
|
+
|
|
1593
|
+
def format_option_types_table(option_types, options={}, domain_name=nil)
|
|
1594
|
+
show_option_source = option_types.find {|it| !it['optionList'].to_s.empty? || !it['optionSource'].to_s.empty? }
|
|
1595
|
+
show_default = option_types.find {|it| !it['defaultValue'].nil? }
|
|
1596
|
+
columns = [
|
|
1597
|
+
{"FIELD LABEL" => lambda {|it| it['fieldLabel'] } },
|
|
1598
|
+
{"FIELD NAME" => lambda {|it|
|
|
1599
|
+
if it['fieldContext'] && it['fieldContext'] != domain_name && it['fieldContext'] != 'domain'
|
|
1600
|
+
"#{it['fieldContext']}.#{it['fieldName']}"
|
|
1601
|
+
else
|
|
1602
|
+
"#{it['fieldName']}"
|
|
1603
|
+
end
|
|
1604
|
+
} },
|
|
1605
|
+
{"TYPE" => lambda {|it| it['type'] } },
|
|
1606
|
+
{"REQUIRED" => lambda {|it| format_boolean it['required'] } },
|
|
1607
|
+
show_option_source ? {"OPTION SOURCE" => lambda {|it|
|
|
1608
|
+
if it['optionList']
|
|
1609
|
+
it['optionList']['name']
|
|
1610
|
+
elsif it['optionSourceType']
|
|
1611
|
+
"#{it['optionSourceType']}/#{it['optionSource']}"
|
|
1612
|
+
else
|
|
1613
|
+
"#{it['optionSource']}"
|
|
1614
|
+
end
|
|
1615
|
+
} } : nil,
|
|
1616
|
+
show_default ? {"DEFAULT" => lambda {|it| it['defaultValue'] } } : nil,
|
|
1617
|
+
].compact
|
|
1618
|
+
as_pretty_table(option_types, columns, options)
|
|
1619
|
+
end
|
|
1620
|
+
|
|
1621
|
+
def format_simple_option_types_table(option_types, options={})
|
|
1622
|
+
as_pretty_table(option_types, {
|
|
1623
|
+
"LABEL" => lambda {|it| it['fieldLabel'] },
|
|
1624
|
+
"NAME" => lambda {|it| it['fieldName'] },
|
|
1625
|
+
"TYPE" => lambda {|it| it['type'] },
|
|
1626
|
+
"REQUIRED" => lambda {|it| format_boolean it['required'] },
|
|
1627
|
+
"DEFAULT" => lambda {|it| it['defaultValue'] },
|
|
1628
|
+
}, options)
|
|
1629
|
+
end
|
|
1630
|
+
|
|
1631
|
+
end
|