shopify-cli 0.9.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/.github/CODEOWNERS +1 -0
- data/.github/CODE_OF_CONDUCT.md +73 -0
- data/.github/CONTRIBUTING.md +51 -0
- data/.github/DESIGN.md +153 -0
- data/.github/ISSUE_TEMPLATE.md +38 -0
- data/.github/PULL_REQUEST_TEMPLATE.md +22 -0
- data/.github/probots.yml +3 -0
- data/.gitignore +19 -0
- data/.rubocop.yml +47 -0
- data/.ruby-version +1 -0
- data/.travis.yml +12 -0
- data/Gemfile +22 -0
- data/Gemfile.lock +77 -0
- data/LICENSE.md +7 -0
- data/README.md +13 -0
- data/Rakefile +101 -0
- data/SECURITY.md +59 -0
- data/Vagrantfile +17 -0
- data/bin/load_shopify.rb +20 -0
- data/bin/shopify +32 -0
- data/dev.yml +17 -0
- data/docs/Gemfile +5 -0
- data/docs/Gemfile.lock +248 -0
- data/docs/_config.yml +16 -0
- data/docs/_data/nav.yml +26 -0
- data/docs/_includes/footer.html +15 -0
- data/docs/_includes/head.html +19 -0
- data/docs/_includes/sidebar_nav.html +22 -0
- data/docs/_includes/toc.html +112 -0
- data/docs/_layouts/default.html +79 -0
- data/docs/app/node/commands/index.md +82 -0
- data/docs/app/node/index.md +35 -0
- data/docs/app/rails/commands/index.md +80 -0
- data/docs/app/rails/index.md +36 -0
- data/docs/core/index.md +70 -0
- data/docs/css/docs.css +157 -0
- data/docs/getting-started/index.md +61 -0
- data/docs/help/start-app/index.md +6 -0
- data/docs/images/header.png +0 -0
- data/docs/index.md +27 -0
- data/docs/installing-ruby.md +28 -0
- data/ext/shopify-cli/extconf.rb +27 -0
- data/install.sh +7 -0
- data/lib/docgen/class_template.md.erb +81 -0
- data/lib/docgen/index_template.md.erb +5 -0
- data/lib/docgen/markdown.rb +101 -0
- data/lib/graphql/admin_introspection.graphql +87 -0
- data/lib/graphql/all_organizations.graphql +19 -0
- data/lib/graphql/all_orgs_with_apps.graphql +30 -0
- data/lib/graphql/api_versions.graphql +6 -0
- data/lib/graphql/convert_dev_to_test_store.graphql +10 -0
- data/lib/graphql/create_app.graphql +20 -0
- data/lib/graphql/create_customer.graphql +9 -0
- data/lib/graphql/create_draft_order.graphql +8 -0
- data/lib/graphql/create_product.graphql +9 -0
- data/lib/graphql/extension_create.graphql +21 -0
- data/lib/graphql/extension_update_draft.graphql +18 -0
- data/lib/graphql/find_organization.graphql +17 -0
- data/lib/graphql/get_app_urls.graphql +6 -0
- data/lib/graphql/update_dashboard_urls.graphql +8 -0
- data/lib/project_types/extension/cli.rb +71 -0
- data/lib/project_types/extension/commands/build.rb +29 -0
- data/lib/project_types/extension/commands/create.rb +49 -0
- data/lib/project_types/extension/commands/extension_command.rb +22 -0
- data/lib/project_types/extension/commands/push.rb +69 -0
- data/lib/project_types/extension/commands/register.rb +78 -0
- data/lib/project_types/extension/commands/serve.rb +24 -0
- data/lib/project_types/extension/commands/tunnel.rb +69 -0
- data/lib/project_types/extension/extension_project.rb +85 -0
- data/lib/project_types/extension/extension_project_keys.rb +10 -0
- data/lib/project_types/extension/features/argo.rb +48 -0
- data/lib/project_types/extension/features/argo_dependencies.rb +28 -0
- data/lib/project_types/extension/features/argo_setup.rb +54 -0
- data/lib/project_types/extension/features/argo_setup_step.rb +31 -0
- data/lib/project_types/extension/features/argo_setup_steps.rb +53 -0
- data/lib/project_types/extension/features/tunnel_url.rb +20 -0
- data/lib/project_types/extension/forms/create.rb +52 -0
- data/lib/project_types/extension/forms/register.rb +48 -0
- data/lib/project_types/extension/messages/message_loading.rb +37 -0
- data/lib/project_types/extension/messages/messages.rb +126 -0
- data/lib/project_types/extension/models/app.rb +14 -0
- data/lib/project_types/extension/models/registration.rb +19 -0
- data/lib/project_types/extension/models/type.rb +76 -0
- data/lib/project_types/extension/models/types/checkout_post_purchase.rb +20 -0
- data/lib/project_types/extension/models/types/subscription_management.rb +20 -0
- data/lib/project_types/extension/models/validation_error.rb +17 -0
- data/lib/project_types/extension/models/version.rb +15 -0
- data/lib/project_types/extension/tasks/converters/registration_converter.rb +26 -0
- data/lib/project_types/extension/tasks/converters/validation_error_converter.rb +25 -0
- data/lib/project_types/extension/tasks/converters/version_converter.rb +28 -0
- data/lib/project_types/extension/tasks/create_extension.rb +31 -0
- data/lib/project_types/extension/tasks/get_apps.rb +34 -0
- data/lib/project_types/extension/tasks/update_draft.rb +29 -0
- data/lib/project_types/extension/tasks/user_errors.rb +45 -0
- data/lib/project_types/node/cli.rb +37 -0
- data/lib/project_types/node/commands/create.rb +117 -0
- data/lib/project_types/node/commands/deploy.rb +22 -0
- data/lib/project_types/node/commands/deploy/heroku.rb +91 -0
- data/lib/project_types/node/commands/generate.rb +51 -0
- data/lib/project_types/node/commands/generate/billing.rb +37 -0
- data/lib/project_types/node/commands/generate/page.rb +55 -0
- data/lib/project_types/node/commands/generate/webhook.rb +33 -0
- data/lib/project_types/node/commands/open.rb +16 -0
- data/lib/project_types/node/commands/populate.rb +23 -0
- data/lib/project_types/node/commands/populate/customer.rb +31 -0
- data/lib/project_types/node/commands/populate/draft_order.rb +28 -0
- data/lib/project_types/node/commands/populate/product.rb +30 -0
- data/lib/project_types/node/commands/serve.rb +45 -0
- data/lib/project_types/node/commands/tunnel.rb +39 -0
- data/lib/project_types/node/forms/create.rb +87 -0
- data/lib/project_types/node/messages/messages.rb +260 -0
- data/lib/project_types/rails/cli.rb +41 -0
- data/lib/project_types/rails/commands/create.rb +126 -0
- data/lib/project_types/rails/commands/deploy.rb +22 -0
- data/lib/project_types/rails/commands/deploy/heroku.rb +113 -0
- data/lib/project_types/rails/commands/generate.rb +49 -0
- data/lib/project_types/rails/commands/generate/webhook.rb +39 -0
- data/lib/project_types/rails/commands/open.rb +16 -0
- data/lib/project_types/rails/commands/populate.rb +23 -0
- data/lib/project_types/rails/commands/populate/customer.rb +31 -0
- data/lib/project_types/rails/commands/populate/draft_order.rb +28 -0
- data/lib/project_types/rails/commands/populate/product.rb +30 -0
- data/lib/project_types/rails/commands/serve.rb +47 -0
- data/lib/project_types/rails/commands/tunnel.rb +39 -0
- data/lib/project_types/rails/forms/create.rb +116 -0
- data/lib/project_types/rails/gem.rb +56 -0
- data/lib/project_types/rails/messages/messages.rb +283 -0
- data/lib/project_types/rails/ruby.rb +17 -0
- data/lib/project_types/script/cli.rb +76 -0
- data/lib/project_types/script/commands/create.rb +45 -0
- data/lib/project_types/script/commands/disable.rb +36 -0
- data/lib/project_types/script/commands/enable.rb +46 -0
- data/lib/project_types/script/commands/push.rb +39 -0
- data/lib/project_types/script/config/extension_points.yml +18 -0
- data/lib/project_types/script/errors.rb +16 -0
- data/lib/project_types/script/forms/create.rb +29 -0
- data/lib/project_types/script/forms/enable.rb +24 -0
- data/lib/project_types/script/forms/push.rb +19 -0
- data/lib/project_types/script/forms/script_form.rb +66 -0
- data/lib/project_types/script/graphql/app_script_update_or_create.graphql +27 -0
- data/lib/project_types/script/graphql/script_service_proxy.graphql +8 -0
- data/lib/project_types/script/graphql/shop_script_delete.graphql +14 -0
- data/lib/project_types/script/graphql/shop_script_update_or_create.graphql +28 -0
- data/lib/project_types/script/layers/application/build_script.rb +43 -0
- data/lib/project_types/script/layers/application/create_script.rb +47 -0
- data/lib/project_types/script/layers/application/disable_script.rb +19 -0
- data/lib/project_types/script/layers/application/enable_script.rb +21 -0
- data/lib/project_types/script/layers/application/extension_points.rb +17 -0
- data/lib/project_types/script/layers/application/project_dependencies.rb +34 -0
- data/lib/project_types/script/layers/application/push_script.rb +30 -0
- data/lib/project_types/script/layers/domain/errors.rb +25 -0
- data/lib/project_types/script/layers/domain/extension_point.rb +29 -0
- data/lib/project_types/script/layers/domain/push_package.rb +29 -0
- data/lib/project_types/script/layers/domain/script.rb +18 -0
- data/lib/project_types/script/layers/infrastructure/assemblyscript_dependency_manager.rb +73 -0
- data/lib/project_types/script/layers/infrastructure/assemblyscript_tsconfig.rb +38 -0
- data/lib/project_types/script/layers/infrastructure/assemblyscript_wasm_builder.rb +39 -0
- data/lib/project_types/script/layers/infrastructure/dependency_manager.rb +36 -0
- data/lib/project_types/script/layers/infrastructure/errors.rb +38 -0
- data/lib/project_types/script/layers/infrastructure/extension_point_repository.rb +31 -0
- data/lib/project_types/script/layers/infrastructure/push_package_repository.rb +47 -0
- data/lib/project_types/script/layers/infrastructure/script_builder.rb +34 -0
- data/lib/project_types/script/layers/infrastructure/script_repository.rb +89 -0
- data/lib/project_types/script/layers/infrastructure/script_service.rb +165 -0
- data/lib/project_types/script/layers/infrastructure/test_suite_repository.rb +59 -0
- data/lib/project_types/script/messages/messages.rb +204 -0
- data/lib/project_types/script/script_project.rb +37 -0
- data/lib/project_types/script/templates/ts/as-pect.config.js +21 -0
- data/lib/project_types/script/ui/error_handler.rb +136 -0
- data/lib/project_types/script/ui/strict_spinner.rb +22 -0
- data/lib/rubygems_plugin.rb +18 -0
- data/lib/shopify-cli/admin_api.rb +99 -0
- data/lib/shopify-cli/admin_api/populate_resource_command.rb +165 -0
- data/lib/shopify-cli/admin_api/schema.rb +32 -0
- data/lib/shopify-cli/api.rb +104 -0
- data/lib/shopify-cli/command.rb +67 -0
- data/lib/shopify-cli/commands.rb +28 -0
- data/lib/shopify-cli/commands/connect.rb +108 -0
- data/lib/shopify-cli/commands/create.rb +50 -0
- data/lib/shopify-cli/commands/help.rb +79 -0
- data/lib/shopify-cli/commands/logout.rb +23 -0
- data/lib/shopify-cli/commands/system.rb +135 -0
- data/lib/shopify-cli/commands/version.rb +15 -0
- data/lib/shopify-cli/context.rb +372 -0
- data/lib/shopify-cli/core.rb +9 -0
- data/lib/shopify-cli/core/entry_point.rb +40 -0
- data/lib/shopify-cli/core/executor.rb +21 -0
- data/lib/shopify-cli/core/help_resolver.rb +20 -0
- data/lib/shopify-cli/core/monorail.rb +118 -0
- data/lib/shopify-cli/db.rb +114 -0
- data/lib/shopify-cli/form.rb +40 -0
- data/lib/shopify-cli/git.rb +141 -0
- data/lib/shopify-cli/helpers.rb +5 -0
- data/lib/shopify-cli/helpers/haikunator.rb +92 -0
- data/lib/shopify-cli/heroku.rb +97 -0
- data/lib/shopify-cli/js_deps.rb +110 -0
- data/lib/shopify-cli/js_system.rb +98 -0
- data/lib/shopify-cli/messages/messages.rb +287 -0
- data/lib/shopify-cli/oauth.rb +192 -0
- data/lib/shopify-cli/oauth/servlet.rb +61 -0
- data/lib/shopify-cli/options.rb +40 -0
- data/lib/shopify-cli/packager.rb +116 -0
- data/lib/shopify-cli/partners_api.rb +114 -0
- data/lib/shopify-cli/partners_api/organizations.rb +32 -0
- data/lib/shopify-cli/process_supervision.rb +187 -0
- data/lib/shopify-cli/project.rb +191 -0
- data/lib/shopify-cli/project_type.rb +83 -0
- data/lib/shopify-cli/resources.rb +5 -0
- data/lib/shopify-cli/resources/env_file.rb +96 -0
- data/lib/shopify-cli/sub_command.rb +15 -0
- data/lib/shopify-cli/task.rb +10 -0
- data/lib/shopify-cli/tasks.rb +32 -0
- data/lib/shopify-cli/tasks/create_api_client.rb +29 -0
- data/lib/shopify-cli/tasks/ensure_dev_store.rb +41 -0
- data/lib/shopify-cli/tasks/ensure_env.rb +31 -0
- data/lib/shopify-cli/tasks/ensure_loopback_url.rb +20 -0
- data/lib/shopify-cli/tasks/update_dashboard_urls.rb +44 -0
- data/lib/shopify-cli/tunnel.rb +154 -0
- data/lib/shopify-cli/version.rb +3 -0
- data/lib/shopify_cli.rb +132 -0
- data/shopify-cli.gemspec +40 -0
- data/shopify.fish +12 -0
- data/shopify.sh +11 -0
- data/vendor/deps/cli-kit/REVISION +1 -0
- data/vendor/deps/cli-kit/lib/cli/kit.rb +60 -0
- data/vendor/deps/cli-kit/lib/cli/kit/autocall.rb +21 -0
- data/vendor/deps/cli-kit/lib/cli/kit/base_command.rb +49 -0
- data/vendor/deps/cli-kit/lib/cli/kit/command_registry.rb +94 -0
- data/vendor/deps/cli-kit/lib/cli/kit/config.rb +133 -0
- data/vendor/deps/cli-kit/lib/cli/kit/error_handler.rb +115 -0
- data/vendor/deps/cli-kit/lib/cli/kit/executor.rb +81 -0
- data/vendor/deps/cli-kit/lib/cli/kit/ini.rb +102 -0
- data/vendor/deps/cli-kit/lib/cli/kit/levenshtein.rb +82 -0
- data/vendor/deps/cli-kit/lib/cli/kit/logger.rb +76 -0
- data/vendor/deps/cli-kit/lib/cli/kit/resolver.rb +60 -0
- data/vendor/deps/cli-kit/lib/cli/kit/ruby_backports/enumerable.rb +6 -0
- data/vendor/deps/cli-kit/lib/cli/kit/support.rb +9 -0
- data/vendor/deps/cli-kit/lib/cli/kit/support/test_helper.rb +244 -0
- data/vendor/deps/cli-kit/lib/cli/kit/system.rb +207 -0
- data/vendor/deps/cli-kit/lib/cli/kit/util.rb +189 -0
- data/vendor/deps/cli-kit/lib/cli/kit/version.rb +5 -0
- data/vendor/deps/cli-ui/REVISION +1 -0
- data/vendor/deps/cli-ui/lib/cli/ui.rb +187 -0
- data/vendor/deps/cli-ui/lib/cli/ui/ansi.rb +153 -0
- data/vendor/deps/cli-ui/lib/cli/ui/box.rb +15 -0
- data/vendor/deps/cli-ui/lib/cli/ui/color.rb +79 -0
- data/vendor/deps/cli-ui/lib/cli/ui/formatter.rb +179 -0
- data/vendor/deps/cli-ui/lib/cli/ui/frame.rb +310 -0
- data/vendor/deps/cli-ui/lib/cli/ui/glyph.rb +78 -0
- data/vendor/deps/cli-ui/lib/cli/ui/progress.rb +88 -0
- data/vendor/deps/cli-ui/lib/cli/ui/prompt.rb +248 -0
- data/vendor/deps/cli-ui/lib/cli/ui/prompt/interactive_options.rb +472 -0
- data/vendor/deps/cli-ui/lib/cli/ui/prompt/options_handler.rb +24 -0
- data/vendor/deps/cli-ui/lib/cli/ui/spinner.rb +48 -0
- data/vendor/deps/cli-ui/lib/cli/ui/spinner/async.rb +40 -0
- data/vendor/deps/cli-ui/lib/cli/ui/spinner/spin_group.rb +241 -0
- data/vendor/deps/cli-ui/lib/cli/ui/stdout_router.rb +227 -0
- data/vendor/deps/cli-ui/lib/cli/ui/terminal.rb +36 -0
- data/vendor/deps/cli-ui/lib/cli/ui/truncater.rb +102 -0
- data/vendor/deps/cli-ui/lib/cli/ui/version.rb +5 -0
- data/vendor/deps/smart_properties/REVISION +1 -0
- data/vendor/deps/smart_properties/lib/smart_properties.rb +174 -0
- data/vendor/deps/smart_properties/lib/smart_properties/errors.rb +114 -0
- data/vendor/deps/smart_properties/lib/smart_properties/property.rb +162 -0
- data/vendor/deps/smart_properties/lib/smart_properties/property_collection.rb +83 -0
- data/vendor/deps/smart_properties/lib/smart_properties/validations.rb +8 -0
- data/vendor/deps/smart_properties/lib/smart_properties/validations/ancestor.rb +27 -0
- data/vendor/deps/smart_properties/lib/smart_properties/version.rb +3 -0
- data/vendor/lib/semantic/LICENSE +20 -0
- data/vendor/lib/semantic/semantic.rb +4 -0
- data/vendor/lib/semantic/version.rb +180 -0
- metadata +374 -0
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
module CLI
|
|
2
|
+
module Kit
|
|
3
|
+
module Util
|
|
4
|
+
class << self
|
|
5
|
+
def snake_case(camel_case, seperator = "_")
|
|
6
|
+
camel_case.to_s # MyCoolThing::MyAPIModule
|
|
7
|
+
.gsub(/::/, '/') # MyCoolThing/MyAPIModule
|
|
8
|
+
.gsub(/([A-Z]+)([A-Z][a-z])/, "\\1#{seperator}\\2") # MyCoolThing::MyAPI_Module
|
|
9
|
+
.gsub(/([a-z\d])([A-Z])/, "\\1#{seperator}\\2") # My_Cool_Thing::My_API_Module
|
|
10
|
+
.downcase # my_cool_thing/my_api_module
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def dash_case(camel_case)
|
|
14
|
+
snake_case(camel_case, '-')
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# The following methods is taken from activesupport
|
|
18
|
+
# All credit for this method goes to the original authors.
|
|
19
|
+
# https://github.com/rails/rails/blob/d66e7835bea9505f7003e5038aa19b6ea95ceea1/activesupport/lib/active_support/core_ext/string/strip.rb
|
|
20
|
+
#
|
|
21
|
+
# Copyright (c) 2005-2018 David Heinemeier Hansson
|
|
22
|
+
#
|
|
23
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
|
24
|
+
# a copy of this software and associated documentation files (the
|
|
25
|
+
# "Software"), to deal in the Software without restriction, including
|
|
26
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
|
27
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
|
28
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
|
29
|
+
# the following conditions:
|
|
30
|
+
#
|
|
31
|
+
# The above copyright notice and this permission notice shall be
|
|
32
|
+
# included in all copies or substantial portions of the Software.
|
|
33
|
+
#
|
|
34
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
35
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
36
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
37
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
38
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
39
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
40
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
41
|
+
#
|
|
42
|
+
# Strips indentation by removing the amount of leading whitespace in the least indented
|
|
43
|
+
# non-empty line in the whole string
|
|
44
|
+
#
|
|
45
|
+
def strip_heredoc(str)
|
|
46
|
+
str.gsub(/^#{str.scan(/^[ \t]*(?=\S)/).min}/, "".freeze)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Joins an array with commas and "and", using the Oxford comma.
|
|
50
|
+
def english_join(array)
|
|
51
|
+
return "" if array.nil?
|
|
52
|
+
return array.join(" and ") if array.length < 3
|
|
53
|
+
|
|
54
|
+
"#{array[0..-2].join(', ')}, and #{array[-1]}"
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Execute a block within the context of a variable enviroment
|
|
58
|
+
#
|
|
59
|
+
def with_environment(environment, value)
|
|
60
|
+
return yield unless environment
|
|
61
|
+
|
|
62
|
+
old_env = ENV[environment]
|
|
63
|
+
begin
|
|
64
|
+
ENV[environment] = value
|
|
65
|
+
yield
|
|
66
|
+
ensure
|
|
67
|
+
old_env ? ENV[environment] = old_env : ENV.delete(environment)
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Converts an integer representing bytes into a human readable format
|
|
72
|
+
#
|
|
73
|
+
def to_filesize(bytes, precision: 2, space: false)
|
|
74
|
+
to_si_scale(bytes, 'B', precision: precision, space: space, factor: 1024)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Converts a number to a human readable format on the SI scale
|
|
78
|
+
#
|
|
79
|
+
def to_si_scale(number, unit = '', factor: 1000, precision: 2, space: false)
|
|
80
|
+
raise ArgumentError, "factor should only be 1000 or 1024" unless [1000, 1024].include?(factor)
|
|
81
|
+
|
|
82
|
+
small_scale = %w(m µ n p f a z y)
|
|
83
|
+
big_scale = %w(k M G T P E Z Y)
|
|
84
|
+
negative = number < 0
|
|
85
|
+
number = number.abs.to_f
|
|
86
|
+
|
|
87
|
+
if number == 0 || number.between?(1, factor)
|
|
88
|
+
prefix = ""
|
|
89
|
+
scale = 0
|
|
90
|
+
else
|
|
91
|
+
scale = Math.log(number, factor).floor
|
|
92
|
+
if number < 1
|
|
93
|
+
index = [-scale - 1, small_scale.length].min
|
|
94
|
+
scale = -(index + 1)
|
|
95
|
+
prefix = small_scale[index]
|
|
96
|
+
else
|
|
97
|
+
index = [scale - 1, big_scale.length].min
|
|
98
|
+
scale = index + 1
|
|
99
|
+
prefix = big_scale[index]
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
divider = (factor**scale)
|
|
104
|
+
fnum = (number / divider).round(precision)
|
|
105
|
+
|
|
106
|
+
# Trim useless decimal
|
|
107
|
+
fnum = fnum.to_i if (fnum.to_i.to_f * divider) == number
|
|
108
|
+
|
|
109
|
+
fnum = -fnum if negative
|
|
110
|
+
prefix = " " + prefix if space
|
|
111
|
+
|
|
112
|
+
"#{fnum}#{prefix}#{unit}"
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Dir.chdir, when invoked in block form, complains when we call chdir
|
|
116
|
+
# again recursively. There's no apparent good reason for this, so we
|
|
117
|
+
# simply implement our own block form of Dir.chdir here.
|
|
118
|
+
def with_dir(dir)
|
|
119
|
+
prev = Dir.pwd
|
|
120
|
+
Dir.chdir(dir)
|
|
121
|
+
yield
|
|
122
|
+
ensure
|
|
123
|
+
Dir.chdir(prev)
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def with_tmp_dir
|
|
127
|
+
require 'fileutils'
|
|
128
|
+
dir = Dir.mktmpdir
|
|
129
|
+
with_dir(dir) do
|
|
130
|
+
yield(dir)
|
|
131
|
+
end
|
|
132
|
+
ensure
|
|
133
|
+
FileUtils.remove_entry(dir)
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# Standard way of checking for CI / Tests
|
|
137
|
+
def testing?
|
|
138
|
+
ci? || ENV['TEST']
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# Set only in IntegrationTest#session; indicates that the process was
|
|
142
|
+
# called by `session.execute` from an IntegrationTest subclass.
|
|
143
|
+
def integration_test_session?
|
|
144
|
+
ENV['INTEGRATION_TEST_SESSION']
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# Standard way of checking for CI
|
|
148
|
+
def ci?
|
|
149
|
+
ENV['CI']
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
# Must call retry_after on the result in order to execute the block
|
|
153
|
+
#
|
|
154
|
+
# Example usage:
|
|
155
|
+
#
|
|
156
|
+
# CLI::Kit::Util.begin do
|
|
157
|
+
# might_raise_if_costly_prep_not_done()
|
|
158
|
+
# end.retry_after(ExpectedError) do
|
|
159
|
+
# costly_prep()
|
|
160
|
+
# end
|
|
161
|
+
def begin(&block_that_might_raise)
|
|
162
|
+
Retrier.new(block_that_might_raise)
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
class Retrier
|
|
167
|
+
def initialize(block_that_might_raise)
|
|
168
|
+
@block_that_might_raise = block_that_might_raise
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def retry_after(exception = StandardError, retries: 1, &before_retry)
|
|
172
|
+
@block_that_might_raise.call
|
|
173
|
+
rescue exception => e
|
|
174
|
+
raise if (retries -= 1) < 0
|
|
175
|
+
if before_retry
|
|
176
|
+
if before_retry.arity == 0
|
|
177
|
+
yield
|
|
178
|
+
else
|
|
179
|
+
yield e
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
retry
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
private_constant :Retrier
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
end
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
35e1b188f19b2ba0ab85bbf48ab983b1f72a361b
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
module CLI
|
|
2
|
+
module UI
|
|
3
|
+
autoload :ANSI, 'cli/ui/ansi'
|
|
4
|
+
autoload :Glyph, 'cli/ui/glyph'
|
|
5
|
+
autoload :Color, 'cli/ui/color'
|
|
6
|
+
autoload :Box, 'cli/ui/box'
|
|
7
|
+
autoload :Frame, 'cli/ui/frame'
|
|
8
|
+
autoload :Progress, 'cli/ui/progress'
|
|
9
|
+
autoload :Prompt, 'cli/ui/prompt'
|
|
10
|
+
autoload :Terminal, 'cli/ui/terminal'
|
|
11
|
+
autoload :Truncater, 'cli/ui/truncater'
|
|
12
|
+
autoload :Formatter, 'cli/ui/formatter'
|
|
13
|
+
autoload :Spinner, 'cli/ui/spinner'
|
|
14
|
+
|
|
15
|
+
# Convenience accessor to +CLI::UI::Spinner::SpinGroup+
|
|
16
|
+
SpinGroup = Spinner::SpinGroup
|
|
17
|
+
|
|
18
|
+
# Glyph resolution using +CLI::UI::Glyph.lookup+
|
|
19
|
+
# Look at the method signature for +Glyph.lookup+ for more details
|
|
20
|
+
#
|
|
21
|
+
# ==== Attributes
|
|
22
|
+
#
|
|
23
|
+
# * +handle+ - handle of the glyph to resolve
|
|
24
|
+
#
|
|
25
|
+
def self.glyph(handle)
|
|
26
|
+
CLI::UI::Glyph.lookup(handle)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Color resolution using +CLI::UI::Color.lookup+
|
|
30
|
+
# Will lookup using +Color.lookup+ if a symbol, otherwise we assume it is a valid color and return it
|
|
31
|
+
#
|
|
32
|
+
# ==== Attributes
|
|
33
|
+
#
|
|
34
|
+
# * +input+ - color to resolve
|
|
35
|
+
#
|
|
36
|
+
def self.resolve_color(input)
|
|
37
|
+
case input
|
|
38
|
+
when Symbol
|
|
39
|
+
CLI::UI::Color.lookup(input)
|
|
40
|
+
else
|
|
41
|
+
input
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Conviencence Method for +CLI::UI::Prompt.confirm+
|
|
46
|
+
#
|
|
47
|
+
# ==== Attributes
|
|
48
|
+
#
|
|
49
|
+
# * +question+ - question to confirm
|
|
50
|
+
#
|
|
51
|
+
def self.confirm(question, **kwargs)
|
|
52
|
+
CLI::UI::Prompt.confirm(question, **kwargs)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Conviencence Method for +CLI::UI::Prompt.ask+
|
|
56
|
+
#
|
|
57
|
+
# ==== Attributes
|
|
58
|
+
#
|
|
59
|
+
# * +question+ - question to ask
|
|
60
|
+
# * +kwargs+ - arugments for +Prompt.ask+
|
|
61
|
+
#
|
|
62
|
+
def self.ask(question, **kwargs)
|
|
63
|
+
CLI::UI::Prompt.ask(question, **kwargs)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Conviencence Method to resolve text using +CLI::UI::Formatter.format+
|
|
67
|
+
# Check +CLI::UI::Formatter::SGR_MAP+ for available formatting options
|
|
68
|
+
#
|
|
69
|
+
# ==== Attributes
|
|
70
|
+
#
|
|
71
|
+
# * +input+ - input to format
|
|
72
|
+
# * +truncate_to+ - number of characters to truncate the string to (or nil)
|
|
73
|
+
#
|
|
74
|
+
def self.resolve_text(input, truncate_to: nil)
|
|
75
|
+
return input if input.nil?
|
|
76
|
+
formatted = CLI::UI::Formatter.new(input).format
|
|
77
|
+
return formatted unless truncate_to
|
|
78
|
+
return CLI::UI::Truncater.call(formatted, truncate_to)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Conviencence Method to format text using +CLI::UI::Formatter.format+
|
|
82
|
+
# Check +CLI::UI::Formatter::SGR_MAP+ for available formatting options
|
|
83
|
+
#
|
|
84
|
+
# https://user-images.githubusercontent.com/3074765/33799827-6d0721a2-dd01-11e7-9ab5-c3d455264afe.png
|
|
85
|
+
# https://user-images.githubusercontent.com/3074765/33799847-9ec03fd0-dd01-11e7-93f7-5f5cc540e61e.png
|
|
86
|
+
#
|
|
87
|
+
# ==== Attributes
|
|
88
|
+
#
|
|
89
|
+
# * +input+ - input to format
|
|
90
|
+
#
|
|
91
|
+
# ==== Options
|
|
92
|
+
#
|
|
93
|
+
# * +enable_color+ - should color be used? default to true unless output is redirected.
|
|
94
|
+
#
|
|
95
|
+
def self.fmt(input, enable_color: enable_color?)
|
|
96
|
+
CLI::UI::Formatter.new(input).format(enable_color: enable_color)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Conviencence Method for +CLI::UI::Frame.open+
|
|
100
|
+
#
|
|
101
|
+
# ==== Attributes
|
|
102
|
+
#
|
|
103
|
+
# * +args+ - arguments for +Frame.open+
|
|
104
|
+
# * +block+ - block for +Frame.open+
|
|
105
|
+
#
|
|
106
|
+
def self.frame(*args, &block)
|
|
107
|
+
CLI::UI::Frame.open(*args, &block)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Conviencence Method for +CLI::UI::Spinner.spin+
|
|
111
|
+
#
|
|
112
|
+
# ==== Attributes
|
|
113
|
+
#
|
|
114
|
+
# * +args+ - arguments for +Spinner.open+
|
|
115
|
+
# * +block+ - block for +Spinner.open+
|
|
116
|
+
#
|
|
117
|
+
def self.spinner(*args, &block)
|
|
118
|
+
CLI::UI::Spinner.spin(*args, &block)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# Conviencence Method to override frame color using +CLI::UI::Frame.with_frame_color+
|
|
122
|
+
#
|
|
123
|
+
# ==== Attributes
|
|
124
|
+
#
|
|
125
|
+
# * +color+ - color to override to
|
|
126
|
+
# * +block+ - block for +Frame.with_frame_color_override+
|
|
127
|
+
#
|
|
128
|
+
def self.with_frame_color(color, &block)
|
|
129
|
+
CLI::UI::Frame.with_frame_color_override(color, &block)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# Duplicate output to a file path
|
|
133
|
+
#
|
|
134
|
+
# ==== Attributes
|
|
135
|
+
#
|
|
136
|
+
# * +path+ - path to duplicate output to
|
|
137
|
+
#
|
|
138
|
+
def self.log_output_to(path)
|
|
139
|
+
if CLI::UI::StdoutRouter.duplicate_output_to
|
|
140
|
+
raise "multiple logs not allowed"
|
|
141
|
+
end
|
|
142
|
+
CLI::UI::StdoutRouter.duplicate_output_to = File.open(path, 'w')
|
|
143
|
+
yield
|
|
144
|
+
ensure
|
|
145
|
+
if file_descriptor = CLI::UI::StdoutRouter.duplicate_output_to
|
|
146
|
+
file_descriptor.close
|
|
147
|
+
CLI::UI::StdoutRouter.duplicate_output_to = nil
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
# Disable all framing within a block
|
|
152
|
+
#
|
|
153
|
+
# ==== Attributes
|
|
154
|
+
#
|
|
155
|
+
# * +block+ - block in which to disable frames
|
|
156
|
+
#
|
|
157
|
+
def self.raw
|
|
158
|
+
prev = Thread.current[:no_cliui_frame_inset]
|
|
159
|
+
Thread.current[:no_cliui_frame_inset] = true
|
|
160
|
+
yield
|
|
161
|
+
ensure
|
|
162
|
+
Thread.current[:no_cliui_frame_inset] = prev
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
# Check whether colour is enabled in Formatter output. By default, colour
|
|
166
|
+
# is enabled when STDOUT is a TTY; that is, when output has not been
|
|
167
|
+
# redirected to another program or to a file.
|
|
168
|
+
#
|
|
169
|
+
def self.enable_color?
|
|
170
|
+
@enable_color
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
# Turn colour output in Formatter on or off.
|
|
174
|
+
#
|
|
175
|
+
# ==== Attributes
|
|
176
|
+
#
|
|
177
|
+
# * +bool+ - true or false; enable or disable colour.
|
|
178
|
+
#
|
|
179
|
+
def self.enable_color=(bool)
|
|
180
|
+
@enable_color = !!bool
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
self.enable_color = $stdout.tty?
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
require 'cli/ui/stdout_router'
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
require 'cli/ui'
|
|
2
|
+
|
|
3
|
+
module CLI
|
|
4
|
+
module UI
|
|
5
|
+
module ANSI
|
|
6
|
+
ESC = "\x1b"
|
|
7
|
+
|
|
8
|
+
# ANSI escape sequences (like \x1b[31m) have zero width.
|
|
9
|
+
# when calculating the padding width, we must exclude them.
|
|
10
|
+
# This also implements a basic version of utf8 character width calculation like
|
|
11
|
+
# we could get for real from something like utf8proc.
|
|
12
|
+
#
|
|
13
|
+
def self.printing_width(str)
|
|
14
|
+
zwj = false
|
|
15
|
+
strip_codes(str).codepoints.reduce(0) do |acc, cp|
|
|
16
|
+
if zwj
|
|
17
|
+
zwj = false
|
|
18
|
+
next acc
|
|
19
|
+
end
|
|
20
|
+
case cp
|
|
21
|
+
when 0x200d # zero-width joiner
|
|
22
|
+
zwj = true
|
|
23
|
+
acc
|
|
24
|
+
else
|
|
25
|
+
acc + 1
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Strips ANSI codes from a str
|
|
31
|
+
#
|
|
32
|
+
# ==== Attributes
|
|
33
|
+
#
|
|
34
|
+
# - +str+ - The string from which to strip codes
|
|
35
|
+
#
|
|
36
|
+
def self.strip_codes(str)
|
|
37
|
+
str.gsub(/\x1b\[[\d;]+[A-z]|\r/, '')
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Returns an ANSI control sequence
|
|
41
|
+
#
|
|
42
|
+
# ==== Attributes
|
|
43
|
+
#
|
|
44
|
+
# - +args+ - Argument to pass to the ANSI control sequence
|
|
45
|
+
# - +cmd+ - ANSI control sequence Command
|
|
46
|
+
#
|
|
47
|
+
def self.control(args, cmd)
|
|
48
|
+
ESC + "[" + args + cmd
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# https://en.wikipedia.org/wiki/ANSI_escape_code#graphics
|
|
52
|
+
def self.sgr(params)
|
|
53
|
+
control(params.to_s, 'm')
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Cursor Movement
|
|
57
|
+
|
|
58
|
+
# Move the cursor up n lines
|
|
59
|
+
#
|
|
60
|
+
# ==== Attributes
|
|
61
|
+
#
|
|
62
|
+
# * +n+ - number of lines by which to move the cursor up
|
|
63
|
+
#
|
|
64
|
+
def self.cursor_up(n = 1)
|
|
65
|
+
return '' if n.zero?
|
|
66
|
+
control(n.to_s, 'A')
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Move the cursor down n lines
|
|
70
|
+
#
|
|
71
|
+
# ==== Attributes
|
|
72
|
+
#
|
|
73
|
+
# * +n+ - number of lines by which to move the cursor down
|
|
74
|
+
#
|
|
75
|
+
def self.cursor_down(n = 1)
|
|
76
|
+
return '' if n.zero?
|
|
77
|
+
control(n.to_s, 'B')
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Move the cursor forward n columns
|
|
81
|
+
#
|
|
82
|
+
# ==== Attributes
|
|
83
|
+
#
|
|
84
|
+
# * +n+ - number of columns by which to move the cursor forward
|
|
85
|
+
#
|
|
86
|
+
def self.cursor_forward(n = 1)
|
|
87
|
+
return '' if n.zero?
|
|
88
|
+
control(n.to_s, 'C')
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Move the cursor back n columns
|
|
92
|
+
#
|
|
93
|
+
# ==== Attributes
|
|
94
|
+
#
|
|
95
|
+
# * +n+ - number of columns by which to move the cursor back
|
|
96
|
+
#
|
|
97
|
+
def self.cursor_back(n = 1)
|
|
98
|
+
return '' if n.zero?
|
|
99
|
+
control(n.to_s, 'D')
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# Move the cursor to a specific column
|
|
103
|
+
#
|
|
104
|
+
# ==== Attributes
|
|
105
|
+
#
|
|
106
|
+
# * +n+ - The column to move to
|
|
107
|
+
#
|
|
108
|
+
def self.cursor_horizontal_absolute(n = 1)
|
|
109
|
+
control(n.to_s, 'G')
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# Show the cursor
|
|
113
|
+
#
|
|
114
|
+
def self.show_cursor
|
|
115
|
+
control('', "?25h")
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# Hide the cursor
|
|
119
|
+
#
|
|
120
|
+
def self.hide_cursor
|
|
121
|
+
control('', "?25l")
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# Save the cursor position
|
|
125
|
+
#
|
|
126
|
+
def self.cursor_save
|
|
127
|
+
control('', 's')
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# Restore the saved cursor position
|
|
131
|
+
#
|
|
132
|
+
def self.cursor_restore
|
|
133
|
+
control('', 'u')
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# Move to the next line
|
|
137
|
+
#
|
|
138
|
+
def self.next_line
|
|
139
|
+
cursor_down + control('1', 'G')
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# Move to the previous line
|
|
143
|
+
#
|
|
144
|
+
def self.previous_line
|
|
145
|
+
cursor_up + control('1', 'G')
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def self.clear_to_end_of_line
|
|
149
|
+
control('', 'K')
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
end
|