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,69 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'listen/file'
|
|
4
|
+
require 'listen/directory'
|
|
5
|
+
|
|
6
|
+
module Listen
|
|
7
|
+
# TODO: rename to Snapshot
|
|
8
|
+
class Change
|
|
9
|
+
# TODO: test this class for coverage
|
|
10
|
+
class Config
|
|
11
|
+
def initialize(queue, silencer)
|
|
12
|
+
@queue = queue
|
|
13
|
+
@silencer = silencer
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def silenced?(path, type)
|
|
17
|
+
@silencer.silenced?(Pathname(path), type)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def queue(*args)
|
|
21
|
+
@queue << args
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
attr_reader :record
|
|
26
|
+
|
|
27
|
+
def initialize(config, record)
|
|
28
|
+
@config = config
|
|
29
|
+
@record = record
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Invalidate some part of the snapshot/record (dir, file, subtree, etc.)
|
|
33
|
+
# rubocop:disable Metrics/MethodLength
|
|
34
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
|
35
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
|
36
|
+
def invalidate(type, rel_path, options)
|
|
37
|
+
watched_dir = Pathname.new(record.root)
|
|
38
|
+
|
|
39
|
+
change = options[:change]
|
|
40
|
+
cookie = options[:cookie]
|
|
41
|
+
|
|
42
|
+
if !cookie && @config.silenced?(rel_path, type)
|
|
43
|
+
Listen.logger.debug { "(silenced): #{rel_path.inspect}" }
|
|
44
|
+
return
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
path = watched_dir + rel_path
|
|
48
|
+
|
|
49
|
+
Listen.logger.debug do
|
|
50
|
+
log_details = options[:silence] && 'recording' || change || 'unknown'
|
|
51
|
+
"#{log_details}: #{type}:#{path} (#{options.inspect})"
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
if change
|
|
55
|
+
options = cookie ? { cookie: cookie } : {}
|
|
56
|
+
@config.queue(type, change, watched_dir, rel_path, options)
|
|
57
|
+
elsif type == :dir
|
|
58
|
+
# NOTE: POSSIBLE RECURSION
|
|
59
|
+
# TODO: fix - use a queue instead
|
|
60
|
+
Directory.scan(self, rel_path, options)
|
|
61
|
+
elsif (change = File.change(record, rel_path)) && !options[:silence]
|
|
62
|
+
@config.queue(:file, change, watched_dir, rel_path)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
# rubocop:enable Metrics/MethodLength
|
|
66
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
|
67
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
|
68
|
+
end
|
|
69
|
+
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'thor'
|
|
4
|
+
require 'listen'
|
|
5
|
+
require 'logger'
|
|
6
|
+
|
|
7
|
+
module Listen
|
|
8
|
+
class CLI < Thor
|
|
9
|
+
default_task :start
|
|
10
|
+
|
|
11
|
+
desc 'start', 'Starts Listen'
|
|
12
|
+
|
|
13
|
+
class_option :verbose,
|
|
14
|
+
type: :boolean,
|
|
15
|
+
default: false,
|
|
16
|
+
aliases: '-v',
|
|
17
|
+
banner: 'Verbose'
|
|
18
|
+
|
|
19
|
+
class_option :directory,
|
|
20
|
+
type: :array,
|
|
21
|
+
default: ['.'],
|
|
22
|
+
aliases: '-d',
|
|
23
|
+
banner: 'One or more directories to listen to'
|
|
24
|
+
|
|
25
|
+
class_option :relative,
|
|
26
|
+
type: :boolean,
|
|
27
|
+
default: false,
|
|
28
|
+
aliases: '-r',
|
|
29
|
+
banner: 'Convert paths relative to current directory'
|
|
30
|
+
|
|
31
|
+
def start
|
|
32
|
+
Listen::Forwarder.new(options).start
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
class Forwarder
|
|
37
|
+
attr_reader :logger
|
|
38
|
+
|
|
39
|
+
def initialize(options)
|
|
40
|
+
@options = options
|
|
41
|
+
@logger = ::Logger.new(STDOUT, level: ::Logger::INFO)
|
|
42
|
+
@logger.formatter = proc { |_, _, _, msg| "#{msg}\n" }
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def start
|
|
46
|
+
logger.info 'Starting listen...'
|
|
47
|
+
|
|
48
|
+
directory = @options[:directory]
|
|
49
|
+
relative = @options[:relative]
|
|
50
|
+
callback = proc do |modified, added, removed|
|
|
51
|
+
if @options[:verbose]
|
|
52
|
+
logger.info "+ #{added}" unless added.empty?
|
|
53
|
+
logger.info "- #{removed}" unless removed.empty?
|
|
54
|
+
logger.info "> #{modified}" unless modified.empty?
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
listener = Listen.to(*directory, relative: relative, &callback)
|
|
59
|
+
|
|
60
|
+
listener.start
|
|
61
|
+
|
|
62
|
+
sleep 0.5 while listener.processing?
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'set'
|
|
4
|
+
|
|
5
|
+
module Listen
|
|
6
|
+
# TODO: refactor (turn it into a normal object, cache the stat, etc)
|
|
7
|
+
class Directory
|
|
8
|
+
# rubocop:disable Metrics/MethodLength
|
|
9
|
+
def self.scan(snapshot, rel_path, options)
|
|
10
|
+
record = snapshot.record
|
|
11
|
+
dir = Pathname.new(record.root)
|
|
12
|
+
previous = record.dir_entries(rel_path)
|
|
13
|
+
|
|
14
|
+
record.add_dir(rel_path)
|
|
15
|
+
|
|
16
|
+
# TODO: use children(with_directory: false)
|
|
17
|
+
path = dir + rel_path
|
|
18
|
+
current = Set.new(_children(path))
|
|
19
|
+
|
|
20
|
+
Listen.logger.debug do
|
|
21
|
+
format('%s: %s(%s): %s -> %s',
|
|
22
|
+
(options[:silence] ? 'Recording' : 'Scanning'),
|
|
23
|
+
rel_path, options.inspect, previous.inspect, current.inspect)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
begin
|
|
27
|
+
current.each do |full_path|
|
|
28
|
+
type = ::File.lstat(full_path.to_s).directory? ? :dir : :file
|
|
29
|
+
item_rel_path = full_path.relative_path_from(dir).to_s
|
|
30
|
+
_change(snapshot, type, item_rel_path, options)
|
|
31
|
+
end
|
|
32
|
+
rescue Errno::ENOENT
|
|
33
|
+
# The directory changed meanwhile, so rescan it
|
|
34
|
+
current = Set.new(_children(path))
|
|
35
|
+
retry
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# TODO: this is not tested properly
|
|
39
|
+
previous = previous.reject { |entry, _| current.include?(path + entry) }
|
|
40
|
+
|
|
41
|
+
_async_changes(snapshot, Pathname.new(rel_path), previous, options)
|
|
42
|
+
rescue Errno::ENOENT, Errno::EHOSTDOWN
|
|
43
|
+
record.unset_path(rel_path)
|
|
44
|
+
_async_changes(snapshot, Pathname.new(rel_path), previous, options)
|
|
45
|
+
rescue Errno::ENOTDIR
|
|
46
|
+
# TODO: path not tested
|
|
47
|
+
record.unset_path(rel_path)
|
|
48
|
+
_async_changes(snapshot, path, previous, options)
|
|
49
|
+
_change(snapshot, :file, rel_path, options)
|
|
50
|
+
rescue
|
|
51
|
+
Listen.logger.warn { format('scan DIED: %s:%s', $ERROR_INFO, $ERROR_POSITION * "\n") }
|
|
52
|
+
raise
|
|
53
|
+
end
|
|
54
|
+
# rubocop:enable Metrics/MethodLength
|
|
55
|
+
|
|
56
|
+
def self.ascendant_of?(base, other)
|
|
57
|
+
other.ascend do |ascendant|
|
|
58
|
+
break true if base == ascendant
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def self._async_changes(snapshot, path, previous, options)
|
|
63
|
+
fail "Not a Pathname: #{path.inspect}" unless path.respond_to?(:children)
|
|
64
|
+
previous.each do |entry, data|
|
|
65
|
+
# TODO: this is a hack with insufficient testing
|
|
66
|
+
type = data.key?(:mtime) ? :file : :dir
|
|
67
|
+
rel_path_s = (path + entry).to_s
|
|
68
|
+
_change(snapshot, type, rel_path_s, options)
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def self._change(snapshot, type, path, options)
|
|
73
|
+
return snapshot.invalidate(type, path, options) if type == :dir
|
|
74
|
+
|
|
75
|
+
# Minor param cleanup for tests
|
|
76
|
+
# TODO: use a dedicated Event class
|
|
77
|
+
opts = options.dup
|
|
78
|
+
opts.delete(:recursive)
|
|
79
|
+
snapshot.invalidate(type, path, opts)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def self._children(path)
|
|
83
|
+
return path.children unless RUBY_ENGINE == 'jruby'
|
|
84
|
+
|
|
85
|
+
# JRuby inconsistency workaround, see:
|
|
86
|
+
# https://github.com/jruby/jruby/issues/3840
|
|
87
|
+
exists = path.exist?
|
|
88
|
+
directory = path.directory?
|
|
89
|
+
exists && !directory and raise Errno::ENOTDIR, path.to_s
|
|
90
|
+
path.children
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Besides programming error exceptions like ArgumentError,
|
|
4
|
+
# all public interface exceptions should be declared here and inherit from Listen::Error.
|
|
5
|
+
module Listen
|
|
6
|
+
class Error < RuntimeError
|
|
7
|
+
class NotStarted < Error; end
|
|
8
|
+
class SymlinkLoop < Error; end
|
|
9
|
+
class INotifyMaxWatchesExceeded < Error; end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Listen
|
|
4
|
+
module Event
|
|
5
|
+
class Config
|
|
6
|
+
attr_reader :listener, :event_queue, :min_delay_between_events
|
|
7
|
+
|
|
8
|
+
def initialize(
|
|
9
|
+
listener,
|
|
10
|
+
event_queue,
|
|
11
|
+
queue_optimizer,
|
|
12
|
+
wait_for_delay,
|
|
13
|
+
&block
|
|
14
|
+
)
|
|
15
|
+
@listener = listener
|
|
16
|
+
@event_queue = event_queue
|
|
17
|
+
@queue_optimizer = queue_optimizer
|
|
18
|
+
@min_delay_between_events = wait_for_delay
|
|
19
|
+
@block = block
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def sleep(seconds)
|
|
23
|
+
Kernel.sleep(seconds)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def call(*args)
|
|
27
|
+
@block&.call(*args)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def callable?
|
|
31
|
+
@block
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def optimize_changes(changes)
|
|
35
|
+
@queue_optimizer.smoosh_changes(changes)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'timeout'
|
|
4
|
+
require 'listen/event/processor'
|
|
5
|
+
require 'listen/thread'
|
|
6
|
+
require 'listen/error'
|
|
7
|
+
|
|
8
|
+
module Listen
|
|
9
|
+
module Event
|
|
10
|
+
class Loop
|
|
11
|
+
include Listen::FSM
|
|
12
|
+
|
|
13
|
+
Error = ::Listen::Error
|
|
14
|
+
NotStarted = ::Listen::Error::NotStarted # for backward compatibility
|
|
15
|
+
|
|
16
|
+
start_state :pre_start
|
|
17
|
+
state :pre_start
|
|
18
|
+
state :starting
|
|
19
|
+
state :started
|
|
20
|
+
state :stopped
|
|
21
|
+
|
|
22
|
+
def initialize(config)
|
|
23
|
+
@config = config
|
|
24
|
+
@wait_thread = nil
|
|
25
|
+
@reasons = ::Queue.new
|
|
26
|
+
initialize_fsm
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def wakeup_on_event
|
|
30
|
+
if started? && @wait_thread&.alive?
|
|
31
|
+
_wakeup(:event)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def started?
|
|
36
|
+
state == :started
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
MAX_STARTUP_SECONDS = 5.0
|
|
40
|
+
|
|
41
|
+
# @raises Error::NotStarted if background thread hasn't started in MAX_STARTUP_SECONDS
|
|
42
|
+
def start
|
|
43
|
+
# TODO: use a Fiber instead?
|
|
44
|
+
return unless state == :pre_start
|
|
45
|
+
|
|
46
|
+
transition! :starting
|
|
47
|
+
|
|
48
|
+
@wait_thread = Listen::Thread.new("wait_thread") do
|
|
49
|
+
_process_changes
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
Listen.logger.debug("Waiting for processing to start...")
|
|
53
|
+
|
|
54
|
+
wait_for_state(:started, timeout: MAX_STARTUP_SECONDS) or
|
|
55
|
+
raise Error::NotStarted, "thread didn't start in #{MAX_STARTUP_SECONDS} seconds (in state: #{state.inspect})"
|
|
56
|
+
|
|
57
|
+
Listen.logger.debug('Processing started.')
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def pause
|
|
61
|
+
# TODO: works?
|
|
62
|
+
# fail NotImplementedError
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def stop
|
|
66
|
+
transition! :stopped
|
|
67
|
+
|
|
68
|
+
@wait_thread&.join
|
|
69
|
+
@wait_thread = nil
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def stopped?
|
|
73
|
+
state == :stopped
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
private
|
|
77
|
+
|
|
78
|
+
def _process_changes
|
|
79
|
+
processor = Event::Processor.new(@config, @reasons)
|
|
80
|
+
|
|
81
|
+
transition! :started
|
|
82
|
+
|
|
83
|
+
processor.loop_for(@config.min_delay_between_events)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def _wakeup(reason)
|
|
87
|
+
@reasons << reason
|
|
88
|
+
@wait_thread.wakeup
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'listen/monotonic_time'
|
|
4
|
+
|
|
5
|
+
module Listen
|
|
6
|
+
module Event
|
|
7
|
+
class Processor
|
|
8
|
+
def initialize(config, reasons)
|
|
9
|
+
@config = config
|
|
10
|
+
@listener = config.listener
|
|
11
|
+
@reasons = reasons
|
|
12
|
+
_reset_no_unprocessed_events
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# TODO: implement this properly instead of checking the state at arbitrary
|
|
16
|
+
# points in time
|
|
17
|
+
def loop_for(latency)
|
|
18
|
+
@latency = latency
|
|
19
|
+
|
|
20
|
+
loop do
|
|
21
|
+
event = _wait_until_events
|
|
22
|
+
_check_stopped
|
|
23
|
+
_wait_until_events_calm_down
|
|
24
|
+
_wait_until_no_longer_paused
|
|
25
|
+
_process_changes(event)
|
|
26
|
+
end
|
|
27
|
+
rescue Stopped
|
|
28
|
+
Listen.logger.debug('Processing stopped')
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
class Stopped < RuntimeError
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def _wait_until_events_calm_down
|
|
37
|
+
loop do
|
|
38
|
+
now = MonotonicTime.now
|
|
39
|
+
|
|
40
|
+
# Assure there's at least latency between callbacks to allow
|
|
41
|
+
# for accumulating changes
|
|
42
|
+
diff = _deadline - now
|
|
43
|
+
break if diff <= 0
|
|
44
|
+
|
|
45
|
+
# give events a bit of time to accumulate so they can be
|
|
46
|
+
# compressed/optimized
|
|
47
|
+
_sleep(diff)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def _wait_until_no_longer_paused
|
|
52
|
+
@listener.wait_for_state(*(Listener.states.keys - [:paused]))
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def _check_stopped
|
|
56
|
+
if @listener.stopped?
|
|
57
|
+
_flush_wakeup_reasons
|
|
58
|
+
raise Stopped
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def _sleep(seconds)
|
|
63
|
+
_check_stopped
|
|
64
|
+
config.sleep(seconds)
|
|
65
|
+
_check_stopped
|
|
66
|
+
|
|
67
|
+
_flush_wakeup_reasons do |reason|
|
|
68
|
+
if reason == :event && !@listener.paused?
|
|
69
|
+
_remember_time_of_first_unprocessed_event
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def _remember_time_of_first_unprocessed_event
|
|
75
|
+
@_remember_time_of_first_unprocessed_event ||= MonotonicTime.now
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def _reset_no_unprocessed_events
|
|
79
|
+
@_remember_time_of_first_unprocessed_event = nil
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def _deadline
|
|
83
|
+
@_remember_time_of_first_unprocessed_event + @latency
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# blocks until event is popped
|
|
87
|
+
# returns the event or `nil` when the event_queue is closed
|
|
88
|
+
# rubocop:disable Naming/MemoizedInstanceVariableName
|
|
89
|
+
def _wait_until_events
|
|
90
|
+
config.event_queue.pop.tap do |_event|
|
|
91
|
+
@_remember_time_of_first_unprocessed_event ||= MonotonicTime.now
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
# rubocop:enable Naming/MemoizedInstanceVariableName
|
|
95
|
+
|
|
96
|
+
def _flush_wakeup_reasons
|
|
97
|
+
until @reasons.empty?
|
|
98
|
+
reason = @reasons.pop
|
|
99
|
+
yield reason if block_given?
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# for easier testing without sleep loop
|
|
104
|
+
def _process_changes(event)
|
|
105
|
+
_reset_no_unprocessed_events
|
|
106
|
+
|
|
107
|
+
changes = [event]
|
|
108
|
+
changes << config.event_queue.pop until config.event_queue.empty?
|
|
109
|
+
|
|
110
|
+
return unless config.callable?
|
|
111
|
+
|
|
112
|
+
hash = config.optimize_changes(changes)
|
|
113
|
+
result = [hash[:modified], hash[:added], hash[:removed]]
|
|
114
|
+
return if result.all?(&:empty?)
|
|
115
|
+
|
|
116
|
+
block_start = MonotonicTime.now
|
|
117
|
+
exception_note = " (exception)"
|
|
118
|
+
::Listen::Thread.rescue_and_log('_process_changes') do
|
|
119
|
+
config.call(*result)
|
|
120
|
+
exception_note = nil
|
|
121
|
+
end
|
|
122
|
+
Listen.logger.debug "Callback#{exception_note} took #{MonotonicTime.now - block_start} sec"
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
attr_reader :config
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'forwardable'
|
|
4
|
+
|
|
5
|
+
module Listen
|
|
6
|
+
module Event
|
|
7
|
+
class Queue
|
|
8
|
+
extend Forwardable
|
|
9
|
+
|
|
10
|
+
class Config
|
|
11
|
+
def initialize(relative)
|
|
12
|
+
@relative = relative
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def relative?
|
|
16
|
+
@relative
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def initialize(config)
|
|
21
|
+
@event_queue = ::Queue.new
|
|
22
|
+
@config = config
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def <<(args)
|
|
26
|
+
type, change, dir, path, options = *args
|
|
27
|
+
fail "Invalid type: #{type.inspect}" unless [:dir, :file].include? type
|
|
28
|
+
fail "Invalid change: #{change.inspect}" unless change.is_a?(Symbol)
|
|
29
|
+
fail "Invalid path: #{path.inspect}" unless path.is_a?(String)
|
|
30
|
+
|
|
31
|
+
dir = if @config.relative?
|
|
32
|
+
_safe_relative_from_cwd(dir)
|
|
33
|
+
else
|
|
34
|
+
dir
|
|
35
|
+
end
|
|
36
|
+
@event_queue << [type, change, dir, path, options]
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
delegate empty?: :@event_queue
|
|
40
|
+
delegate pop: :@event_queue
|
|
41
|
+
delegate close: :@event_queue
|
|
42
|
+
|
|
43
|
+
private
|
|
44
|
+
|
|
45
|
+
def _safe_relative_from_cwd(dir)
|
|
46
|
+
dir.relative_path_from(Pathname.pwd)
|
|
47
|
+
rescue ArgumentError
|
|
48
|
+
dir
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'digest'
|
|
4
|
+
|
|
5
|
+
module Listen
|
|
6
|
+
class File
|
|
7
|
+
# rubocop:disable Metrics/MethodLength
|
|
8
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
|
9
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
|
10
|
+
def self.change(record, rel_path)
|
|
11
|
+
path = Pathname.new(record.root) + rel_path
|
|
12
|
+
lstat = path.lstat
|
|
13
|
+
|
|
14
|
+
data = { mtime: lstat.mtime.to_f, mode: lstat.mode, size: lstat.size }
|
|
15
|
+
|
|
16
|
+
record_data = record.file_data(rel_path)
|
|
17
|
+
|
|
18
|
+
if record_data.empty?
|
|
19
|
+
record.update_file(rel_path, data)
|
|
20
|
+
return :added
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
if data[:mode] != record_data[:mode]
|
|
24
|
+
record.update_file(rel_path, data)
|
|
25
|
+
return :modified
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
if data[:mtime] != record_data[:mtime]
|
|
29
|
+
record.update_file(rel_path, data)
|
|
30
|
+
return :modified
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
if data[:size] != record_data[:size]
|
|
34
|
+
record.update_file(rel_path, data)
|
|
35
|
+
return :modified
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
return if /1|true/ =~ ENV['LISTEN_GEM_DISABLE_HASHING']
|
|
39
|
+
return unless inaccurate_mac_time?(lstat)
|
|
40
|
+
|
|
41
|
+
# Check if change happened within 1 second (maybe it's even
|
|
42
|
+
# too much, e.g. 0.3-0.5 could be sufficient).
|
|
43
|
+
#
|
|
44
|
+
# With rb-fsevent, there's a (configurable) latency between
|
|
45
|
+
# when file was changed and when the event was triggered.
|
|
46
|
+
#
|
|
47
|
+
# If a file is saved at ???14.998, by the time the event is
|
|
48
|
+
# actually received by Listen, the time could already be e.g.
|
|
49
|
+
# ???15.7.
|
|
50
|
+
#
|
|
51
|
+
# And since Darwin adapter uses directory scanning, the file
|
|
52
|
+
# mtime may be the same (e.g. file was changed at ???14.001,
|
|
53
|
+
# then at ???14.998, but the fstat time would be ???14.0 in
|
|
54
|
+
# both cases).
|
|
55
|
+
#
|
|
56
|
+
# If change happened at ???14.999997, the mtime is 14.0, so for
|
|
57
|
+
# an mtime=???14.0 we assume it could even be almost ???15.0
|
|
58
|
+
#
|
|
59
|
+
# So if Time.now.to_f is ???15.999998 and stat reports mtime
|
|
60
|
+
# at ???14.0, then event was due to that file'd change when:
|
|
61
|
+
#
|
|
62
|
+
# ???15.999997 - ???14.999998 < 1.0s
|
|
63
|
+
#
|
|
64
|
+
# So the "2" is "1 + 1" (1s to cover rb-fsevent latency +
|
|
65
|
+
# 1s maximum difference between real mtime and that recorded
|
|
66
|
+
# in the file system)
|
|
67
|
+
#
|
|
68
|
+
return if data[:mtime].to_i + 2 <= Time.now.to_f
|
|
69
|
+
|
|
70
|
+
sha = Digest::SHA256.file(path).digest
|
|
71
|
+
record.update_file(rel_path, data.merge(sha: sha))
|
|
72
|
+
if record_data[:sha] && sha != record_data[:sha]
|
|
73
|
+
:modified
|
|
74
|
+
end
|
|
75
|
+
rescue SystemCallError
|
|
76
|
+
record.unset_path(rel_path)
|
|
77
|
+
:removed
|
|
78
|
+
rescue
|
|
79
|
+
Listen.logger.debug "lstat failed for: #{rel_path} (#{$ERROR_INFO})"
|
|
80
|
+
raise
|
|
81
|
+
end
|
|
82
|
+
# rubocop:enable Metrics/MethodLength
|
|
83
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
|
84
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
|
85
|
+
|
|
86
|
+
def self.inaccurate_mac_time?(stat)
|
|
87
|
+
# 'mac' means Modified/Accessed/Created
|
|
88
|
+
|
|
89
|
+
# Since precision depends on mounted FS (e.g. you can have a FAT partiion
|
|
90
|
+
# mounted on Linux), check for fields with a remainder to detect this
|
|
91
|
+
|
|
92
|
+
[stat.mtime, stat.ctime, stat.atime].map(&:usec).all?(&:zero?)
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|