fluid_cli 0.1.2
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/README.md +1 -0
- data/dev.yml +5 -0
- data/exe/fluid +24 -0
- data/lib/fluid_cli/api.rb +135 -0
- data/lib/fluid_cli/assets/post_auth_page/index.html.erb +34 -0
- data/lib/fluid_cli/assets/post_auth_page/style.css +58 -0
- data/lib/fluid_cli/command.rb +55 -0
- data/lib/fluid_cli/commands/help.rb +21 -0
- data/lib/fluid_cli/commands/login.rb +30 -0
- data/lib/fluid_cli/commands/logout.rb +38 -0
- data/lib/fluid_cli/commands/switch.rb +23 -0
- data/lib/fluid_cli/commands/theme/common/company_helper.rb +15 -0
- data/lib/fluid_cli/commands/theme/common/root_helper.rb +95 -0
- data/lib/fluid_cli/commands/theme/dev.rb +61 -0
- data/lib/fluid_cli/commands/theme/help.rb +21 -0
- data/lib/fluid_cli/commands/theme/init.rb +46 -0
- data/lib/fluid_cli/commands/theme/pull.rb +68 -0
- data/lib/fluid_cli/commands/theme/push.rb +132 -0
- data/lib/fluid_cli/commands/theme.rb +23 -0
- data/lib/fluid_cli/commands/whoami.rb +23 -0
- data/lib/fluid_cli/commands.rb +19 -0
- data/lib/fluid_cli/company_switcher.rb +69 -0
- data/lib/fluid_cli/context.rb +691 -0
- data/lib/fluid_cli/db.rb +114 -0
- data/lib/fluid_cli/entry_point.rb +10 -0
- data/lib/fluid_cli/environment.rb +32 -0
- data/lib/fluid_cli/file_system_listener.rb +29 -0
- data/lib/fluid_cli/form.rb +42 -0
- data/lib/fluid_cli/git.rb +319 -0
- data/lib/fluid_cli/http_request.rb +54 -0
- data/lib/fluid_cli/identity_auth/servlet.rb +39 -0
- data/lib/fluid_cli/identity_auth.rb +126 -0
- data/lib/fluid_cli/options.rb +38 -0
- data/lib/fluid_cli/theme/dev_server/certificate_manager.rb +79 -0
- data/lib/fluid_cli/theme/dev_server/errors.rb +9 -0
- data/lib/fluid_cli/theme/dev_server/header_hash.rb +98 -0
- data/lib/fluid_cli/theme/dev_server/hooks/file_change_hook.rb +39 -0
- data/lib/fluid_cli/theme/dev_server/hot_reload/resources/hot-reload-no-script.html +27 -0
- data/lib/fluid_cli/theme/dev_server/hot_reload/resources/hot_reload.js +28 -0
- data/lib/fluid_cli/theme/dev_server/hot_reload/resources/sse_client.js +43 -0
- data/lib/fluid_cli/theme/dev_server/hot_reload/resources/theme.js +16 -0
- data/lib/fluid_cli/theme/dev_server/hot_reload/script_injector.rb +54 -0
- data/lib/fluid_cli/theme/dev_server/hot_reload.rb +75 -0
- data/lib/fluid_cli/theme/dev_server/local_assets.rb +92 -0
- data/lib/fluid_cli/theme/dev_server/proxy.rb +235 -0
- data/lib/fluid_cli/theme/dev_server/proxy_param_builder.rb +82 -0
- data/lib/fluid_cli/theme/dev_server/reload_mode.rb +34 -0
- data/lib/fluid_cli/theme/dev_server/sse.rb +75 -0
- data/lib/fluid_cli/theme/dev_server/watcher.rb +57 -0
- data/lib/fluid_cli/theme/dev_server/web_server.rb +140 -0
- data/lib/fluid_cli/theme/dev_server.rb +289 -0
- data/lib/fluid_cli/theme/development_theme.rb +101 -0
- data/lib/fluid_cli/theme/file.rb +105 -0
- data/lib/fluid_cli/theme/forms/select.rb +33 -0
- data/lib/fluid_cli/theme/mime_type.rb +34 -0
- data/lib/fluid_cli/theme/presenters/theme_presenter.rb +49 -0
- data/lib/fluid_cli/theme/presenters/themes_presenter.rb +31 -0
- data/lib/fluid_cli/theme/root.rb +62 -0
- data/lib/fluid_cli/theme/syncer/checksums.rb +66 -0
- data/lib/fluid_cli/theme/syncer/downloader.rb +54 -0
- data/lib/fluid_cli/theme/syncer/error_reporter.rb +45 -0
- data/lib/fluid_cli/theme/syncer/merger.rb +53 -0
- data/lib/fluid_cli/theme/syncer/operation.rb +58 -0
- data/lib/fluid_cli/theme/syncer/standard_reporter.rb +32 -0
- data/lib/fluid_cli/theme/syncer/unsupported_script_warning.rb +90 -0
- data/lib/fluid_cli/theme/syncer/uploader/forms/apply_to_all.rb +41 -0
- data/lib/fluid_cli/theme/syncer/uploader/forms/apply_to_all_form.rb +37 -0
- data/lib/fluid_cli/theme/syncer/uploader/forms/base_strategy_form.rb +64 -0
- data/lib/fluid_cli/theme/syncer/uploader/forms/select_delete_strategy.rb +29 -0
- data/lib/fluid_cli/theme/syncer/uploader/forms/select_update_strategy.rb +30 -0
- data/lib/fluid_cli/theme/syncer/uploader/json_delete_handler.rb +49 -0
- data/lib/fluid_cli/theme/syncer/uploader/json_update_handler.rb +71 -0
- data/lib/fluid_cli/theme/syncer/uploader.rb +105 -0
- data/lib/fluid_cli/theme/syncer.rb +412 -0
- data/lib/fluid_cli/theme/theme.rb +186 -0
- data/lib/fluid_cli/theme/ui/sync_progress_bar.rb +22 -0
- data/lib/fluid_cli/thread_pool/job.rb +35 -0
- data/lib/fluid_cli/thread_pool.rb +49 -0
- data/lib/fluid_cli/version.rb +3 -0
- data/lib/fluid_cli.rb +59 -0
- data/vendor/deps/base64/.document +5 -0
- data/vendor/deps/base64/.gitignore +9 -0
- data/vendor/deps/base64/BSDL +22 -0
- data/vendor/deps/base64/COPYING +56 -0
- data/vendor/deps/base64/Gemfile +9 -0
- data/vendor/deps/base64/LEGAL +60 -0
- data/vendor/deps/base64/README.md +48 -0
- data/vendor/deps/base64/Rakefile +31 -0
- data/vendor/deps/base64/base64.gemspec +28 -0
- data/vendor/deps/base64/bin/console +14 -0
- data/vendor/deps/base64/bin/setup +8 -0
- data/vendor/deps/base64/lib/base64.rb +382 -0
- data/vendor/deps/base64/sig/base64.rbs +358 -0
- data/vendor/deps/base64/test/base64/test_base64.rb +115 -0
- data/vendor/deps/base64/test_sig/test_base64.rb +44 -0
- data/vendor/deps/cli-kit/REVISION +1 -0
- data/vendor/deps/cli-kit/lib/cli/kit/args/definition.rb +286 -0
- data/vendor/deps/cli-kit/lib/cli/kit/args/evaluation.rb +215 -0
- data/vendor/deps/cli-kit/lib/cli/kit/args/parser/node.rb +128 -0
- data/vendor/deps/cli-kit/lib/cli/kit/args/parser.rb +125 -0
- data/vendor/deps/cli-kit/lib/cli/kit/args/tokenizer.rb +130 -0
- data/vendor/deps/cli-kit/lib/cli/kit/args.rb +16 -0
- data/vendor/deps/cli-kit/lib/cli/kit/base_command.rb +30 -0
- data/vendor/deps/cli-kit/lib/cli/kit/command_help.rb +268 -0
- data/vendor/deps/cli-kit/lib/cli/kit/command_registry.rb +150 -0
- data/vendor/deps/cli-kit/lib/cli/kit/config.rb +137 -0
- data/vendor/deps/cli-kit/lib/cli/kit/core_ext.rb +28 -0
- data/vendor/deps/cli-kit/lib/cli/kit/error_handler.rb +166 -0
- data/vendor/deps/cli-kit/lib/cli/kit/executor.rb +92 -0
- data/vendor/deps/cli-kit/lib/cli/kit/ini.rb +91 -0
- data/vendor/deps/cli-kit/lib/cli/kit/levenshtein.rb +92 -0
- data/vendor/deps/cli-kit/lib/cli/kit/logger.rb +94 -0
- data/vendor/deps/cli-kit/lib/cli/kit/opts.rb +248 -0
- data/vendor/deps/cli-kit/lib/cli/kit/parse_args.rb +55 -0
- data/vendor/deps/cli-kit/lib/cli/kit/resolver.rb +66 -0
- data/vendor/deps/cli-kit/lib/cli/kit/support/test_helper.rb +260 -0
- data/vendor/deps/cli-kit/lib/cli/kit/support.rb +11 -0
- data/vendor/deps/cli-kit/lib/cli/kit/system.rb +290 -0
- data/vendor/deps/cli-kit/lib/cli/kit/util.rb +118 -0
- data/vendor/deps/cli-kit/lib/cli/kit/version.rb +7 -0
- data/vendor/deps/cli-kit/lib/cli/kit.rb +139 -0
- data/vendor/deps/cli-ui/REVISION +1 -0
- data/vendor/deps/cli-ui/lib/cli/ui/ansi.rb +218 -0
- data/vendor/deps/cli-ui/lib/cli/ui/color.rb +101 -0
- data/vendor/deps/cli-ui/lib/cli/ui/formatter.rb +219 -0
- data/vendor/deps/cli-ui/lib/cli/ui/frame/frame_stack.rb +67 -0
- data/vendor/deps/cli-ui/lib/cli/ui/frame/frame_style/box.rb +179 -0
- data/vendor/deps/cli-ui/lib/cli/ui/frame/frame_style/bracket.rb +152 -0
- data/vendor/deps/cli-ui/lib/cli/ui/frame/frame_style.rb +127 -0
- data/vendor/deps/cli-ui/lib/cli/ui/frame.rb +286 -0
- data/vendor/deps/cli-ui/lib/cli/ui/glyph.rb +92 -0
- data/vendor/deps/cli-ui/lib/cli/ui/os.rb +63 -0
- data/vendor/deps/cli-ui/lib/cli/ui/printer.rb +64 -0
- data/vendor/deps/cli-ui/lib/cli/ui/progress.rb +132 -0
- data/vendor/deps/cli-ui/lib/cli/ui/progress_reporter.rb +209 -0
- data/vendor/deps/cli-ui/lib/cli/ui/prompt/interactive_options.rb +583 -0
- data/vendor/deps/cli-ui/lib/cli/ui/prompt/options_handler.rb +36 -0
- data/vendor/deps/cli-ui/lib/cli/ui/prompt.rb +381 -0
- data/vendor/deps/cli-ui/lib/cli/ui/spinner/async.rb +48 -0
- data/vendor/deps/cli-ui/lib/cli/ui/spinner/spin_group.rb +602 -0
- data/vendor/deps/cli-ui/lib/cli/ui/spinner.rb +79 -0
- data/vendor/deps/cli-ui/lib/cli/ui/stdout_router.rb +399 -0
- data/vendor/deps/cli-ui/lib/cli/ui/table.rb +83 -0
- data/vendor/deps/cli-ui/lib/cli/ui/terminal.rb +55 -0
- data/vendor/deps/cli-ui/lib/cli/ui/truncater.rb +106 -0
- data/vendor/deps/cli-ui/lib/cli/ui/version.rb +8 -0
- data/vendor/deps/cli-ui/lib/cli/ui/widgets/base.rb +46 -0
- data/vendor/deps/cli-ui/lib/cli/ui/widgets/status.rb +79 -0
- data/vendor/deps/cli-ui/lib/cli/ui/widgets.rb +89 -0
- data/vendor/deps/cli-ui/lib/cli/ui/work_queue.rb +142 -0
- data/vendor/deps/cli-ui/lib/cli/ui/wrap.rb +61 -0
- data/vendor/deps/cli-ui/lib/cli/ui.rb +359 -0
- data/vendor/deps/cli-ui/vendor/reentrant_mutex.rb +78 -0
- data/vendor/deps/debug/CONTRIBUTING.md +573 -0
- data/vendor/deps/debug/Gemfile +10 -0
- data/vendor/deps/debug/LICENSE.txt +22 -0
- data/vendor/deps/debug/README.md +996 -0
- data/vendor/deps/debug/Rakefile +57 -0
- data/vendor/deps/debug/TODO.md +23 -0
- data/vendor/deps/debug/debug.gemspec +33 -0
- data/vendor/deps/debug/exe/rdbg +53 -0
- data/vendor/deps/debug/ext/debug/Makefile +273 -0
- data/vendor/deps/debug/ext/debug/debug.c +228 -0
- data/vendor/deps/debug/ext/debug/debug_version.h +1 -0
- data/vendor/deps/debug/ext/debug/extconf.rb +27 -0
- data/vendor/deps/debug/ext/debug/iseq_collector.c +93 -0
- data/vendor/deps/debug/lib/debug/abbrev_command.rb +77 -0
- data/vendor/deps/debug/lib/debug/breakpoint.rb +556 -0
- data/vendor/deps/debug/lib/debug/client.rb +263 -0
- data/vendor/deps/debug/lib/debug/color.rb +123 -0
- data/vendor/deps/debug/lib/debug/config.rb +592 -0
- data/vendor/deps/debug/lib/debug/console.rb +224 -0
- data/vendor/deps/debug/lib/debug/dap_custom/traceInspector.rb +336 -0
- data/vendor/deps/debug/lib/debug/debug.bundle +0 -0
- data/vendor/deps/debug/lib/debug/frame_info.rb +190 -0
- data/vendor/deps/debug/lib/debug/irb_integration.rb +37 -0
- data/vendor/deps/debug/lib/debug/local.rb +115 -0
- data/vendor/deps/debug/lib/debug/open.rb +13 -0
- data/vendor/deps/debug/lib/debug/open_nonstop.rb +15 -0
- data/vendor/deps/debug/lib/debug/prelude.rb +50 -0
- data/vendor/deps/debug/lib/debug/server.rb +534 -0
- data/vendor/deps/debug/lib/debug/server_cdp.rb +1348 -0
- data/vendor/deps/debug/lib/debug/server_dap.rb +1108 -0
- data/vendor/deps/debug/lib/debug/session.rb +2667 -0
- data/vendor/deps/debug/lib/debug/source_repository.rb +150 -0
- data/vendor/deps/debug/lib/debug/start.rb +5 -0
- data/vendor/deps/debug/lib/debug/thread_client.rb +1457 -0
- data/vendor/deps/debug/lib/debug/tracer.rb +241 -0
- data/vendor/deps/debug/lib/debug/version.rb +5 -0
- data/vendor/deps/debug/lib/debug.rb +9 -0
- data/vendor/deps/debug/misc/README.md.erb +660 -0
- data/vendor/deps/listen/.github/release-drafter.yml +17 -0
- data/vendor/deps/listen/.github/workflows/development.yml +67 -0
- data/vendor/deps/listen/.github/workflows/push.yml +12 -0
- data/vendor/deps/listen/.gitignore +28 -0
- data/vendor/deps/listen/.rspec +3 -0
- data/vendor/deps/listen/.rubocop.yml +283 -0
- data/vendor/deps/listen/.yardopts +11 -0
- data/vendor/deps/listen/CHANGELOG.md +1 -0
- data/vendor/deps/listen/CONTRIBUTING.md +45 -0
- data/vendor/deps/listen/Gemfile +33 -0
- data/vendor/deps/listen/Guardfile +26 -0
- data/vendor/deps/listen/LICENSE.txt +22 -0
- data/vendor/deps/listen/README.md +490 -0
- data/vendor/deps/listen/Rakefile +154 -0
- data/vendor/deps/listen/bin/listen +11 -0
- data/vendor/deps/listen/lib/listen/adapter/base.rb +129 -0
- data/vendor/deps/listen/lib/listen/adapter/bsd.rb +104 -0
- data/vendor/deps/listen/lib/listen/adapter/config.rb +31 -0
- data/vendor/deps/listen/lib/listen/adapter/darwin.rb +77 -0
- data/vendor/deps/listen/lib/listen/adapter/linux.rb +108 -0
- data/vendor/deps/listen/lib/listen/adapter/polling.rb +40 -0
- data/vendor/deps/listen/lib/listen/adapter/windows.rb +96 -0
- data/vendor/deps/listen/lib/listen/adapter.rb +43 -0
- data/vendor/deps/listen/lib/listen/backend.rb +40 -0
- data/vendor/deps/listen/lib/listen/change.rb +69 -0
- data/vendor/deps/listen/lib/listen/cli.rb +65 -0
- data/vendor/deps/listen/lib/listen/directory.rb +93 -0
- data/vendor/deps/listen/lib/listen/error.rb +11 -0
- data/vendor/deps/listen/lib/listen/event/config.rb +39 -0
- data/vendor/deps/listen/lib/listen/event/loop.rb +92 -0
- data/vendor/deps/listen/lib/listen/event/processor.rb +128 -0
- data/vendor/deps/listen/lib/listen/event/queue.rb +52 -0
- data/vendor/deps/listen/lib/listen/file.rb +95 -0
- data/vendor/deps/listen/lib/listen/fsm.rb +131 -0
- data/vendor/deps/listen/lib/listen/listener/config.rb +41 -0
- data/vendor/deps/listen/lib/listen/listener.rb +136 -0
- data/vendor/deps/listen/lib/listen/logger.rb +65 -0
- data/vendor/deps/listen/lib/listen/monotonic_time.rb +27 -0
- data/vendor/deps/listen/lib/listen/options.rb +24 -0
- data/vendor/deps/listen/lib/listen/queue_optimizer.rb +129 -0
- data/vendor/deps/listen/lib/listen/record/entry.rb +66 -0
- data/vendor/deps/listen/lib/listen/record/symlink_detector.rb +47 -0
- data/vendor/deps/listen/lib/listen/record.rb +122 -0
- data/vendor/deps/listen/lib/listen/silencer/controller.rb +50 -0
- data/vendor/deps/listen/lib/listen/silencer.rb +106 -0
- data/vendor/deps/listen/lib/listen/thread.rb +54 -0
- data/vendor/deps/listen/lib/listen/version.rb +5 -0
- data/vendor/deps/listen/lib/listen.rb +47 -0
- data/vendor/deps/listen/listen.gemspec +40 -0
- data/vendor/deps/listen/spec/acceptance/listen_spec.rb +320 -0
- data/vendor/deps/listen/spec/lib/listen/adapter/base_spec.rb +101 -0
- data/vendor/deps/listen/spec/lib/listen/adapter/bsd_spec.rb +13 -0
- data/vendor/deps/listen/spec/lib/listen/adapter/config_spec.rb +122 -0
- data/vendor/deps/listen/spec/lib/listen/adapter/darwin_spec.rb +82 -0
- data/vendor/deps/listen/spec/lib/listen/adapter/linux_spec.rb +199 -0
- data/vendor/deps/listen/spec/lib/listen/adapter/polling_spec.rb +83 -0
- data/vendor/deps/listen/spec/lib/listen/adapter/windows_spec.rb +13 -0
- data/vendor/deps/listen/spec/lib/listen/adapter_spec.rb +69 -0
- data/vendor/deps/listen/spec/lib/listen/backend_spec.rb +82 -0
- data/vendor/deps/listen/spec/lib/listen/change_spec.rb +102 -0
- data/vendor/deps/listen/spec/lib/listen/cli_spec.rb +116 -0
- data/vendor/deps/listen/spec/lib/listen/directory_spec.rb +284 -0
- data/vendor/deps/listen/spec/lib/listen/event/config_spec.rb +33 -0
- data/vendor/deps/listen/spec/lib/listen/event/loop_spec.rb +118 -0
- data/vendor/deps/listen/spec/lib/listen/event/processor_spec.rb +250 -0
- data/vendor/deps/listen/spec/lib/listen/event/queue_spec.rb +118 -0
- data/vendor/deps/listen/spec/lib/listen/file_spec.rb +254 -0
- data/vendor/deps/listen/spec/lib/listen/fsm_spec.rb +147 -0
- data/vendor/deps/listen/spec/lib/listen/listener/config_spec.rb +29 -0
- data/vendor/deps/listen/spec/lib/listen/listener_spec.rb +321 -0
- data/vendor/deps/listen/spec/lib/listen/logger_spec.rb +212 -0
- data/vendor/deps/listen/spec/lib/listen/monotonic_time_spec.rb +58 -0
- data/vendor/deps/listen/spec/lib/listen/queue_optimizer_spec.rb +111 -0
- data/vendor/deps/listen/spec/lib/listen/record_spec.rb +424 -0
- data/vendor/deps/listen/spec/lib/listen/silencer/controller_spec.rb +97 -0
- data/vendor/deps/listen/spec/lib/listen/silencer_spec.rb +109 -0
- data/vendor/deps/listen/spec/lib/listen/thread_spec.rb +133 -0
- data/vendor/deps/listen/spec/lib/listen_spec.rb +25 -0
- data/vendor/deps/listen/spec/spec_helper.rb +49 -0
- data/vendor/deps/listen/spec/support/acceptance_helper.rb +260 -0
- data/vendor/deps/listen/spec/support/fixtures_helper.rb +32 -0
- data/vendor/deps/listen/spec/support/platform_helper.rb +17 -0
- data/vendor/deps/observer/.github/dependabot.yml +6 -0
- data/vendor/deps/observer/.github/workflows/test.yml +33 -0
- data/vendor/deps/observer/.gitignore +8 -0
- data/vendor/deps/observer/BSDL +22 -0
- data/vendor/deps/observer/COPYING +56 -0
- data/vendor/deps/observer/Gemfile +9 -0
- data/vendor/deps/observer/README.md +139 -0
- data/vendor/deps/observer/Rakefile +10 -0
- data/vendor/deps/observer/bin/console +14 -0
- data/vendor/deps/observer/bin/setup +8 -0
- data/vendor/deps/observer/lib/observer.rb +229 -0
- data/vendor/deps/observer/observer.gemspec +32 -0
- data/vendor/deps/observer/test/test_observer.rb +66 -0
- data/vendor/deps/webrick/.gitignore +9 -0
- data/vendor/deps/webrick/Gemfile +3 -0
- data/vendor/deps/webrick/LICENSE.txt +22 -0
- data/vendor/deps/webrick/README.md +61 -0
- data/vendor/deps/webrick/Rakefile +10 -0
- data/vendor/deps/webrick/lib/webrick/accesslog.rb +157 -0
- data/vendor/deps/webrick/lib/webrick/cgi.rb +313 -0
- data/vendor/deps/webrick/lib/webrick/compat.rb +36 -0
- data/vendor/deps/webrick/lib/webrick/config.rb +158 -0
- data/vendor/deps/webrick/lib/webrick/cookie.rb +172 -0
- data/vendor/deps/webrick/lib/webrick/htmlutils.rb +30 -0
- data/vendor/deps/webrick/lib/webrick/httpauth/authenticator.rb +117 -0
- data/vendor/deps/webrick/lib/webrick/httpauth/basicauth.rb +116 -0
- data/vendor/deps/webrick/lib/webrick/httpauth/digestauth.rb +395 -0
- data/vendor/deps/webrick/lib/webrick/httpauth/htdigest.rb +132 -0
- data/vendor/deps/webrick/lib/webrick/httpauth/htgroup.rb +97 -0
- data/vendor/deps/webrick/lib/webrick/httpauth/htpasswd.rb +158 -0
- data/vendor/deps/webrick/lib/webrick/httpauth/userdb.rb +53 -0
- data/vendor/deps/webrick/lib/webrick/httpauth.rb +96 -0
- data/vendor/deps/webrick/lib/webrick/httpproxy.rb +354 -0
- data/vendor/deps/webrick/lib/webrick/httprequest.rb +636 -0
- data/vendor/deps/webrick/lib/webrick/httpresponse.rb +564 -0
- data/vendor/deps/webrick/lib/webrick/https.rb +152 -0
- data/vendor/deps/webrick/lib/webrick/httpserver.rb +294 -0
- data/vendor/deps/webrick/lib/webrick/httpservlet/abstract.rb +152 -0
- data/vendor/deps/webrick/lib/webrick/httpservlet/cgi_runner.rb +47 -0
- data/vendor/deps/webrick/lib/webrick/httpservlet/cgihandler.rb +126 -0
- data/vendor/deps/webrick/lib/webrick/httpservlet/erbhandler.rb +88 -0
- data/vendor/deps/webrick/lib/webrick/httpservlet/filehandler.rb +552 -0
- data/vendor/deps/webrick/lib/webrick/httpservlet/prochandler.rb +47 -0
- data/vendor/deps/webrick/lib/webrick/httpservlet.rb +23 -0
- data/vendor/deps/webrick/lib/webrick/httpstatus.rb +194 -0
- data/vendor/deps/webrick/lib/webrick/httputils.rb +512 -0
- data/vendor/deps/webrick/lib/webrick/httpversion.rb +76 -0
- data/vendor/deps/webrick/lib/webrick/log.rb +156 -0
- data/vendor/deps/webrick/lib/webrick/server.rb +381 -0
- data/vendor/deps/webrick/lib/webrick/ssl.rb +215 -0
- data/vendor/deps/webrick/lib/webrick/utils.rb +265 -0
- data/vendor/deps/webrick/lib/webrick/version.rb +18 -0
- data/vendor/deps/webrick/lib/webrick.rb +232 -0
- data/vendor/deps/webrick/webrick.gemspec +74 -0
- metadata +412 -0
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
require 'cli/kit'
|
|
2
|
+
|
|
3
|
+
module CLI
|
|
4
|
+
module Kit
|
|
5
|
+
module Support
|
|
6
|
+
module TestHelper
|
|
7
|
+
def setup
|
|
8
|
+
super
|
|
9
|
+
CLI::Kit::System.reset!
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def assert_all_commands_run(should_raise: true)
|
|
13
|
+
errors = CLI::Kit::System.error_message
|
|
14
|
+
CLI::Kit::System.reset!
|
|
15
|
+
# this is in minitest, but sorbet doesn't know that. probably we
|
|
16
|
+
# could structure this better.
|
|
17
|
+
uself = self #: as untyped
|
|
18
|
+
uself.assert(false, errors) if should_raise && !errors.nil?
|
|
19
|
+
errors
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def teardown
|
|
23
|
+
super
|
|
24
|
+
assert_all_commands_run
|
|
25
|
+
rescue Errno::EACCES
|
|
26
|
+
# this sometimes happens on windows builds - let's ignore it
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
module FakeConfig
|
|
30
|
+
require 'tmpdir'
|
|
31
|
+
require 'fileutils'
|
|
32
|
+
|
|
33
|
+
def setup
|
|
34
|
+
super
|
|
35
|
+
@tmpdir = Dir.mktmpdir
|
|
36
|
+
@prev_xdg = ENV['XDG_CONFIG_HOME']
|
|
37
|
+
ENV['XDG_CONFIG_HOME'] = @tmpdir
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def teardown
|
|
41
|
+
FileUtils.rm_rf(@tmpdir)
|
|
42
|
+
ENV['XDG_CONFIG_HOME'] = @prev_xdg
|
|
43
|
+
super
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
class FakeSuccess
|
|
48
|
+
def initialize(success)
|
|
49
|
+
@success = success
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def success?
|
|
53
|
+
@success
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
module ::CLI
|
|
58
|
+
module Kit
|
|
59
|
+
module System
|
|
60
|
+
class << self
|
|
61
|
+
alias_method :original_system, :system
|
|
62
|
+
def system(cmd, *a, sudo: false, env: {}, stdin: nil, **kwargs)
|
|
63
|
+
a.unshift(cmd)
|
|
64
|
+
expected_command = expected_command(a, sudo: sudo, env: env)
|
|
65
|
+
|
|
66
|
+
# In the case of an unexpected command, expected_command will be nil
|
|
67
|
+
return FakeSuccess.new(false) if expected_command.nil?
|
|
68
|
+
|
|
69
|
+
# Otherwise handle the command
|
|
70
|
+
if expected_command[:allow]
|
|
71
|
+
uself = self #: as untyped
|
|
72
|
+
uself.original_system(*a, sudo: sudo, env: env, **kwargs)
|
|
73
|
+
else
|
|
74
|
+
FakeSuccess.new(expected_command[:success])
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
alias_method :original_capture2, :capture2
|
|
79
|
+
def capture2(cmd, *a, sudo: false, env: {}, **kwargs)
|
|
80
|
+
a.unshift(cmd)
|
|
81
|
+
expected_command = expected_command(a, sudo: sudo, env: env)
|
|
82
|
+
|
|
83
|
+
# In the case of an unexpected command, expected_command will be nil
|
|
84
|
+
return [nil, FakeSuccess.new(false)] if expected_command.nil?
|
|
85
|
+
|
|
86
|
+
# Otherwise handle the command
|
|
87
|
+
if expected_command[:allow]
|
|
88
|
+
uself = self #: as untyped
|
|
89
|
+
uself.original_capture2(*a, sudo: sudo, env: env, **kwargs)
|
|
90
|
+
else
|
|
91
|
+
[
|
|
92
|
+
expected_command[:stdout],
|
|
93
|
+
FakeSuccess.new(expected_command[:success]),
|
|
94
|
+
]
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
alias_method :original_capture2e, :capture2e
|
|
99
|
+
def capture2e(cmd, *a, sudo: false, env: {}, **kwargs)
|
|
100
|
+
a.unshift(cmd)
|
|
101
|
+
expected_command = expected_command(a, sudo: sudo, env: env)
|
|
102
|
+
|
|
103
|
+
# In the case of an unexpected command, expected_command will be nil
|
|
104
|
+
return [nil, FakeSuccess.new(false)] if expected_command.nil?
|
|
105
|
+
|
|
106
|
+
# Otherwise handle the command
|
|
107
|
+
if expected_command[:allow]
|
|
108
|
+
uself = self #: as untyped
|
|
109
|
+
uself.original_capture2e(*a, sudo: sudo, env: env, **kwargs)
|
|
110
|
+
else
|
|
111
|
+
[
|
|
112
|
+
expected_command[:stdout],
|
|
113
|
+
FakeSuccess.new(expected_command[:success]),
|
|
114
|
+
]
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
alias_method :original_capture3, :capture3
|
|
119
|
+
def capture3(cmd, *a, sudo: false, env: {}, **kwargs)
|
|
120
|
+
a.unshift(cmd)
|
|
121
|
+
expected_command = expected_command(a, sudo: sudo, env: env)
|
|
122
|
+
|
|
123
|
+
# In the case of an unexpected command, expected_command will be nil
|
|
124
|
+
return [nil, nil, FakeSuccess.new(false)] if expected_command.nil?
|
|
125
|
+
|
|
126
|
+
# Otherwise handle the command
|
|
127
|
+
if expected_command[:allow]
|
|
128
|
+
uself = self #: as untyped
|
|
129
|
+
uself.original_capture3(*a, sudo: sudo, env: env, **kwargs)
|
|
130
|
+
else
|
|
131
|
+
[
|
|
132
|
+
expected_command[:stdout],
|
|
133
|
+
expected_command[:stderr],
|
|
134
|
+
FakeSuccess.new(expected_command[:success]),
|
|
135
|
+
]
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# Sets up an expectation for a command and stubs out the call (unless allow is true)
|
|
140
|
+
#
|
|
141
|
+
# #### Parameters
|
|
142
|
+
# `*a` : the command, represented as a splat
|
|
143
|
+
# `stdout` : stdout to stub the command with (defaults to empty string)
|
|
144
|
+
# `stderr` : stderr to stub the command with (defaults to empty string)
|
|
145
|
+
# `allow` : allow determines if the command will be actually run, or stubbed. Defaults to nil (stub)
|
|
146
|
+
# `success` : success status to stub the command with (Defaults to nil)
|
|
147
|
+
# `sudo` : expectation of sudo being set or not (defaults to false)
|
|
148
|
+
# `env` : expectation of env being set or not (defaults to {})
|
|
149
|
+
#
|
|
150
|
+
# Note: Must set allow or success
|
|
151
|
+
#
|
|
152
|
+
def fake(*a, stdout: '', stderr: '', allow: nil, success: nil, sudo: false, env: {})
|
|
153
|
+
raise ArgumentError, 'success or allow must be set' if success.nil? && allow.nil?
|
|
154
|
+
|
|
155
|
+
@delegate_open3 ||= {}
|
|
156
|
+
@delegate_open3[a.join(' ')] = {
|
|
157
|
+
expected: {
|
|
158
|
+
sudo: sudo,
|
|
159
|
+
env: env,
|
|
160
|
+
},
|
|
161
|
+
actual: {
|
|
162
|
+
sudo: nil,
|
|
163
|
+
env: nil,
|
|
164
|
+
},
|
|
165
|
+
stdout: stdout,
|
|
166
|
+
stderr: stderr,
|
|
167
|
+
allow: allow,
|
|
168
|
+
success: success,
|
|
169
|
+
run: false,
|
|
170
|
+
}
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
# Resets the faked commands
|
|
174
|
+
#
|
|
175
|
+
def reset!
|
|
176
|
+
@delegate_open3 = {}
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
# Returns the errors associated to a test run
|
|
180
|
+
#
|
|
181
|
+
# #### Returns
|
|
182
|
+
# `errors` (String) a string representing errors found on this run, nil if none
|
|
183
|
+
def error_message
|
|
184
|
+
errors = {
|
|
185
|
+
unexpected: [],
|
|
186
|
+
not_run: [],
|
|
187
|
+
other: {},
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
@delegate_open3.each do |cmd, opts|
|
|
191
|
+
if opts[:unexpected]
|
|
192
|
+
errors[:unexpected] << cmd
|
|
193
|
+
elsif opts[:run]
|
|
194
|
+
error = []
|
|
195
|
+
|
|
196
|
+
if opts[:expected][:sudo] != opts[:actual][:sudo]
|
|
197
|
+
error << "- sudo was supposed to be #{opts[:expected][:sudo]} but was #{opts[:actual][:sudo]}"
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
if opts[:expected][:env] != opts[:actual][:env]
|
|
201
|
+
error << "- env was supposed to be #{opts[:expected][:env]} but was #{opts[:actual][:env]}"
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
errors[:other][cmd] = error.join("\n") unless error.empty?
|
|
205
|
+
else
|
|
206
|
+
errors[:not_run] << cmd
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
final_error = []
|
|
211
|
+
|
|
212
|
+
unless errors[:unexpected].empty?
|
|
213
|
+
final_error << CLI::UI.fmt(<<~EOF)
|
|
214
|
+
{{bold:Unexpected command invocations:}}
|
|
215
|
+
{{command:#{errors[:unexpected].join("\n")}}}
|
|
216
|
+
EOF
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
unless errors[:not_run].empty?
|
|
220
|
+
final_error << CLI::UI.fmt(<<~EOF)
|
|
221
|
+
{{bold:Expected commands were not run:}}
|
|
222
|
+
{{command:#{errors[:not_run].join("\n")}}}
|
|
223
|
+
EOF
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
unless errors[:other].empty?
|
|
227
|
+
final_error << CLI::UI.fmt(<<~EOF)
|
|
228
|
+
{{bold:Commands were not run as expected:}}
|
|
229
|
+
#{errors[:other].map { |cmd, msg| "{{command:#{cmd}}}\n#{msg}" }.join("\n\n")}
|
|
230
|
+
EOF
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
return if final_error.empty?
|
|
234
|
+
|
|
235
|
+
"\n" + final_error.join("\n") # Initial new line for formatting reasons
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
private
|
|
239
|
+
|
|
240
|
+
def expected_command(a, sudo: raise, env: raise)
|
|
241
|
+
expected_cmd = @delegate_open3[a.join(' ')]
|
|
242
|
+
|
|
243
|
+
if expected_cmd.nil?
|
|
244
|
+
@delegate_open3[a.join(' ')] = { unexpected: true }
|
|
245
|
+
return
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
expected_cmd[:run] = true
|
|
249
|
+
expected_cmd[:actual][:sudo] = sudo
|
|
250
|
+
expected_cmd[:actual][:env] = env
|
|
251
|
+
expected_cmd
|
|
252
|
+
end
|
|
253
|
+
end
|
|
254
|
+
end
|
|
255
|
+
end
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
end
|
|
259
|
+
end
|
|
260
|
+
end
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
# typed: true
|
|
2
|
+
|
|
3
|
+
require 'cli/kit'
|
|
4
|
+
require 'open3'
|
|
5
|
+
require 'English'
|
|
6
|
+
|
|
7
|
+
module CLI
|
|
8
|
+
module Kit
|
|
9
|
+
module System
|
|
10
|
+
SUDO_PROMPT = CLI::UI.fmt('{{info:(sudo)}} Password: ')
|
|
11
|
+
class << self
|
|
12
|
+
# Ask for sudo access with a message explaning the need for it
|
|
13
|
+
# Will make subsequent commands capable of running with sudo for a period of time
|
|
14
|
+
#
|
|
15
|
+
# #### Parameters
|
|
16
|
+
# - `msg`: A message telling the user why sudo is needed
|
|
17
|
+
#
|
|
18
|
+
# #### Usage
|
|
19
|
+
# `ctx.sudo_reason("We need to do a thing")`
|
|
20
|
+
#
|
|
21
|
+
#: (String msg) -> void
|
|
22
|
+
def sudo_reason(msg)
|
|
23
|
+
# See if sudo has a cached password
|
|
24
|
+
%x(env SUDO_ASKPASS=/usr/bin/false sudo -A true > /dev/null 2>&1)
|
|
25
|
+
return if $CHILD_STATUS.success?
|
|
26
|
+
|
|
27
|
+
CLI::UI.with_frame_color(:blue) do
|
|
28
|
+
puts(CLI::UI.fmt("{{i}} #{msg}"))
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Execute a command in the user's environment
|
|
33
|
+
# This is meant to be largely equivalent to backticks, only with the env passed in.
|
|
34
|
+
# Captures the results of the command without output to the console
|
|
35
|
+
#
|
|
36
|
+
# #### Parameters
|
|
37
|
+
# - `*a`: A splat of arguments evaluated as a command. (e.g. `'rm', folder` is equivalent to `rm #{folder}`)
|
|
38
|
+
# - `sudo`: If truthy, run this command with sudo. If String, pass to `sudo_reason`
|
|
39
|
+
# - `env`: process environment with which to execute this command
|
|
40
|
+
# - `**kwargs`: additional arguments to pass to Open3.capture2
|
|
41
|
+
#
|
|
42
|
+
# #### Returns
|
|
43
|
+
# - `output`: output (STDOUT) of the command execution
|
|
44
|
+
# - `status`: boolean success status of the command execution
|
|
45
|
+
#
|
|
46
|
+
# #### Usage
|
|
47
|
+
# `out, stat = CLI::Kit::System.capture2('ls', 'a_folder')`
|
|
48
|
+
#
|
|
49
|
+
#: (String cmd, *String args, ?sudo: (String | bool), ?env: Hash[String, String?], **untyped kwargs) -> [String, Process::Status]
|
|
50
|
+
def capture2(cmd, *args, sudo: false, env: ENV.to_h, **kwargs)
|
|
51
|
+
delegate_open3(cmd, args, kwargs, sudo: sudo, env: env, method: :capture2)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Execute a command in the user's environment
|
|
55
|
+
# This is meant to be largely equivalent to backticks, only with the env passed in.
|
|
56
|
+
# Captures the results of the command without output to the console
|
|
57
|
+
#
|
|
58
|
+
# #### Parameters
|
|
59
|
+
# - `*a`: A splat of arguments evaluated as a command. (e.g. `'rm', folder` is equivalent to `rm #{folder}`)
|
|
60
|
+
# - `sudo`: If truthy, run this command with sudo. If String, pass to `sudo_reason`
|
|
61
|
+
# - `env`: process environment with which to execute this command
|
|
62
|
+
# - `**kwargs`: additional arguments to pass to Open3.capture2e
|
|
63
|
+
#
|
|
64
|
+
# #### Returns
|
|
65
|
+
# - `output`: output (STDOUT merged with STDERR) of the command execution
|
|
66
|
+
# - `status`: boolean success status of the command execution
|
|
67
|
+
#
|
|
68
|
+
# #### Usage
|
|
69
|
+
# `out_and_err, stat = CLI::Kit::System.capture2e('ls', 'a_folder')`
|
|
70
|
+
#
|
|
71
|
+
#: (String cmd, *String args, ?sudo: (String | bool), ?env: Hash[String, String?], **untyped kwargs) -> [String, Process::Status]
|
|
72
|
+
def capture2e(cmd, *args, sudo: false, env: ENV.to_h, **kwargs)
|
|
73
|
+
delegate_open3(cmd, args, kwargs, sudo: sudo, env: env, method: :capture2e)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Execute a command in the user's environment
|
|
77
|
+
# This is meant to be largely equivalent to backticks, only with the env passed in.
|
|
78
|
+
# Captures the results of the command without output to the console
|
|
79
|
+
#
|
|
80
|
+
# #### Parameters
|
|
81
|
+
# - `*a`: A splat of arguments evaluated as a command. (e.g. `'rm', folder` is equivalent to `rm #{folder}`)
|
|
82
|
+
# - `sudo`: If truthy, run this command with sudo. If String, pass to `sudo_reason`
|
|
83
|
+
# - `env`: process environment with which to execute this command
|
|
84
|
+
# - `**kwargs`: additional arguments to pass to Open3.capture3
|
|
85
|
+
#
|
|
86
|
+
# #### Returns
|
|
87
|
+
# - `output`: STDOUT of the command execution
|
|
88
|
+
# - `error`: STDERR of the command execution
|
|
89
|
+
# - `status`: boolean success status of the command execution
|
|
90
|
+
#
|
|
91
|
+
# #### Usage
|
|
92
|
+
# `out, err, stat = CLI::Kit::System.capture3('ls', 'a_folder')`
|
|
93
|
+
#
|
|
94
|
+
#: (String cmd, *String args, ?sudo: (String | bool), ?env: Hash[String, String?], **untyped kwargs) -> [String, String, Process::Status]
|
|
95
|
+
def capture3(cmd, *args, sudo: false, env: ENV.to_h, **kwargs)
|
|
96
|
+
delegate_open3(cmd, args, kwargs, sudo: sudo, env: env, method: :capture3)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
#: (String cmd, *String args, ?sudo: (String | bool), ?env: Hash[String, String?], **untyped kwargs) ?{ (IO stdin, IO stdout, Process::Waiter wait_thr) -> [IO, IO, Process::Waiter] } -> [IO, IO, Process::Waiter]
|
|
100
|
+
def popen2(cmd, *args, sudo: false, env: ENV.to_h, **kwargs, &block)
|
|
101
|
+
delegate_open3(cmd, args, kwargs, sudo: sudo, env: env, method: :popen2, &block)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
#: (String cmd, *String args, ?sudo: (String | bool), ?env: Hash[String, String?], **untyped kwargs) ?{ (IO stdin, IO stdout, Process::Waiter wait_thr) -> [IO, IO, Process::Waiter] } -> [IO, IO, Process::Waiter]
|
|
105
|
+
def popen2e(cmd, *args, sudo: false, env: ENV.to_h, **kwargs, &block)
|
|
106
|
+
delegate_open3(cmd, args, kwargs, sudo: sudo, env: env, method: :popen2e, &block)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
#: (String cmd, *String args, ?sudo: (String | bool), ?env: Hash[String, String?], **untyped kwargs) ?{ (IO stdin, IO stdout, IO stderr, Process::Waiter wait_thr) -> [IO, IO, IO, Process::Waiter] } -> [IO, IO, IO, Process::Waiter]
|
|
110
|
+
def popen3(cmd, *args, sudo: false, env: ENV.to_h, **kwargs, &block)
|
|
111
|
+
delegate_open3(cmd, args, kwargs, sudo: sudo, env: env, method: :popen3, &block)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# Execute a command in the user's environment
|
|
115
|
+
# Outputs result of the command without capturing it
|
|
116
|
+
#
|
|
117
|
+
# #### Parameters
|
|
118
|
+
# - `*a`: A splat of arguments evaluated as a command. (e.g. `'rm', folder` is equivalent to `rm #{folder}`)
|
|
119
|
+
# - `sudo`: If truthy, run this command with sudo. If String, pass to `sudo_reason`
|
|
120
|
+
# - `env`: process environment with which to execute this command
|
|
121
|
+
# - `**kwargs`: additional keyword arguments to pass to Process.spawn
|
|
122
|
+
#
|
|
123
|
+
# #### Returns
|
|
124
|
+
# - `status`: The `Process:Status` result for the command execution
|
|
125
|
+
#
|
|
126
|
+
# #### Usage
|
|
127
|
+
# `stat = CLI::Kit::System.system('ls', 'a_folder')`
|
|
128
|
+
#
|
|
129
|
+
#: (String cmd, *String args, ?sudo: (String | bool), ?env: Hash[String, String?], ?stdin: (IO | String | Integer | Symbol)?, **untyped kwargs) ?{ (String out, String err) -> void } -> Process::Status
|
|
130
|
+
def system(cmd, *args, sudo: false, env: ENV.to_h, stdin: nil, **kwargs, &block)
|
|
131
|
+
cmd, args = apply_sudo(cmd, args, sudo)
|
|
132
|
+
|
|
133
|
+
out_r, out_w = IO.pipe
|
|
134
|
+
err_r, err_w = IO.pipe
|
|
135
|
+
in_stream = if stdin
|
|
136
|
+
stdin
|
|
137
|
+
elsif STDIN.closed?
|
|
138
|
+
:close
|
|
139
|
+
else
|
|
140
|
+
STDIN
|
|
141
|
+
end
|
|
142
|
+
cmd, args = resolve_path(cmd, args, env)
|
|
143
|
+
process = Process #: as untyped
|
|
144
|
+
pid = process.spawn(env, cmd, *args, 0 => in_stream, :out => out_w, :err => err_w, **kwargs)
|
|
145
|
+
out_w.close
|
|
146
|
+
err_w.close
|
|
147
|
+
|
|
148
|
+
handlers = if block_given?
|
|
149
|
+
{
|
|
150
|
+
out_r => ->(data) { yield(data.force_encoding(Encoding::UTF_8), '') },
|
|
151
|
+
err_r => ->(data) { yield('', data.force_encoding(Encoding::UTF_8)) },
|
|
152
|
+
}
|
|
153
|
+
else
|
|
154
|
+
{
|
|
155
|
+
out_r => ->(data) { STDOUT.write(data) },
|
|
156
|
+
err_r => ->(data) { STDOUT.write(data) },
|
|
157
|
+
}
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
previous_trailing = Hash.new('')
|
|
161
|
+
loop do
|
|
162
|
+
break if Process.wait(pid, Process::WNOHANG)
|
|
163
|
+
|
|
164
|
+
ios = [err_r, out_r].reject(&:closed?)
|
|
165
|
+
next if ios.empty?
|
|
166
|
+
|
|
167
|
+
readers, = IO.select(ios, [], [], 1)
|
|
168
|
+
next if readers.nil? # If IO.select times out we iterate again so we can check if the process has exited
|
|
169
|
+
|
|
170
|
+
readers.each do |io|
|
|
171
|
+
data, trailing = split_partial_characters(io.readpartial(4096))
|
|
172
|
+
handlers[io].call(previous_trailing[io] + data)
|
|
173
|
+
previous_trailing[io] = trailing
|
|
174
|
+
rescue IOError
|
|
175
|
+
io.close
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
$CHILD_STATUS
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
# Split off trailing partial UTF-8 Characters. UTF-8 Multibyte characters start with a 11xxxxxx byte that tells
|
|
183
|
+
# how many following bytes are part of this character, followed by some number of 10xxxxxx bytes. This simple
|
|
184
|
+
# algorithm will split off a whole trailing multi-byte character.
|
|
185
|
+
#: (String data) -> [String, String]
|
|
186
|
+
def split_partial_characters(data)
|
|
187
|
+
last_byte = data.getbyte(-1) #: as !nil
|
|
188
|
+
return [data, ''] if (last_byte & 0b1000_0000).zero?
|
|
189
|
+
|
|
190
|
+
# UTF-8 is up to 4 characters per rune, so we could never want to trim more than that, and we want to avoid
|
|
191
|
+
# allocating an array for the whole of data with bytes
|
|
192
|
+
min_bound = -[4, data.bytesize].min
|
|
193
|
+
fb = data.byteslice(min_bound..-1) #: as !nil
|
|
194
|
+
final_bytes = fb.bytes
|
|
195
|
+
partial_character_sub_index = final_bytes.rindex { |byte| byte & 0b1100_0000 == 0b1100_0000 }
|
|
196
|
+
|
|
197
|
+
# Bail out for non UTF-8
|
|
198
|
+
return [data, ''] unless partial_character_sub_index
|
|
199
|
+
|
|
200
|
+
start_byte = final_bytes[partial_character_sub_index]
|
|
201
|
+
full_size = if start_byte & 0b1111_1000 == 0b1111_0000
|
|
202
|
+
4
|
|
203
|
+
elsif start_byte & 0b1111_0000 == 0b1110_0000
|
|
204
|
+
3
|
|
205
|
+
elsif start_byte & 0b1110_0000 == 0b110_00000
|
|
206
|
+
2
|
|
207
|
+
else
|
|
208
|
+
nil # Not a valid UTF-8 character
|
|
209
|
+
end
|
|
210
|
+
return [data, ''] if full_size.nil? # Bail out for non UTF-8
|
|
211
|
+
|
|
212
|
+
if final_bytes.size - partial_character_sub_index == full_size
|
|
213
|
+
# We have a full UTF-8 character, so we can just return the data
|
|
214
|
+
return [data, '']
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
partial_character_index = min_bound + partial_character_sub_index
|
|
218
|
+
|
|
219
|
+
[
|
|
220
|
+
data.byteslice(0...partial_character_index), #: as !nil
|
|
221
|
+
data.byteslice(partial_character_index..-1), #: as !nil
|
|
222
|
+
]
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
#: -> Symbol
|
|
226
|
+
def os
|
|
227
|
+
return :mac if /darwin/.match(RUBY_PLATFORM)
|
|
228
|
+
return :linux if /linux/.match(RUBY_PLATFORM)
|
|
229
|
+
return :windows if /mingw/.match(RUBY_PLATFORM)
|
|
230
|
+
|
|
231
|
+
raise "Could not determine OS from platform #{RUBY_PLATFORM}"
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
#: (String cmd, Hash[String, String?] env) -> String?
|
|
235
|
+
def which(cmd, env)
|
|
236
|
+
exts = os == :windows ? (env['PATHEXT'] || 'exe').split(';') : ['']
|
|
237
|
+
(env['PATH'] || '').split(File::PATH_SEPARATOR).each do |path|
|
|
238
|
+
exts.each do |ext|
|
|
239
|
+
exe = File.join(path, "#{cmd}#{ext}")
|
|
240
|
+
return exe if File.executable?(exe) && !File.directory?(exe)
|
|
241
|
+
end
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
nil
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
private
|
|
248
|
+
|
|
249
|
+
#: (String cmd, Array[String] args, (String | bool) sudo) -> [String, Array[String]]
|
|
250
|
+
def apply_sudo(cmd, args, sudo)
|
|
251
|
+
return [cmd, args] if !sudo || Process.uid.zero?
|
|
252
|
+
|
|
253
|
+
sudo_reason(sudo) if sudo.is_a?(String)
|
|
254
|
+
['sudo', args.unshift('-E', '-S', '-p', SUDO_PROMPT, '--', cmd)]
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
#: (String cmd, Array[String] args, Hash[Symbol, untyped] kwargs, ?sudo: (String | bool), ?env: Hash[String, String?], ?method: Symbol) ?{ (?) -> untyped } -> untyped
|
|
258
|
+
def delegate_open3(cmd, args, kwargs, sudo: raise, env: raise, method: raise, &block)
|
|
259
|
+
cmd, args = apply_sudo(cmd, args, sudo)
|
|
260
|
+
cmd, args = resolve_path(cmd, args, env)
|
|
261
|
+
open3 = Open3 #: as untyped
|
|
262
|
+
open3.send(method, env, cmd, *args, **kwargs, &block)
|
|
263
|
+
rescue Errno::EINTR
|
|
264
|
+
raise(Errno::EINTR, "command interrupted: #{cmd} #{args.join(" ")}")
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
# Ruby resolves the program to execute using its own PATH, but we want it to
|
|
268
|
+
# use the provided one, so we ensure ruby chooses to spawn a shell, which will
|
|
269
|
+
# parse our command and properly spawn our target using the provided environment.
|
|
270
|
+
#
|
|
271
|
+
# This is important because dev clobbers its own environment such that ruby
|
|
272
|
+
# means /usr/bin/ruby, but we want it to select the ruby targeted by the active
|
|
273
|
+
# project.
|
|
274
|
+
#
|
|
275
|
+
# See https://github.com/Shopify/dev/pull/625 for more details.
|
|
276
|
+
#: (String cmd, Array[String] args, Hash[String, String?] env) -> [String, Array[String]]
|
|
277
|
+
def resolve_path(cmd, args, env)
|
|
278
|
+
# If only one argument was provided, make sure it's interpreted by a shell.
|
|
279
|
+
if args.empty?
|
|
280
|
+
prefix = os == :windows ? 'break && ' : 'true ; '
|
|
281
|
+
return [prefix + cmd, []]
|
|
282
|
+
end
|
|
283
|
+
return [cmd, args] if cmd.include?('/')
|
|
284
|
+
|
|
285
|
+
[which(cmd, env) || cmd, args]
|
|
286
|
+
end
|
|
287
|
+
end
|
|
288
|
+
end
|
|
289
|
+
end
|
|
290
|
+
end
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# typed: true
|
|
2
|
+
|
|
3
|
+
require 'cli/kit'
|
|
4
|
+
|
|
5
|
+
module CLI
|
|
6
|
+
module Kit
|
|
7
|
+
module Util
|
|
8
|
+
class << self
|
|
9
|
+
#
|
|
10
|
+
# Converts an integer representing bytes into a human readable format
|
|
11
|
+
#
|
|
12
|
+
#: (Integer bytes, ?precision: Integer, ?space: bool) -> String
|
|
13
|
+
def to_filesize(bytes, precision: 2, space: false)
|
|
14
|
+
to_si_scale(bytes, 'B', precision: precision, space: space, factor: 1024)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Converts a number to a human readable format on the SI scale
|
|
18
|
+
#
|
|
19
|
+
#: (Numeric number, ?String unit, ?factor: Integer, ?precision: Integer, ?space: bool) -> String
|
|
20
|
+
def to_si_scale(number, unit = '', factor: 1000, precision: 2, space: false)
|
|
21
|
+
raise ArgumentError, 'factor should only be 1000 or 1024' unless [1000, 1024].include?(factor)
|
|
22
|
+
|
|
23
|
+
small_scale = ['m', 'µ', 'n', 'p', 'f', 'a', 'z', 'y']
|
|
24
|
+
big_scale = ['k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y']
|
|
25
|
+
negative = number < 0
|
|
26
|
+
number = number.abs.to_f
|
|
27
|
+
|
|
28
|
+
if number == 0.0 || number.between?(1, factor)
|
|
29
|
+
prefix = ''
|
|
30
|
+
scale = 0
|
|
31
|
+
else
|
|
32
|
+
scale = Math.log(number, factor).floor
|
|
33
|
+
if number < 1
|
|
34
|
+
index = [-scale - 1, small_scale.length].min
|
|
35
|
+
scale = -(index + 1)
|
|
36
|
+
prefix = small_scale[index] #: as !nil
|
|
37
|
+
else
|
|
38
|
+
index = [scale - 1, big_scale.length].min
|
|
39
|
+
scale = index + 1
|
|
40
|
+
prefix = big_scale[index] #: as !nil
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
divider = (factor**scale)
|
|
45
|
+
fnum = (number / divider.to_f).round(precision)
|
|
46
|
+
|
|
47
|
+
# Trim useless decimal
|
|
48
|
+
fnum = fnum.to_i if (fnum.to_i.to_f * divider.to_f) == number
|
|
49
|
+
|
|
50
|
+
fnum = -fnum if negative
|
|
51
|
+
if space
|
|
52
|
+
prefix = ' ' + prefix
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
"#{fnum}#{prefix}#{unit}"
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Dir.chdir, when invoked in block form, complains when we call chdir
|
|
59
|
+
# again recursively. There's no apparent good reason for this, so we
|
|
60
|
+
# simply implement our own block form of Dir.chdir here.
|
|
61
|
+
#: [T] (String dir) { -> T } -> T
|
|
62
|
+
def with_dir(dir, &block)
|
|
63
|
+
prev = Dir.pwd
|
|
64
|
+
begin
|
|
65
|
+
Dir.chdir(dir)
|
|
66
|
+
yield
|
|
67
|
+
ensure
|
|
68
|
+
Dir.chdir(prev)
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Must call retry_after on the result in order to execute the block
|
|
73
|
+
#
|
|
74
|
+
# Example usage:
|
|
75
|
+
#
|
|
76
|
+
# CLI::Kit::Util.begin do
|
|
77
|
+
# might_raise_if_costly_prep_not_done()
|
|
78
|
+
# end.retry_after(ExpectedError) do
|
|
79
|
+
# costly_prep()
|
|
80
|
+
# end
|
|
81
|
+
#: [T] { -> T } -> Retrier[T]
|
|
82
|
+
def begin(&block_that_might_raise)
|
|
83
|
+
Retrier.new(block_that_might_raise)
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
#: [BlockReturnType]
|
|
88
|
+
class Retrier
|
|
89
|
+
#: (^-> BlockReturnType block_that_might_raise) -> void
|
|
90
|
+
def initialize(block_that_might_raise)
|
|
91
|
+
@block_that_might_raise = block_that_might_raise
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
#: (?singleton(Exception) exception, ?retries: Integer) ?{ (Exception e) -> void } -> BlockReturnType
|
|
95
|
+
def retry_after(exception = StandardError, retries: 1, &before_retry)
|
|
96
|
+
@block_that_might_raise.call
|
|
97
|
+
rescue exception => e
|
|
98
|
+
raise if (retries -= 1) < 0
|
|
99
|
+
|
|
100
|
+
if before_retry
|
|
101
|
+
# rubocop:disable Style/IdenticalConditionalBranches
|
|
102
|
+
if before_retry.arity == 0
|
|
103
|
+
prc = before_retry #: as ^() -> void
|
|
104
|
+
prc.call
|
|
105
|
+
else
|
|
106
|
+
prc = before_retry #: as ^(Exception) -> void
|
|
107
|
+
prc.call(e)
|
|
108
|
+
end
|
|
109
|
+
# rubocop:enable Style/IdenticalConditionalBranches
|
|
110
|
+
end
|
|
111
|
+
retry
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
private_constant :Retrier
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|