From d0da95dfc50ed5b13c51f6675bfa0b4f1a9aa012 Mon Sep 17 00:00:00 2001 From: Alexey Berezhok Date: Tue, 3 Dec 2024 21:44:39 +0300 Subject: [PATCH] Added passenger support. Partialy 1 --- bin/v-add-user-sftp-jail | 4 + bin/v-ext-modules | 152 ++++ bin/v-ext-modules-run | 82 +++ bin/v-list-sys-info | 4 +- func/upgrade.sh | 25 - func_ruby/.bundle/config | 2 + func_ruby/Gemfile | 7 + func_ruby/Gemfile.lock | 22 + .../configs/passenger_manager/version | 1 + func_ruby/ext-modules/empty_module.mod | 30 + func_ruby/ext-modules/passenger_manager.mod | 108 +++ .../passenger_manager/passenger_installer.pp | 29 + .../passenger_uninstaller.pp | 24 + func_ruby/ext-modules/puppet_installer.mod | 116 +++ .../gems/ruby/3.3.0/cache/e2mmap-0.1.0.gem | Bin 0 -> 7680 bytes .../gems/ruby/3.3.0/cache/envbash-1.0.1.gem | Bin 0 -> 9728 bytes .../gems/ruby/3.3.0/cache/interface-1.0.5.gem | Bin 0 -> 15360 bytes .../gems/ruby/3.3.0/cache/shell-0.8.1.gem | Bin 0 -> 18432 bytes .../gems/ruby/3.3.0/cache/sync-0.5.0.gem | Bin 0 -> 8704 bytes .../gems/ruby/3.3.0/gems/e2mmap-0.1.0/Gemfile | 6 + .../ruby/3.3.0/gems/e2mmap-0.1.0/LICENSE.txt | 22 + .../ruby/3.3.0/gems/e2mmap-0.1.0/README.md | 85 +++ .../ruby/3.3.0/gems/e2mmap-0.1.0/Rakefile | 1 + .../ruby/3.3.0/gems/e2mmap-0.1.0/bin/console | 14 + .../ruby/3.3.0/gems/e2mmap-0.1.0/bin/setup | 8 + .../3.3.0/gems/e2mmap-0.1.0/e2mmap.gemspec | 26 + .../3.3.0/gems/e2mmap-0.1.0/lib/e2mmap.rb | 177 +++++ .../gems/e2mmap-0.1.0/lib/e2mmap/version.rb | 3 + .../3.3.0/gems/envbash-1.0.1/.editorconfig | 18 + .../ruby/3.3.0/gems/envbash-1.0.1/.travis.yml | 12 + .../ruby/3.3.0/gems/envbash-1.0.1/Gemfile | 2 + .../ruby/3.3.0/gems/envbash-1.0.1/LICENSE | 21 + .../ruby/3.3.0/gems/envbash-1.0.1/README.md | 71 ++ .../ruby/3.3.0/gems/envbash-1.0.1/Rakefile | 13 + .../3.3.0/gems/envbash-1.0.1/envbash.gemspec | 19 + .../3.3.0/gems/envbash-1.0.1/lib/envbash.rb | 2 + .../gems/envbash-1.0.1/lib/envbash/load.rb | 16 + .../gems/envbash-1.0.1/lib/envbash/read.rb | 62 ++ .../3.3.0/gems/envbash-1.0.1/test/helper.rb | 10 + .../gems/envbash-1.0.1/test/test_load.rb | 74 ++ .../gems/envbash-1.0.1/test/test_read.rb | 95 +++ .../ruby/3.3.0/gems/interface-1.0.5/CHANGES | 30 + .../ruby/3.3.0/gems/interface-1.0.5/MANIFEST | 12 + .../ruby/3.3.0/gems/interface-1.0.5/README | 74 ++ .../ruby/3.3.0/gems/interface-1.0.5/Rakefile | 50 ++ .../interface-1.0.5/certs/djberg96_pub.pem | 26 + .../examples/example_instance.rb | 30 + .../examples/example_interface.rb | 28 + .../interface-1.0.5/examples/example_sub.rb | 34 + .../examples/example_unrequire.rb | 26 + .../gems/interface-1.0.5/interface.gemspec | 34 + .../gems/interface-1.0.5/lib/interface.rb | 106 +++ .../interface-1.0.5/test/test_interface.rb | 64 ++ .../gems/ruby/3.3.0/gems/shell-0.8.1/Gemfile | 11 + .../ruby/3.3.0/gems/shell-0.8.1/LICENSE.txt | 22 + .../ruby/3.3.0/gems/shell-0.8.1/README.md | 97 +++ .../gems/ruby/3.3.0/gems/shell-0.8.1/Rakefile | 17 + .../ruby/3.3.0/gems/shell-0.8.1/bin/console | 7 + .../ruby/3.3.0/gems/shell-0.8.1/bin/setup | 6 + .../ruby/3.3.0/gems/shell-0.8.1/lib/shell.rb | 462 ++++++++++++ .../shell-0.8.1/lib/shell/builtin-command.rb | 147 ++++ .../lib/shell/command-processor.rb | 671 ++++++++++++++++++ .../3.3.0/gems/shell-0.8.1/lib/shell/error.rb | 26 + .../gems/shell-0.8.1/lib/shell/filter.rb | 138 ++++ .../lib/shell/process-controller.rb | 309 ++++++++ .../shell-0.8.1/lib/shell/system-command.rb | 159 +++++ .../gems/shell-0.8.1/lib/shell/version.rb | 17 + .../ruby/3.3.0/gems/shell-0.8.1/shell.gemspec | 42 ++ .../ruby/3.3.0/gems/sync-0.5.0/.travis.yml | 5 + .../gems/ruby/3.3.0/gems/sync-0.5.0/Gemfile | 5 + .../ruby/3.3.0/gems/sync-0.5.0/LICENSE.txt | 22 + .../gems/ruby/3.3.0/gems/sync-0.5.0/README.md | 77 ++ .../gems/ruby/3.3.0/gems/sync-0.5.0/Rakefile | 10 + .../ruby/3.3.0/gems/sync-0.5.0/bin/console | 7 + .../gems/ruby/3.3.0/gems/sync-0.5.0/bin/setup | 6 + .../ruby/3.3.0/gems/sync-0.5.0/lib/sync.rb | 328 +++++++++ .../ruby/3.3.0/gems/sync-0.5.0/sync.gemspec | 27 + .../3.3.0/specifications/e2mmap-0.1.0.gemspec | 26 + .../specifications/envbash-1.0.1.gemspec | 26 + .../specifications/interface-1.0.5.gemspec | 29 + .../3.3.0/specifications/shell-0.8.1.gemspec | 26 + .../3.3.0/specifications/sync-0.5.0.gemspec | 27 + func_ruby/global_options.rb | 16 + func_ruby/main.rb | 230 ++++++ func_ruby/modules.rb | 271 +++++++ func_ruby/update_required_gems.sh | 7 + install/hst-install-rhel.sh | 5 +- src/rpm/hestia/hestia.spec | 8 + src/rpm/hestia/hestia.tmpfiles | 2 +- src/rpm/nginx/hestia-nginx.service | 3 +- web/edit/extmodules/index.php | 37 + web/edit/web/index.php | 8 + web/extm/passenger_manger/edit/index.php | 0 web/list/extmodules/index.php | 24 + web/locale/ru/LC_MESSAGES/hestiacp.po | 4 + web/templates/pages/extmodules.php | 100 +++ web/templates/pages/list_services.php | 3 + 97 files changed, 5316 insertions(+), 31 deletions(-) create mode 100755 bin/v-ext-modules create mode 100644 bin/v-ext-modules-run create mode 100644 func_ruby/.bundle/config create mode 100644 func_ruby/Gemfile create mode 100644 func_ruby/Gemfile.lock create mode 100644 func_ruby/ext-modules/configs/passenger_manager/version create mode 100644 func_ruby/ext-modules/empty_module.mod create mode 100644 func_ruby/ext-modules/passenger_manager.mod create mode 100644 func_ruby/ext-modules/payload/passenger_manager/passenger_installer.pp create mode 100644 func_ruby/ext-modules/payload/passenger_manager/passenger_uninstaller.pp create mode 100644 func_ruby/ext-modules/puppet_installer.mod create mode 100644 func_ruby/gems/ruby/3.3.0/cache/e2mmap-0.1.0.gem create mode 100644 func_ruby/gems/ruby/3.3.0/cache/envbash-1.0.1.gem create mode 100644 func_ruby/gems/ruby/3.3.0/cache/interface-1.0.5.gem create mode 100644 func_ruby/gems/ruby/3.3.0/cache/shell-0.8.1.gem create mode 100644 func_ruby/gems/ruby/3.3.0/cache/sync-0.5.0.gem create mode 100644 func_ruby/gems/ruby/3.3.0/gems/e2mmap-0.1.0/Gemfile create mode 100644 func_ruby/gems/ruby/3.3.0/gems/e2mmap-0.1.0/LICENSE.txt create mode 100644 func_ruby/gems/ruby/3.3.0/gems/e2mmap-0.1.0/README.md create mode 100644 func_ruby/gems/ruby/3.3.0/gems/e2mmap-0.1.0/Rakefile create mode 100755 func_ruby/gems/ruby/3.3.0/gems/e2mmap-0.1.0/bin/console create mode 100755 func_ruby/gems/ruby/3.3.0/gems/e2mmap-0.1.0/bin/setup create mode 100644 func_ruby/gems/ruby/3.3.0/gems/e2mmap-0.1.0/e2mmap.gemspec create mode 100644 func_ruby/gems/ruby/3.3.0/gems/e2mmap-0.1.0/lib/e2mmap.rb create mode 100644 func_ruby/gems/ruby/3.3.0/gems/e2mmap-0.1.0/lib/e2mmap/version.rb create mode 100644 func_ruby/gems/ruby/3.3.0/gems/envbash-1.0.1/.editorconfig create mode 100644 func_ruby/gems/ruby/3.3.0/gems/envbash-1.0.1/.travis.yml create mode 100644 func_ruby/gems/ruby/3.3.0/gems/envbash-1.0.1/Gemfile create mode 100644 func_ruby/gems/ruby/3.3.0/gems/envbash-1.0.1/LICENSE create mode 100644 func_ruby/gems/ruby/3.3.0/gems/envbash-1.0.1/README.md create mode 100644 func_ruby/gems/ruby/3.3.0/gems/envbash-1.0.1/Rakefile create mode 100644 func_ruby/gems/ruby/3.3.0/gems/envbash-1.0.1/envbash.gemspec create mode 100644 func_ruby/gems/ruby/3.3.0/gems/envbash-1.0.1/lib/envbash.rb create mode 100644 func_ruby/gems/ruby/3.3.0/gems/envbash-1.0.1/lib/envbash/load.rb create mode 100644 func_ruby/gems/ruby/3.3.0/gems/envbash-1.0.1/lib/envbash/read.rb create mode 100644 func_ruby/gems/ruby/3.3.0/gems/envbash-1.0.1/test/helper.rb create mode 100644 func_ruby/gems/ruby/3.3.0/gems/envbash-1.0.1/test/test_load.rb create mode 100644 func_ruby/gems/ruby/3.3.0/gems/envbash-1.0.1/test/test_read.rb create mode 100644 func_ruby/gems/ruby/3.3.0/gems/interface-1.0.5/CHANGES create mode 100644 func_ruby/gems/ruby/3.3.0/gems/interface-1.0.5/MANIFEST create mode 100644 func_ruby/gems/ruby/3.3.0/gems/interface-1.0.5/README create mode 100644 func_ruby/gems/ruby/3.3.0/gems/interface-1.0.5/Rakefile create mode 100644 func_ruby/gems/ruby/3.3.0/gems/interface-1.0.5/certs/djberg96_pub.pem create mode 100644 func_ruby/gems/ruby/3.3.0/gems/interface-1.0.5/examples/example_instance.rb create mode 100644 func_ruby/gems/ruby/3.3.0/gems/interface-1.0.5/examples/example_interface.rb create mode 100644 func_ruby/gems/ruby/3.3.0/gems/interface-1.0.5/examples/example_sub.rb create mode 100644 func_ruby/gems/ruby/3.3.0/gems/interface-1.0.5/examples/example_unrequire.rb create mode 100644 func_ruby/gems/ruby/3.3.0/gems/interface-1.0.5/interface.gemspec create mode 100644 func_ruby/gems/ruby/3.3.0/gems/interface-1.0.5/lib/interface.rb create mode 100644 func_ruby/gems/ruby/3.3.0/gems/interface-1.0.5/test/test_interface.rb create mode 100644 func_ruby/gems/ruby/3.3.0/gems/shell-0.8.1/Gemfile create mode 100644 func_ruby/gems/ruby/3.3.0/gems/shell-0.8.1/LICENSE.txt create mode 100644 func_ruby/gems/ruby/3.3.0/gems/shell-0.8.1/README.md create mode 100644 func_ruby/gems/ruby/3.3.0/gems/shell-0.8.1/Rakefile create mode 100755 func_ruby/gems/ruby/3.3.0/gems/shell-0.8.1/bin/console create mode 100755 func_ruby/gems/ruby/3.3.0/gems/shell-0.8.1/bin/setup create mode 100644 func_ruby/gems/ruby/3.3.0/gems/shell-0.8.1/lib/shell.rb create mode 100644 func_ruby/gems/ruby/3.3.0/gems/shell-0.8.1/lib/shell/builtin-command.rb create mode 100644 func_ruby/gems/ruby/3.3.0/gems/shell-0.8.1/lib/shell/command-processor.rb create mode 100644 func_ruby/gems/ruby/3.3.0/gems/shell-0.8.1/lib/shell/error.rb create mode 100644 func_ruby/gems/ruby/3.3.0/gems/shell-0.8.1/lib/shell/filter.rb create mode 100644 func_ruby/gems/ruby/3.3.0/gems/shell-0.8.1/lib/shell/process-controller.rb create mode 100644 func_ruby/gems/ruby/3.3.0/gems/shell-0.8.1/lib/shell/system-command.rb create mode 100644 func_ruby/gems/ruby/3.3.0/gems/shell-0.8.1/lib/shell/version.rb create mode 100644 func_ruby/gems/ruby/3.3.0/gems/shell-0.8.1/shell.gemspec create mode 100644 func_ruby/gems/ruby/3.3.0/gems/sync-0.5.0/.travis.yml create mode 100644 func_ruby/gems/ruby/3.3.0/gems/sync-0.5.0/Gemfile create mode 100644 func_ruby/gems/ruby/3.3.0/gems/sync-0.5.0/LICENSE.txt create mode 100644 func_ruby/gems/ruby/3.3.0/gems/sync-0.5.0/README.md create mode 100644 func_ruby/gems/ruby/3.3.0/gems/sync-0.5.0/Rakefile create mode 100755 func_ruby/gems/ruby/3.3.0/gems/sync-0.5.0/bin/console create mode 100755 func_ruby/gems/ruby/3.3.0/gems/sync-0.5.0/bin/setup create mode 100644 func_ruby/gems/ruby/3.3.0/gems/sync-0.5.0/lib/sync.rb create mode 100644 func_ruby/gems/ruby/3.3.0/gems/sync-0.5.0/sync.gemspec create mode 100644 func_ruby/gems/ruby/3.3.0/specifications/e2mmap-0.1.0.gemspec create mode 100644 func_ruby/gems/ruby/3.3.0/specifications/envbash-1.0.1.gemspec create mode 100644 func_ruby/gems/ruby/3.3.0/specifications/interface-1.0.5.gemspec create mode 100644 func_ruby/gems/ruby/3.3.0/specifications/shell-0.8.1.gemspec create mode 100644 func_ruby/gems/ruby/3.3.0/specifications/sync-0.5.0.gemspec create mode 100644 func_ruby/global_options.rb create mode 100644 func_ruby/main.rb create mode 100644 func_ruby/modules.rb create mode 100644 func_ruby/update_required_gems.sh create mode 100644 web/edit/extmodules/index.php create mode 100644 web/extm/passenger_manger/edit/index.php create mode 100644 web/list/extmodules/index.php create mode 100644 web/templates/pages/extmodules.php diff --git a/bin/v-add-user-sftp-jail b/bin/v-add-user-sftp-jail index 8abbf22..03856ac 100755 --- a/bin/v-add-user-sftp-jail +++ b/bin/v-add-user-sftp-jail @@ -14,6 +14,10 @@ user=$1 restart=$2 +if [ "$user" == "puppet" ]; then + exit +fi + # Includes # shellcheck source=/etc/hestiacp/hestia.conf source /etc/hestiacp/hestia.conf diff --git a/bin/v-ext-modules b/bin/v-ext-modules new file mode 100755 index 0000000..e2ccbdc --- /dev/null +++ b/bin/v-ext-modules @@ -0,0 +1,152 @@ +#!/opt/brepo/ruby33/bin/ruby +# info: action with extended modules +# options: COMMAND [COMMAND_OPTION | FORMAT] [FORMAT] +# +# example: v-ext-modules list json +# +# This function enables and disables additional modules + +#----------------------------------------------------------# +# Variables & Functions # +#----------------------------------------------------------# + +# Argument definition +v_command = ARGV[0] +v_ext_option = ARGV[1] +v_format = ARGV[2] + +require "/usr/local/hestia/func_ruby/global_options" + +load_ruby_options_defaults +$HESTIA = load_hestia_default_path_from_env + +require "main" +require "modules" + +hestia_check_privileged_user + +load_global_bash_variables "/etc/hestiacp/hestia.conf" +if $HESTIA.nil? + hestia_print_error_message_to_cli "Can't find HESTIA base path" + exit 1 +end + +load_global_bash_variables "#{$HESTIA}/conf/hestia.conf" + +#----------------------------------------------------------# +# Verifications # +#----------------------------------------------------------# + +check_args 1, ARGV, "COMMAND [COMMAND_OPTION] [ACTION]" + +# Perform verification if read-only mode is enabled +check_hestia_demo_mode + +#----------------------------------------------------------# +# Action # +#----------------------------------------------------------# + +case v_command.to_sym +when :list, :state + info = [] + pm = PluginManager.new + if v_command.to_sym == :state + if v_ext_option.nil? + hestia_print_error_message_to_cli "no module name specified" + log_event E_ARGS, $ARGUMENTS + exit 1 + end + load_module = v_ext_option.to_s.strip.split(",")[0].to_s.strip + pm.load_plugins(nil, load_module) + else + pm.load_plugins + end + pm.get_loaded_plugins.each_key do |mod| + next if mod == "default" + + inst = pm.get_instance(mod) + if inst.key != pm.get_key + hestia_print_error_message_to_cli "incorrect module with incorrect rights #{mod}" + log_event E_ARGS, $ARGUMENTS + exit 1 + end + info_result = inst.info + info_result[:STATE] = hestia_ext_module_state_in_conf(info_result[:NAME], :get) + info << info_result + end + result_arr = info.sort do |a, b| + if a[:ID] < b[:ID] + -1 + elsif a[:ID] > b[:ID] + 1 + else + a[:ID] < b[:ID] + end + end + if v_command.to_sym == :state + format = (v_format.nil? ? "shell" : v_format.strip) + else + format = (v_ext_option.nil? ? "shell" : v_ext_option.strip) + end + hestia_print_array_of_hashes(result_arr, format, "ID, NAME, DESCR, STATE, REQ") +when :enable + if v_ext_option.nil? + hestia_print_error_message_to_cli "no module name specified" + log_event E_ARGS, $ARGUMENTS + exit 1 + end + pm = PluginManager.new + load_module = v_ext_option.to_s.strip.split(",")[0].to_s.strip + pm.load_plugins(nil, load_module) + if pm.get_loaded_plugins.key? load_module + if hestia_ext_module_state_in_conf(load_module, :get) == "disabled" + inst = pm.get_instance(load_module) + result = inst.enable() + if result == "" + hestia_ext_module_state_in_conf(load_module, :enable) + log_event OK, $ARGUMENTS + else + hestia_print_error_message_to_cli "module #{load_module} return error #{result}" + log_event E_MODULE, $ARGUMENTS + exit 1 + end + end + else + hestia_print_error_message_to_cli "no module with name #{load_module} found" + log_event E_INVALID, $ARGUMENTS + exit 1 + end +when :disable + if v_ext_option.nil? + hestia_print_error_message_to_cli "no module name specified" + log_event E_ARGS, $ARGUMENTS + exit 1 + end + pm = PluginManager.new + load_module = v_ext_option.to_s.strip.split(",")[0].to_s.strip + pm.load_plugins(nil, load_module) + if pm.get_loaded_plugins.key? load_module + if hestia_ext_module_state_in_conf(load_module, :get) == "enabled" + inst = pm.get_instance(load_module) + result = inst.disable() + if result == "" + hestia_ext_module_state_in_conf(load_module, :disable) + log_event OK, $ARGUMENTS + else + hestia_print_error_message_to_cli "module #{load_module} return error #{result}" + log_event E_MODULE, $ARGUMENTS + exit 1 + end + end + else + hestia_print_error_message_to_cli "no module with name #{load_module} found" + log_event E_INVALID, $ARGUMENTS + exit 1 + end +else + hestia_print_error_message_to_cli "unknown command" + log_event E_INVALID, $ARGUMENTS + exit 1 +end + +exit 0 diff --git a/bin/v-ext-modules-run b/bin/v-ext-modules-run new file mode 100644 index 0000000..f7c21fa --- /dev/null +++ b/bin/v-ext-modules-run @@ -0,0 +1,82 @@ +#!/opt/brepo/ruby33/bin/ruby +# info: action with extended modules +# options: MODULE_ID [MODULE_RELATED_COMMNDS] +# +# example: v-ext-modules list json +# +# This function enables and disables additional modules + +#----------------------------------------------------------# +# Variables & Functions # +#----------------------------------------------------------# + +# Argument definition +v_id = ARGV[0] + +require "/usr/local/hestia/func_ruby/global_options" + +load_ruby_options_defaults +$HESTIA = load_hestia_default_path_from_env + +require "main" +require "modules" + +hestia_check_privileged_user + +load_global_bash_variables "/etc/hestiacp/hestia.conf" +if $HESTIA.nil? + hestia_print_error_message_to_cli "Can't find HESTIA base path" + exit 1 +end + +load_global_bash_variables "#{$HESTIA}/conf/hestia.conf" + +#----------------------------------------------------------# +# Verifications # +#----------------------------------------------------------# + +check_args 1, ARGV, "MODULE_ID [MODULE_RELATED_COMMNDS]" + +# Perform verification if read-only mode is enabled +check_hestia_demo_mode + +#----------------------------------------------------------# +# Action # +#----------------------------------------------------------# + +if v_id.nil? + hestia_print_error_message_to_cli "no module name specified" + log_event E_ARGS, $ARGUMENTS + exit 1 +end +pm = PluginManager.new +load_module = v_id.strip +pm.load_plugins(nil, load_module) +if pm.get_loaded_plugins.key? load_module + if hestia_ext_module_state_in_conf(load_module, :get) == "enabled" + inst = pm.get_instance(load_module) + NEW_ARGV = if ARGV.length > 0 + ARGV.drop(1) + else + ARGV + end + result = inst.command(NEW_ARGV) + if result == "" + log_event OK, $ARGUMENTS + else + hestia_print_error_message_to_cli "module #{load_module} return error #{result}" + log_event E_MODULE, $ARGUMENTS + exit 1 + end + else + hestia_print_error_message_to_cli "module #{load_module} disabled" + log_event E_INVALID, $ARGUMENTS + exit 1 + end +else + hestia_print_error_message_to_cli "no module with name #{load_module} found" + log_event E_INVALID, $ARGUMENTS + exit 1 +end + +exit 0 diff --git a/bin/v-list-sys-info b/bin/v-list-sys-info index 66b462e..b39b3f4 100755 --- a/bin/v-list-sys-info +++ b/bin/v-list-sys-info @@ -69,8 +69,8 @@ HOSTNAME=$(hostname) # Check OS/Release if [ -d '/etc/sysconfig' ]; then if [ -e '/etc/redhat-release' ]; then - OS='CentOS' - VERSION=$(cat /etc/redhat-release | tr ' ' '\n' | grep [0-9]) + OS=$(cat /etc/redhat-release | cut -d' ' -f1) + VERSION=$(cat /etc/redhat-release | tr ' ' '\n' | grep -P "\d+(\.\d+)?") else OS="Amazon" VERSION=$(cat /etc/issue | tr ' ' '\n' | grep [0-9]) diff --git a/func/upgrade.sh b/func/upgrade.sh index d69d71c..1bb2c79 100644 --- a/func/upgrade.sh +++ b/func/upgrade.sh @@ -118,11 +118,6 @@ upgrade_complete_message() { echo "=============================================================================" echo echo "Upgrade complete! If you encounter any issues or find a bug, " - echo "please take a moment to report it to us on GitHub at the URL below: " - echo "https://github.com/hestiacp/hestiacp/issues " - echo - echo "Read the release notes to learn about new fixes and features: " - echo "https://github.com/hestiacp/hestiacp/blob/release/CHANGELOG.md " echo echo "We hope that you enjoy using this version of Hestia Control Panel, " echo "have a wonderful day! " @@ -130,13 +125,6 @@ upgrade_complete_message() { echo "Sincerely, " echo "The Hestia Control Panel development team " echo - echo "Web: https://www.hestiacp.com/ " - echo "Docs: https://docs.hestiacp.com/ " - echo "Forum: https://forum.hestiacp.com/ " - echo "GitHub: https://github.com/hestiacp/hestiacp/ " - echo - echo "Help support the Hestia Control Panel project by donating via PayPal: " - echo "https://www.hestiacp.com/donate " echo echo "Made with love & pride by the open-source community around the world. " echo @@ -148,8 +136,6 @@ upgrade_complete_message_log() { echo echo "=============================================================================" echo "UPGRADE COMPLETE. " - echo "Please report any issues on GitHub: " - echo "https://github.com/hestiacp/hestiacp/issues " echo "=============================================================================" echo $BIN/v-log-action "system" "Info" "Updates" "Update installed (Version: $new_version)." @@ -219,17 +205,6 @@ upgrade_send_notification_to_email() { echo "" >> $message_tmp_file fi - echo "What's new: https://github.com/hestiacp/hestiacp/blob/$RELEASE_BRANCH/CHANGELOG.md" >> $message_tmp_file - echo >> $message_tmp_file - echo "What to do if you run into issues:" >> $message_tmp_file - echo "- Check our forums for possible solutions: https://forum.hestiacp.com" >> $message_tmp_file - echo "- File an issue report on GitHub: https://github.com/hestiacp/hestiacp/issues" >> $message_tmp_file - echo "" >> $message_tmp_file - echo "Help support the Hestia Control Panel project by donating via PayPal: https://www.hestiacp.com/donate" >> $message_tmp_file - echo "===================================================" >> $message_tmp_file - echo "Have a wonderful day," >> $message_tmp_file - echo "The Hestia Control Panel development team" >> $message_tmp_file - # Read back message from file and pass through to sendmail cat $message_tmp_file | $send_mail -s "Update Installed - v${new_version}" $admin_email rm -f $message_tmp_file diff --git a/func_ruby/.bundle/config b/func_ruby/.bundle/config new file mode 100644 index 0000000..6efc687 --- /dev/null +++ b/func_ruby/.bundle/config @@ -0,0 +1,2 @@ +--- +BUNDLE_PATH: "gems" diff --git a/func_ruby/Gemfile b/func_ruby/Gemfile new file mode 100644 index 0000000..3c0c923 --- /dev/null +++ b/func_ruby/Gemfile @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +source "https://rubygems.org" + +gem "envbash" +gem "interface" +gem "shell" \ No newline at end of file diff --git a/func_ruby/Gemfile.lock b/func_ruby/Gemfile.lock new file mode 100644 index 0000000..1216ebb --- /dev/null +++ b/func_ruby/Gemfile.lock @@ -0,0 +1,22 @@ +GEM + remote: https://rubygems.org/ + specs: + e2mmap (0.1.0) + envbash (1.0.1) + interface (1.0.5) + shell (0.8.1) + e2mmap + sync + sync (0.5.0) + +PLATFORMS + ruby + x86_64-linux + +DEPENDENCIES + envbash + interface + shell + +BUNDLED WITH + 2.5.16 diff --git a/func_ruby/ext-modules/configs/passenger_manager/version b/func_ruby/ext-modules/configs/passenger_manager/version new file mode 100644 index 0000000..8a9ecc2 --- /dev/null +++ b/func_ruby/ext-modules/configs/passenger_manager/version @@ -0,0 +1 @@ +0.0.1 \ No newline at end of file diff --git a/func_ruby/ext-modules/empty_module.mod b/func_ruby/ext-modules/empty_module.mod new file mode 100644 index 0000000..5379d37 --- /dev/null +++ b/func_ruby/ext-modules/empty_module.mod @@ -0,0 +1,30 @@ +#!/opt/brepo/ruby33/bin/ruby + +class EmptyWorker < Kernel::ModuleCoreWorker + MODULE_ID = "empty_module" + + def info + { + ID: 3, + NAME: MODULE_ID, + DESCR: "Just empty module for storing max module id", + REQ: "", + } + end + + implements IPluginInterface +end + +module EmptyModule + def get_object + Proc.new { EmptyWorker.new } + end + + module_function :get_object +end + +class Kernel::PluginConfiguration + include EmptyModule + + @@loaded_plugins[EmptyWorker::MODULE_ID] = EmptyModule.get_object +end diff --git a/func_ruby/ext-modules/passenger_manager.mod b/func_ruby/ext-modules/passenger_manager.mod new file mode 100644 index 0000000..962ca2b --- /dev/null +++ b/func_ruby/ext-modules/passenger_manager.mod @@ -0,0 +1,108 @@ +#!/opt/brepo/ruby33/bin/ruby + +require "shell" + +class PassengerWorker < Kernel::ModuleCoreWorker + MODULE_ID = "passenger_manager" + + def check_domains_with_passenger + true + end + + def info + { + ID: 2, + NAME: MODULE_ID, + DESCR: "Added passenger support for nginx", + REQ: "puppet_installer", + } + end + + def enable + log_file = get_log + f_inst_pp = get_module_paydata("passenger_installer.pp") + f_uninst_pp = get_module_paydata("passenger_uninstaller.pp") + if !check + inf = info + log("Req error, needed #{inf[:REQ]}") + "Req error, needed #{inf[:REQ]}" + else + begin + log("install packages for passenger + nginx support: /usr/bin/puppet apply --detailed-exitcodes #{f_inst_pp}") + result_action = `/usr/bin/puppet apply --detailed-exitcodes "#{f_inst_pp}"` + ex_status = $?.exitstatus + if ex_status.to_i == 0 || ex_status.to_i == 2 + log(result_action) + super + else + log(result_action) + log("Try to disable action: /usr/bin/puppet apply --detailed-exitcodes #{f_uninst_pp}") + result_action = `/usr/bin/puppet apply --detailed-exitcodes "#{f_uninst_pp}"` + "module installation error. See log #{log_file}" + end + rescue => e + log("module installation error #{e.message} #{e.backtrace.first}") + "module installation error. See log #{log_file}" + end + end + end + + def disable + log_file = get_log + f_uninst_pp = get_module_paydata("passenger_uninstaller.pp") + if !check_domains_with_passenger + return "Presents domains with passenger support disable it first" + end + begin + log("uninstall packages for passenger + nginx support") + log("Try to disable action: /usr/bin/puppet apply --detailed-exitcodes #{f_uninst_pp}") + result_action = `/usr/bin/puppet apply --detailed-exitcodes "#{f_uninst_pp}"` + ex_status = $?.exitstatus + if ex_status.to_i == 0 || ex_status.to_i == 2 + log(result_action) + super + else + log(result_action) + "module installation error. See log #{log_file}" + end + rescue => e + log("module installation error #{e.message} #{e.backtrace.first}") + "module installation error. See log #{log_file}" + end + end + + def prepare_default_ruby_conf() + #TODO + end + + def command(args) + if args.length < 1 + log("Not enough arguments. Needed command") + "Not enough arguments. Needed command" + end + m_command = args[0].strip + case m_command + when "get_rubys" + #TODO + else + log("Unknown commands. #{args}") + "Unknown commands. #{args}" + end + end + + implements IPluginInterface +end + +module PassengerModule + def get_object + Proc.new { PassengerWorker.new } + end + + module_function :get_object +end + +class Kernel::PluginConfiguration + include PassengerModule + + @@loaded_plugins[PassengerWorker::MODULE_ID] = PassengerModule.get_object +end diff --git a/func_ruby/ext-modules/payload/passenger_manager/passenger_installer.pp b/func_ruby/ext-modules/payload/passenger_manager/passenger_installer.pp new file mode 100644 index 0000000..32dcb93 --- /dev/null +++ b/func_ruby/ext-modules/payload/passenger_manager/passenger_installer.pp @@ -0,0 +1,29 @@ +package { 'passenger': + ensure => installed, + name => 'passenger', + provider => 'dnf', +} +-> package { 'nginx-passenger': + ensure => installed, + name => 'nginx-mod-http-passenger', + provider => 'dnf', +} +-> file { 'passenger.conf': + ensure => file, + path => '/etc/nginx/conf.d/passenger.conf', + content => 'passenger_root /usr/share/ruby/vendor_ruby/phusion_passenger/locations.ini; +passenger_ruby /usr/bin/ruby; +passenger_instance_registry_dir /var/run/passenger-instreg; +passenger_user_switching on;', +} +-> file { 'passenger_includer.conf': + ensure => file, + content => 'load_module modules/ngx_http_passenger_module.so;', + path => '/etc/nginx/conf.d/main/passenger.conf', +} +~> service { 'nginx_service': + ensure => running, + name => 'nginx', + provider => 'systemd', + hasrestart => true, +} diff --git a/func_ruby/ext-modules/payload/passenger_manager/passenger_uninstaller.pp b/func_ruby/ext-modules/payload/passenger_manager/passenger_uninstaller.pp new file mode 100644 index 0000000..0e3a511 --- /dev/null +++ b/func_ruby/ext-modules/payload/passenger_manager/passenger_uninstaller.pp @@ -0,0 +1,24 @@ +package { 'nginx-passenger': + ensure => absent, + name => 'nginx-mod-http-passenger', + provider => 'dnf', +} +-> package { 'passenger': + ensure => absent, + name => 'passenger', + provider => 'dnf', +} +-> file { 'passenger.conf': + ensure => absent, + path => '/etc/nginx/conf.d/passenger.conf', +} +-> file { 'passenger_includer.conf': + ensure => absent, + path => '/etc/nginx/conf.d/main/passenger.conf', +} +~> service { 'nginx_service': + ensure => running, + name => 'nginx', + provider => 'systemd', + hasrestart => true, +} diff --git a/func_ruby/ext-modules/puppet_installer.mod b/func_ruby/ext-modules/puppet_installer.mod new file mode 100644 index 0000000..b81ebde --- /dev/null +++ b/func_ruby/ext-modules/puppet_installer.mod @@ -0,0 +1,116 @@ +#!/opt/brepo/ruby33/bin/ruby + +require "shell" +require "date" + +class PuppetWorker < Kernel::ModuleCoreWorker + MODULE_ID = "puppet_installer" + + def info + { + ID: 1, + NAME: MODULE_ID, + DESCR: "Added puppet support, needed for another modules", + REQ: "", + } + end + + def enable + log_file = get_log + date = DateTime.now + bkp_name = date.strftime("%Y_%m_%d_%H_%M_%S") + if !check + inf = info + log("Req error, needed #{inf[:REQ]}") + "Req error, needed #{inf[:REQ]}" + else + Shell.def_system_command("dnf", "/usr/bin/dnf") + Shell.def_system_command("gem", "/usr/bin/gem") + Shell.verbose = true + Shell.debug = false + sh = Shell.new + begin + %x( /usr/bin/rpm -q puppet ) + unless $?.success? + log("install puppet packages") + sh.transact do + dnf("install", "-y", "puppet", "ruby", "rubygems", "puppet-stdlib") > log_file + gem("cleanup", "thor") > log_file + end + else + log("puppet installed") + end + log("prepare puppet configuration") + if File.exist?("/etc/puppet/puppet.conf") + File.rename("/etc/puppet/puppet.conf", "/etc/puppet/puppet.conf.#{bkp_name}") + end + puppet_conf = <<~CONF + [main] + confdir=/etc/puppet + logdir=/var/log/puppet + vardir=/var/lib/puppet + ssldir=/var/lib/puppet/ssl + rundir=/var/run/puppet + factpath=$confdir/facter + environmentpath=$confdir/environments + basemodulepath=/usr/share/puppet/modules + default_manifest=$confdir/manifests + environment_timeout = unlimited + manifests_path =$confdir/manifests + CONF + File.open("/etc/puppet/puppet.conf", "w") do |f| + f.puts(puppet_conf) + end + log("prepare hiera configuration") + if File.exist?("/etc/puppet/hiera.yaml") + File.rename("/etc/puppet/hiera.yaml", "/etc/puppet/hiera.yaml.#{bkp_name}") + end + hiera_conf = <<~CONF + --- + version: 5 + hierarchy: + - name: "yaml" + datadir: /tmp/puppet/hieradata + # data is staged to a local directory by the puppet-manifest-apply.sh script + data_hash: yaml_data + paths: + - runtime.yaml + - host.yaml + - secure_system.yaml + - system.yaml + - secure_static.yaml + - static.yaml + - personality.yaml + - global.yaml + CONF + File.open("/etc/puppet/hiera.yaml", "w") do |f| + f.puts(hiera_conf) + end + log("create manifests directory") + sh.transact do + ((mkdir("/etc/puppet/manifests")) > log_file) unless File.exist?("/etc/puppet/manifests") + end + super + rescue => e + log("module installation error #{e.message} #{e.backtrace.first}") + "module installation error. See log #{log_file}" + end + end + end + + implements IPluginInterface +end + +module PuppetModule + def get_object + Proc.new { PuppetWorker.new } + end + + module_function :get_object +end + +class Kernel::PluginConfiguration + include PuppetModule + + @@loaded_plugins[PuppetWorker::MODULE_ID] = PuppetModule.get_object +end diff --git a/func_ruby/gems/ruby/3.3.0/cache/e2mmap-0.1.0.gem b/func_ruby/gems/ruby/3.3.0/cache/e2mmap-0.1.0.gem new file mode 100644 index 0000000000000000000000000000000000000000..c5d26939849b22dfa667f1d8c0b24dfe19be1fe4 GIT binary patch literal 7680 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 literal 0 HcmV?d00001 diff --git a/func_ruby/gems/ruby/3.3.0/cache/envbash-1.0.1.gem b/func_ruby/gems/ruby/3.3.0/cache/envbash-1.0.1.gem new file mode 100644 index 0000000000000000000000000000000000000000..0c9ce5d58ca2262bbc597d7325f447df2ad8eaa8 GIT binary patch literal 9728 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 literal 0 HcmV?d00001 diff --git a/func_ruby/gems/ruby/3.3.0/cache/shell-0.8.1.gem b/func_ruby/gems/ruby/3.3.0/cache/shell-0.8.1.gem new file mode 100644 index 0000000000000000000000000000000000000000..d7d8bf56fa03d1c734630cf4bda5c7091b256c68 GIT binary patch literal 18432 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 literal 0 HcmV?d00001 diff --git a/func_ruby/gems/ruby/3.3.0/cache/sync-0.5.0.gem b/func_ruby/gems/ruby/3.3.0/cache/sync-0.5.0.gem new file mode 100644 index 0000000000000000000000000000000000000000..1aa977b6701e0382d1e6e84190d8838a69e4ec1a GIT binary patch literal 8704 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 RWBlELzdP`E2may?{2N3QuL}SG literal 0 HcmV?d00001 diff --git a/func_ruby/gems/ruby/3.3.0/gems/e2mmap-0.1.0/Gemfile b/func_ruby/gems/ruby/3.3.0/gems/e2mmap-0.1.0/Gemfile new file mode 100644 index 0000000..f53ebba --- /dev/null +++ b/func_ruby/gems/ruby/3.3.0/gems/e2mmap-0.1.0/Gemfile @@ -0,0 +1,6 @@ +source "https://rubygems.org" + +git_source(:github) {|repo_name| "https://github.com/#{repo_name}" } + +# Specify your gem's dependencies in e2mmap.gemspec +gemspec diff --git a/func_ruby/gems/ruby/3.3.0/gems/e2mmap-0.1.0/LICENSE.txt b/func_ruby/gems/ruby/3.3.0/gems/e2mmap-0.1.0/LICENSE.txt new file mode 100644 index 0000000..a009cae --- /dev/null +++ b/func_ruby/gems/ruby/3.3.0/gems/e2mmap-0.1.0/LICENSE.txt @@ -0,0 +1,22 @@ +Copyright (C) 1993-2013 Yukihiro Matsumoto. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. diff --git a/func_ruby/gems/ruby/3.3.0/gems/e2mmap-0.1.0/README.md b/func_ruby/gems/ruby/3.3.0/gems/e2mmap-0.1.0/README.md new file mode 100644 index 0000000..99928d1 --- /dev/null +++ b/func_ruby/gems/ruby/3.3.0/gems/e2mmap-0.1.0/README.md @@ -0,0 +1,85 @@ +# Exception2MessageMapper + +Helper module for easily defining exceptions with predefined messages. + +## Installation + +Add this line to your application's Gemfile: + +```ruby +gem 'e2mmap' +``` + +And then execute: + + $ bundle + +Or install it yourself as: + + $ gem install e2mmap + +## Usage + +1. + +``` +class Foo + extend Exception2MessageMapper + def_e2message ExistingExceptionClass, "message..." + def_exception :NewExceptionClass, "message..."[, superclass] + ... +end +``` + +2. + +``` +module Error + extend Exception2MessageMapper + def_e2message ExistingExceptionClass, "message..." + def_exception :NewExceptionClass, "message..."[, superclass] + ... +end + +class Foo + include Error + ... +end + +foo = Foo.new +foo.Fail .... +``` + +3. + +``` +module Error + extend Exception2MessageMapper + def_e2message ExistingExceptionClass, "message..." + def_exception :NewExceptionClass, "message..."[, superclass] + ... +end + +class Foo + extend Exception2MessageMapper + include Error + ... +end + +Foo.Fail NewExceptionClass, arg... +Foo.Fail ExistingExceptionClass, arg... +``` + +## Development + +After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment. + +To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org). + +## Contributing + +Bug reports and pull requests are welcome on GitHub at https://github.com/ruby/e2mmap. + +## License + +The gem is available as open source under the terms of the [2-Clause BSD License](https://opensource.org/licenses/BSD-2-Clause). diff --git a/func_ruby/gems/ruby/3.3.0/gems/e2mmap-0.1.0/Rakefile b/func_ruby/gems/ruby/3.3.0/gems/e2mmap-0.1.0/Rakefile new file mode 100644 index 0000000..2995527 --- /dev/null +++ b/func_ruby/gems/ruby/3.3.0/gems/e2mmap-0.1.0/Rakefile @@ -0,0 +1 @@ +require "bundler/gem_tasks" diff --git a/func_ruby/gems/ruby/3.3.0/gems/e2mmap-0.1.0/bin/console b/func_ruby/gems/ruby/3.3.0/gems/e2mmap-0.1.0/bin/console new file mode 100755 index 0000000..9e353bc --- /dev/null +++ b/func_ruby/gems/ruby/3.3.0/gems/e2mmap-0.1.0/bin/console @@ -0,0 +1,14 @@ +#!/usr/bin/env ruby + +require "bundler/setup" +require "e2mmap" + +# You can add fixtures and/or initialization code here to make experimenting +# with your gem easier. You can also use a different console, if you like. + +# (If you use this, don't forget to add pry to your Gemfile!) +# require "pry" +# Pry.start + +require "irb" +IRB.start(__FILE__) diff --git a/func_ruby/gems/ruby/3.3.0/gems/e2mmap-0.1.0/bin/setup b/func_ruby/gems/ruby/3.3.0/gems/e2mmap-0.1.0/bin/setup new file mode 100755 index 0000000..dce67d8 --- /dev/null +++ b/func_ruby/gems/ruby/3.3.0/gems/e2mmap-0.1.0/bin/setup @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +IFS=$'\n\t' +set -vx + +bundle install + +# Do any other automated setup that you need to do here diff --git a/func_ruby/gems/ruby/3.3.0/gems/e2mmap-0.1.0/e2mmap.gemspec b/func_ruby/gems/ruby/3.3.0/gems/e2mmap-0.1.0/e2mmap.gemspec new file mode 100644 index 0000000..b9808d8 --- /dev/null +++ b/func_ruby/gems/ruby/3.3.0/gems/e2mmap-0.1.0/e2mmap.gemspec @@ -0,0 +1,26 @@ +begin + require_relative "lib/e2mmap/version" +rescue LoadError + # for Ruby core repository + require_relative "e2mmap/version" +end + +Gem::Specification.new do |spec| + spec.name = "e2mmap" + spec.version = Exception2MessageMapper::VERSION + spec.authors = ["Keiju ISHITSUKA"] + spec.email = ["keiju@ruby-lang.org"] + + spec.summary = %q{Module for defining custom exceptions with specific messages.} + spec.description = %q{Module for defining custom exceptions with specific messages.} + spec.homepage = "https://github.com/ruby/e2mmap" + spec.license = "BSD-2-Clause" + + spec.files = [".gitignore", "Gemfile", "LICENSE.txt", "README.md", "Rakefile", "bin/console", "bin/setup", "e2mmap.gemspec", "lib/e2mmap.rb", "lib/e2mmap/version.rb"] + spec.bindir = "exe" + spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } + spec.require_paths = ["lib"] + + spec.add_development_dependency "bundler", "~> 1.16" + spec.add_development_dependency "rake", "~> 10.0" +end diff --git a/func_ruby/gems/ruby/3.3.0/gems/e2mmap-0.1.0/lib/e2mmap.rb b/func_ruby/gems/ruby/3.3.0/gems/e2mmap-0.1.0/lib/e2mmap.rb new file mode 100644 index 0000000..1c1d714 --- /dev/null +++ b/func_ruby/gems/ruby/3.3.0/gems/e2mmap-0.1.0/lib/e2mmap.rb @@ -0,0 +1,177 @@ +# frozen_string_literal: true +# +#-- +# e2mmap.rb - for Ruby 1.1 +# $Release Version: 2.0$ +# $Revision: 1.10 $ +# by Keiju ISHITSUKA +# +#++ +# +# Helper module for easily defining exceptions with predefined messages. +# +# == Usage +# +# 1. +# class Foo +# extend Exception2MessageMapper +# def_e2message ExistingExceptionClass, "message..." +# def_exception :NewExceptionClass, "message..."[, superclass] +# ... +# end +# +# 2. +# module Error +# extend Exception2MessageMapper +# def_e2message ExistingExceptionClass, "message..." +# def_exception :NewExceptionClass, "message..."[, superclass] +# ... +# end +# class Foo +# include Error +# ... +# end +# +# foo = Foo.new +# foo.Fail .... +# +# 3. +# module Error +# extend Exception2MessageMapper +# def_e2message ExistingExceptionClass, "message..." +# def_exception :NewExceptionClass, "message..."[, superclass] +# ... +# end +# class Foo +# extend Exception2MessageMapper +# include Error +# ... +# end +# +# Foo.Fail NewExceptionClass, arg... +# Foo.Fail ExistingExceptionClass, arg... +# +# +module Exception2MessageMapper + + E2MM = Exception2MessageMapper # :nodoc: + + def E2MM.extend_object(cl) + super + cl.bind(self) unless cl < E2MM + end + + def bind(cl) + self.module_eval "#{<<-"begin;"}\n#{<<-"end;"}", __FILE__, __LINE__+1 + begin; + def Raise(err = nil, *rest) + Exception2MessageMapper.Raise(self.class, err, *rest) + end + alias Fail Raise + + class << self + undef included + end + def self.included(mod) + mod.extend Exception2MessageMapper + end + end; + end + + # Fail(err, *rest) + # err: exception + # rest: message arguments + # + def Raise(err = nil, *rest) + E2MM.Raise(self, err, *rest) + end + alias Fail Raise + alias fail Raise + + # def_e2message(c, m) + # c: exception + # m: message_form + # define exception c with message m. + # + def def_e2message(c, m) + E2MM.def_e2message(self, c, m) + end + + # def_exception(n, m, s) + # n: exception_name + # m: message_form + # s: superclass(default: StandardError) + # define exception named ``c'' with message m. + # + def def_exception(n, m, s = StandardError) + E2MM.def_exception(self, n, m, s) + end + + # + # Private definitions. + # + # {[class, exp] => message, ...} + @MessageMap = {} + + # E2MM.def_e2message(k, e, m) + # k: class to define exception under. + # e: exception + # m: message_form + # define exception c with message m. + # + def E2MM.def_e2message(k, c, m) + E2MM.instance_eval{@MessageMap[[k, c]] = m} + c + end + + # E2MM.def_exception(k, n, m, s) + # k: class to define exception under. + # n: exception_name + # m: message_form + # s: superclass(default: StandardError) + # define exception named ``c'' with message m. + # + def E2MM.def_exception(k, n, m, s = StandardError) + e = Class.new(s) + E2MM.instance_eval{@MessageMap[[k, e]] = m} + k.module_eval {remove_const(n)} if k.const_defined?(n, false) + k.const_set(n, e) + end + + # Fail(klass, err, *rest) + # klass: class to define exception under. + # err: exception + # rest: message arguments + # + def E2MM.Raise(klass = E2MM, err = nil, *rest) + if form = e2mm_message(klass, err) + b = $@.nil? ? caller(1) : $@ + b.shift if b[0] =~ /^#{Regexp.quote(__FILE__)}:/ + raise err, sprintf(form, *rest), b + else + E2MM.Fail E2MM, ErrNotRegisteredException, err.inspect + end + end + class << E2MM + alias Fail Raise + end + + def E2MM.e2mm_message(klass, exp) + for c in klass.ancestors + if mes = @MessageMap[[c,exp]] + m = klass.instance_eval('"' + mes + '"') + return m + end + end + nil + end + class << self + alias message e2mm_message + end + + E2MM.def_exception(E2MM, + :ErrNotRegisteredException, + "not registered exception(%s)") +end + + diff --git a/func_ruby/gems/ruby/3.3.0/gems/e2mmap-0.1.0/lib/e2mmap/version.rb b/func_ruby/gems/ruby/3.3.0/gems/e2mmap-0.1.0/lib/e2mmap/version.rb new file mode 100644 index 0000000..c459aea --- /dev/null +++ b/func_ruby/gems/ruby/3.3.0/gems/e2mmap-0.1.0/lib/e2mmap/version.rb @@ -0,0 +1,3 @@ +module Exception2MessageMapper + VERSION = "0.1.0" +end diff --git a/func_ruby/gems/ruby/3.3.0/gems/envbash-1.0.1/.editorconfig b/func_ruby/gems/ruby/3.3.0/gems/envbash-1.0.1/.editorconfig new file mode 100644 index 0000000..c161e08 --- /dev/null +++ b/func_ruby/gems/ruby/3.3.0/gems/envbash-1.0.1/.editorconfig @@ -0,0 +1,18 @@ +root = true + +# Unix-style newlines with a newline ending every file +[*] +charset = utf-8 +indent_style = space +indent_size = 4 +tab_width = 8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true + +[*.{json,rb,yaml,yml}] +indent_size = 2 + +# Tab indents for Makefile +[Makefile] +indent_style = tab diff --git a/func_ruby/gems/ruby/3.3.0/gems/envbash-1.0.1/.travis.yml b/func_ruby/gems/ruby/3.3.0/gems/envbash-1.0.1/.travis.yml new file mode 100644 index 0000000..e59fe67 --- /dev/null +++ b/func_ruby/gems/ruby/3.3.0/gems/envbash-1.0.1/.travis.yml @@ -0,0 +1,12 @@ +sudo: false +language: ruby +cache: bundler +rvm: +- 2.1 +- 2.2 +- 2.3.3 +- 2.4.0 +install: +- bundle +script: +- rake diff --git a/func_ruby/gems/ruby/3.3.0/gems/envbash-1.0.1/Gemfile b/func_ruby/gems/ruby/3.3.0/gems/envbash-1.0.1/Gemfile new file mode 100644 index 0000000..3be9c3c --- /dev/null +++ b/func_ruby/gems/ruby/3.3.0/gems/envbash-1.0.1/Gemfile @@ -0,0 +1,2 @@ +source "https://rubygems.org" +gemspec diff --git a/func_ruby/gems/ruby/3.3.0/gems/envbash-1.0.1/LICENSE b/func_ruby/gems/ruby/3.3.0/gems/envbash-1.0.1/LICENSE new file mode 100644 index 0000000..fa448b7 --- /dev/null +++ b/func_ruby/gems/ruby/3.3.0/gems/envbash-1.0.1/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 Scampersand LLC + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/func_ruby/gems/ruby/3.3.0/gems/envbash-1.0.1/README.md b/func_ruby/gems/ruby/3.3.0/gems/envbash-1.0.1/README.md new file mode 100644 index 0000000..95ddf8d --- /dev/null +++ b/func_ruby/gems/ruby/3.3.0/gems/envbash-1.0.1/README.md @@ -0,0 +1,71 @@ +# envbash + +[![gem](https://img.shields.io/gem/v/envbash.svg?style=plastic)](https://rubygems.org/gems/envbash) +[![travis](https://img.shields.io/travis/scampersand/envbash-ruby/master.svg?style=plastic)](https://travis-ci.org/scampersand/envbash-ruby?branch=master) +[![codecov](https://img.shields.io/codecov/c/github/scampersand/envbash-ruby/master.svg?style=plastic)](https://codecov.io/gh/scampersand/envbash-ruby/branch/master) + +Ruby gem for sourcing a bash script to augment the environment. + +## Rationale + +[12-factor apps](https://12factor.net/) require +[configuration loaded from the environment](https://12factor.net/config). + +That's [easy on a platform like Heroku](https://devcenter.heroku.com/articles/config-vars), +where the environment is preset by the user with commands like +`heroku config:set`. But it's messier in development and non-Heroku +deployments, where the environment might need to be loaded from a file. + +This package provides a mechanism for sourcing a Bash script to update +Ruby's environment (`ENV`). There are reasons for using a Bash script +instead of another configuration language: + +1. Environment variable keys and values should always be strings. Using a Bash + script to update the environment enforces that restriction, so there won't + be surprises when you deploy into something like Heroku later on. + +2. Using a script means that the values can be sourced into a Bash shell, + something that's non-trivial if you use a different config language. + +3. For better or worse, using a script means that environment variables can be + set using the full power of the shell, including reading from other files. + +Commonly the external file is called `env.bash`, hence the name of this project. + +## Installation + +Install from [RubyGems](https://rubygems.org/gems/envbash) + + gem install envbash + +or in your Gemfile: + + gem 'envbash' + +## Usage + +Call `EnvBash.load` to source a Bash script into the current Ruby process. +Any variables that are set in the script, regardless of whether they are +explicitly exported, will be added to the process environment. + +For example, given `env.bash` with the following content: + +```bash +FOO='bar baz qux' +``` + +This can be loaded into Ruby: + +```ruby +require 'envbash' + +EnvBash.load('env.bash') + +puts ENV['FOO'] #=> bar baz qux +``` + +## Legal + +Copyright 2017 [Scampersand LLC](https://scampersand.com) + +Released under the [MIT license](https://github.com/scampersand/envbash-ruby/blob/master/LICENSE) diff --git a/func_ruby/gems/ruby/3.3.0/gems/envbash-1.0.1/Rakefile b/func_ruby/gems/ruby/3.3.0/gems/envbash-1.0.1/Rakefile new file mode 100644 index 0000000..4ede505 --- /dev/null +++ b/func_ruby/gems/ruby/3.3.0/gems/envbash-1.0.1/Rakefile @@ -0,0 +1,13 @@ +require 'rake/testtask' + +Rake::TestTask.new(:test) do |test| + test.libs << 'lib' << 'test' + # make sure helper.rb is loaded first, to start simplecov + test.test_files = FileList['test/helper.rb', 'test/test*.rb'] +end + +task :default => :test + +# this adds "rake build" to make pkg/envbash-*.gem +require 'bundler/setup' +Bundler::GemHelper.install_tasks diff --git a/func_ruby/gems/ruby/3.3.0/gems/envbash-1.0.1/envbash.gemspec b/func_ruby/gems/ruby/3.3.0/gems/envbash-1.0.1/envbash.gemspec new file mode 100644 index 0000000..04af662 --- /dev/null +++ b/func_ruby/gems/ruby/3.3.0/gems/envbash-1.0.1/envbash.gemspec @@ -0,0 +1,19 @@ +Gem::Specification.new do |spec| + spec.name = "envbash" + spec.summary = "Source env.bash script to update environment" + spec.version = "1.0.1" + spec.authors = ["Aron Griffis"] + spec.email = "aron@scampersand.com" + spec.homepage = "https://github.com/scampersand/envbash-ruby" + spec.licenses = ["MIT"] + + spec.files = `git ls-files -z`.split("\x0") + spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } + spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) + spec.require_paths = ["lib"] + + spec.add_development_dependency "codecov" + spec.add_development_dependency "minitest" + spec.add_development_dependency "minitest-assert_errors" + spec.add_development_dependency "rake" +end diff --git a/func_ruby/gems/ruby/3.3.0/gems/envbash-1.0.1/lib/envbash.rb b/func_ruby/gems/ruby/3.3.0/gems/envbash-1.0.1/lib/envbash.rb new file mode 100644 index 0000000..dd07199 --- /dev/null +++ b/func_ruby/gems/ruby/3.3.0/gems/envbash-1.0.1/lib/envbash.rb @@ -0,0 +1,2 @@ +require_relative 'envbash/load' +require_relative 'envbash/read' diff --git a/func_ruby/gems/ruby/3.3.0/gems/envbash-1.0.1/lib/envbash/load.rb b/func_ruby/gems/ruby/3.3.0/gems/envbash-1.0.1/lib/envbash/load.rb new file mode 100644 index 0000000..3019dd4 --- /dev/null +++ b/func_ruby/gems/ruby/3.3.0/gems/envbash-1.0.1/lib/envbash/load.rb @@ -0,0 +1,16 @@ +require_relative 'read' + + +module EnvBash + def EnvBash.load(envbash, into: ENV, override: false, remove: false, **kwargs) + loaded = read(envbash, **kwargs) + is_env = into.equal? ENV + into = into.to_h if is_env + if loaded + into.select! {|k| loaded.include? k} if remove + loaded.reject! {|k| into.include? k} unless override + into.merge! loaded + end + ENV.replace into if is_env + end +end diff --git a/func_ruby/gems/ruby/3.3.0/gems/envbash-1.0.1/lib/envbash/read.rb b/func_ruby/gems/ruby/3.3.0/gems/envbash-1.0.1/lib/envbash/read.rb new file mode 100644 index 0000000..258d242 --- /dev/null +++ b/func_ruby/gems/ruby/3.3.0/gems/envbash-1.0.1/lib/envbash/read.rb @@ -0,0 +1,62 @@ +require 'open3' +require 'shellwords' + + +module EnvBash + + FIXUPS = %w{_ OLDPWD PWD SHLVL} + + class ScriptExitedEarly < StandardError + end + + def EnvBash.read(envbash, bash: 'bash', env: ENV, missing_ok: false, fixups: FIXUPS) + # make sure the file exists and is readable. + # alternatively we could test File.readable?(envbash) but this approach + # raises Errno::ENOENT or Errno::EACCES which is what we want. + begin + File.open(envbash).close + rescue Errno::ENOENT + return if missing_ok + raise + end + + # construct an inline script which sources env.bash then prints the + # resulting environment so it can be eval'd back into this process. + inline = <<-EOT + set -a + source #{envbash.shellescape} >/dev/null + #{Gem.ruby.shellescape} -e 'p ENV' + EOT + + # Process.spawn treats env as overriding ENV, and anything that should be + # omitted needs to have a nil value. If env == ENV then this is a noop. + env = Hash[ENV.keys.map {|k| [k, nil]}].merge(env) + + # run the inline script with bash -c, capturing stdout. if there is any + # error output from env.bash, it will pass through to stderr. + # exit status is ignored. + output, _ = Open3.capture2(env, 'bash', '-c', inline, :in=>"/dev/null") + + # the only stdout from the inline script should be + # `p ENV` so there should be no syntax errors eval'ing this. however there + # will be no output to eval if the sourced env.bash exited early, and that + # indicates script failure. + raise ScriptExitedEarly if output.empty? + + # the eval'd output should return a hash. + nenv = eval(output) + + # there are a few environment variables that vary between this process and + # running the inline script with bash -c, but are certainly not part of the + # intentional settings in env.bash. + for f in fixups + if env[f] # not .include? because env might have nil values + nenv[f] = env[f] + else + nenv.delete(f) + end + end + + nenv + end +end diff --git a/func_ruby/gems/ruby/3.3.0/gems/envbash-1.0.1/test/helper.rb b/func_ruby/gems/ruby/3.3.0/gems/envbash-1.0.1/test/helper.rb new file mode 100644 index 0000000..6a612d6 --- /dev/null +++ b/func_ruby/gems/ruby/3.3.0/gems/envbash-1.0.1/test/helper.rb @@ -0,0 +1,10 @@ +require 'simplecov' +SimpleCov.start + +if ENV['CI'] == 'true' + require 'codecov' + SimpleCov.formatter = SimpleCov::Formatter::Codecov +end + +require 'minitest/autorun' +require 'minitest/assert_errors' diff --git a/func_ruby/gems/ruby/3.3.0/gems/envbash-1.0.1/test/test_load.rb b/func_ruby/gems/ruby/3.3.0/gems/envbash-1.0.1/test/test_load.rb new file mode 100644 index 0000000..710632d --- /dev/null +++ b/func_ruby/gems/ruby/3.3.0/gems/envbash-1.0.1/test/test_load.rb @@ -0,0 +1,74 @@ +require_relative 'helper' +require 'envbash' + + +class TestLoad < Minitest::Test + def setup + @orig = ENV.to_h + ENV['A'] = 'A' + ENV['B'] = 'B' + ENV['C'] = 'C' + ENV.delete('D') + @loaded = ENV.to_h.merge('A'=>'a', 'D'=>'d') + @loaded.delete('B') + end + + def teardown + ENV.replace(@orig) + end + + def test_load_no_override_no_remove + EnvBash.stub :read, @loaded do + # the first argument doesn't matter since read is stubbed + EnvBash.load('') + end + assert_equal ENV['A'], 'A' # NOT overridden + assert_equal ENV['B'], 'B' # NOT removed + assert_equal ENV['C'], 'C' # inherited + assert_equal ENV['D'], 'd' # loaded + end + + def test_load_override_no_remove + EnvBash.stub :read, @loaded do + # the first argument doesn't matter since read is stubbed + EnvBash.load('', override: true) + end + assert_equal ENV['A'], 'a' # overridden + assert_equal ENV['B'], 'B' # NOT removed + assert_equal ENV['C'], 'C' # inherited + assert_equal ENV['D'], 'd' # loaded + end + + def test_load_no_override_remove + EnvBash.stub :read, @loaded do + # the first argument doesn't matter since read is stubbed + EnvBash.load('', remove: true) + end + assert_equal ENV['A'], 'A' # NOT overridden + assert ! ENV.include?('B') # removed + assert_equal ENV['C'], 'C' # inherited + assert_equal ENV['D'], 'd' # loaded + end + + def test_load_override_remove + EnvBash.stub :read, @loaded do + # the first argument doesn't matter since read is stubbed + EnvBash.load('', override: true, remove: true) + end + assert_equal ENV['A'], 'a' # overridden + assert ! ENV.include?('B') # removed + assert_equal ENV['C'], 'C' # inherited + assert_equal ENV['D'], 'd' # loaded + end + + def test_load_into + orig = ENV.to_h + into = {} + EnvBash.stub :read, {'A'=>'B'} do + # the first argument doesn't matter since read is stubbed + EnvBash.load('', into: into) + end + assert_equal into, {'A'=>'B'} + assert_equal ENV.to_h, orig + end +end diff --git a/func_ruby/gems/ruby/3.3.0/gems/envbash-1.0.1/test/test_read.rb b/func_ruby/gems/ruby/3.3.0/gems/envbash-1.0.1/test/test_read.rb new file mode 100644 index 0000000..7dafb7d --- /dev/null +++ b/func_ruby/gems/ruby/3.3.0/gems/envbash-1.0.1/test/test_read.rb @@ -0,0 +1,95 @@ +require_relative 'helper' +require 'fileutils' +require 'tmpdir' +require 'envbash' + + +class TestRead < Minitest::Test + def setup + @tmpdir = Dir.mktmpdir + @envbash = File.join @tmpdir, 'env.bash' + @orig = ENV.to_h + end + + def teardown + ENV.replace(@orig) + FileUtils.rm_rf(@tmpdir) + end + + def test_read_missing_not_ok + assert_error_raised(nil, Errno::ENOENT) do + EnvBash.read @envbash + end + end + + def test_read_missing_ok + assert_no_error do + EnvBash.read @envbash, missing_ok: true + end + end + + def test_read_permission_error + FileUtils.chmod 0, @tmpdir + assert_error_raised(nil, Errno::EACCES) do + EnvBash.read @envbash + end + end + + def test_read_empty + FileUtils.touch @envbash + result = EnvBash.read @envbash + assert_equal result, @orig + end + + def test_read_normal + ENV.delete('FOO') + orig = ENV.to_h # separate from @orig + File.open(@envbash, 'w') do |f| + f.write 'FOO=BAR' + end + result = EnvBash.read @envbash + assert_equal result['FOO'], 'BAR' + result.delete('FOO') + assert_equal result, orig + end + + def test_read_error + File.open(@envbash, 'w') do |f| + # stderr doesn't matter, nor does final status. + f.write "echo 'okay!' >&2\nfalse" + end + result = EnvBash.read @envbash + assert_equal result, @orig + end + + def test_read_exit + File.open(@envbash, 'w') do |f| + f.write 'exit' + end + assert_error_raised(nil, EnvBash::ScriptExitedEarly) do + EnvBash.read @envbash + end + end + + def test_read_env + File.open(@envbash, 'w') do |f| + f.write 'FOO=BAR' + end + result = EnvBash.read @envbash, env: {} + assert_equal result, {'FOO'=>'BAR'} + end + + def test_read_fixups + File.open(@envbash, 'w') do |f| + f.write 'A=B; C=D; E=F; G=H' + end + myenv = {'A'=>'Z', 'E'=>'F'} + result = EnvBash.read @envbash, env: myenv, fixups: ['A', 'C'] + # there will be extra stuff in result since fixups is overridden, so can't + # test strict equality. + assert_equal result['A'], 'Z' # fixups, myenv, env.bash + assert !result.include?('C') # fixups, not myenv, env.bash + assert_equal result['E'], 'F' # not fixups, myenv, env.bash + assert_equal result['G'], 'H' # not fixups, not myenv, env.bash + end +end diff --git a/func_ruby/gems/ruby/3.3.0/gems/interface-1.0.5/CHANGES b/func_ruby/gems/ruby/3.3.0/gems/interface-1.0.5/CHANGES new file mode 100644 index 0000000..41ff318 --- /dev/null +++ b/func_ruby/gems/ruby/3.3.0/gems/interface-1.0.5/CHANGES @@ -0,0 +1,30 @@ +== 1.0.4 - 8-Jan-2016 +* This gem is now signed. +* The gem related tasks in the Rakefile now assume Rubygems 2.x. + +== 1.0.3 - 12-Oct-2014 +* Rakefile, gemspec and README updates. + +== 1.0.2 - 7-Oct-2009 +* Fixed packaging bug in the gemspec, and made some other minor changes. +* Added the 'gem' rake task. +* Updated copyright and license in the README. + +== 1.0.1 - 29-Jul-2009 +* Now compatible with Ruby 1.9.x. +* Replaced the install.rb with a Rakefile and various tasks. +* Updated the license to Artistic 2.0. +* Added test-unit 2.x as a development dependency and refactored the test + suite to take advantage of some of its features. +* Renamed the test file to test_interface.rb. +* Renamed the example programs to all start with 'example_' to avoid any + possible confusion with actual test suites. +* Added rake tasks for running the example programs. +* Updated and refactored the gemspec. + +== 1.0.0 - 5-Jun-2005 +* Re-released on RubyForge. +* Some test suite and doc changes. + +== 0.1.0 - 9-May-2004 +* Initial release diff --git a/func_ruby/gems/ruby/3.3.0/gems/interface-1.0.5/MANIFEST b/func_ruby/gems/ruby/3.3.0/gems/interface-1.0.5/MANIFEST new file mode 100644 index 0000000..62012d8 --- /dev/null +++ b/func_ruby/gems/ruby/3.3.0/gems/interface-1.0.5/MANIFEST @@ -0,0 +1,12 @@ +* CHANGES +* MANIFEST +* README +* Rakefile +* interface.gemspec +* certs/djberg96_pub.pem +* examples/example_instance.rb +* examples/example_interface.rb +* examples/example_sub.rb +* examples/example_unrequire.rb +* lib/interface.rb +* test/test_interface.rb diff --git a/func_ruby/gems/ruby/3.3.0/gems/interface-1.0.5/README b/func_ruby/gems/ruby/3.3.0/gems/interface-1.0.5/README new file mode 100644 index 0000000..e72c683 --- /dev/null +++ b/func_ruby/gems/ruby/3.3.0/gems/interface-1.0.5/README @@ -0,0 +1,74 @@ +== Description + This module provides Java style interfaces for Ruby, including a fairly + similar syntax. I don't necessarily believe in interfaces, but I wanted to + put it out there as proof that it could be done. Frankly, Java needs mixins + more than Ruby needs interfaces, but here you go. + +== Installation + gem install interface + +== Synopsis + require 'interface' + + MyInterface = interface{ + required_methods :foo, :bar, :baz + } + + # Raises an error until 'baz' is defined + class MyClass + def foo + puts "foo" + end + + def bar + puts "bar" + end + + implements MyInterface + end + +== General Notes + Subinterfaces work as well. See the test_sub.rb file under the 'test' + directory for a sample. + +== Developer's Notes + A discussion on IRC with Mauricio Fernandez got us talking about traits. + During that discussion I remembered a blog entry by David Naseby. I + revisited his blog entry and took a closer look: + + http://ruby-naseby.blogspot.com/2008/11/traits-in-ruby.html + + Keep in mind that I also happened to be thinking about Java at the moment + because of a recent job switch that involved coding in Java. I was also + trying to figure out what the purpose of interfaces were. + + As I read the first page of David Naseby's article I realized that, + whether intended or not, he had implemented a rudimentary form of interfaces + for Ruby. When I discovered this, I talked about it some more with Mauricio + and he and I (mostly him) fleshed out the rest of the module, including some + syntax improvements. The result is syntax and functionality that is nearly + identical to Java. + + I should note that, although I am listed as the author, this was mostly the + combined work of David Naseby and Mauricio Fernandez. I just happened to be + the guy that put it all together. + +== Acknowledgements + This module was largely inspired and somewhat copied from a post by + David Naseby (see URL above). It was subsequently modified almost entirely + by Mauricio Fernandez through a series of discussions on IRC. + +== Copyright + (C) 2004-2016 Daniel J. Berger + All rights reserved. + +== Warranty + This package is provided "as is" and without any express or + implied warranties, including, without limitation, the implied + warranties of merchantability and fitness for a particular purpose. + +== License + Artistic 2.0 + +== Author + Daniel J. Berger diff --git a/func_ruby/gems/ruby/3.3.0/gems/interface-1.0.5/Rakefile b/func_ruby/gems/ruby/3.3.0/gems/interface-1.0.5/Rakefile new file mode 100644 index 0000000..435ef93 --- /dev/null +++ b/func_ruby/gems/ruby/3.3.0/gems/interface-1.0.5/Rakefile @@ -0,0 +1,50 @@ +require 'rake' +require 'rake/clean' +require 'rake/testtask' + +CLEAN.include("**/*.gem", "**/*.rbc") + +namespace :gem do + desc "Create the interface gem" + task :create => [:clean] do + require 'rubygems/package' + spec = eval(IO.read('interface.gemspec')) + spec.signing_key = File.join(Dir.home, '.ssh', 'gem-private_key.pem') + Gem::Package.build(spec, true) + end + + desc "Install the interface gem" + task :install => [:create] do + file = Dir["*.gem"].first + sh "gem install -l #{file}" + end +end + +namespace :example do + desc 'Run the example_instance.rb sample program' + task :instance do + ruby '-Ilib examples/example_instance.rb' + end + + desc 'Run the example_interface.rb sample program' + task :interface do + ruby '-Ilib examples/example_interface.rb' + end + + desc 'Run the example_sub.rb sample program' + task :sub do + ruby '-Ilib examples/example_sub.rb' + end + + desc 'Run the example_unrequire.rb sample program' + task :unrequire do + ruby '-Ilib examples/example_unrequire.rb' + end +end + +Rake::TestTask.new do |t| + t.verbose = true + t.warning = true +end + +task :default => :test diff --git a/func_ruby/gems/ruby/3.3.0/gems/interface-1.0.5/certs/djberg96_pub.pem b/func_ruby/gems/ruby/3.3.0/gems/interface-1.0.5/certs/djberg96_pub.pem new file mode 100644 index 0000000..a098922 --- /dev/null +++ b/func_ruby/gems/ruby/3.3.0/gems/interface-1.0.5/certs/djberg96_pub.pem @@ -0,0 +1,26 @@ +-----BEGIN CERTIFICATE----- +MIIEcDCCAtigAwIBAgIBATANBgkqhkiG9w0BAQsFADA/MREwDwYDVQQDDAhkamJl +cmc5NjEVMBMGCgmSJomT8ixkARkWBWdtYWlsMRMwEQYKCZImiZPyLGQBGRYDY29t +MB4XDTE4MDMxODE1MjIwN1oXDTI4MDMxNTE1MjIwN1owPzERMA8GA1UEAwwIZGpi +ZXJnOTYxFTATBgoJkiaJk/IsZAEZFgVnbWFpbDETMBEGCgmSJomT8ixkARkWA2Nv +bTCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBALgfaroVM6CI06cxr0/h +A+j+pc8fgpRgBVmHFaFunq28GPC3IvW7Nvc3Y8SnAW7pP1EQIbhlwRIaQzJ93/yj +u95KpkP7tA9erypnV7dpzBkzNlX14ACaFD/6pHoXoe2ltBxk3CCyyzx70mTqJpph +75IB03ni9a8yqn8pmse+s83bFJOAqddSj009sGPcQO+QOWiNxqYv1n5EHcvj2ebO +6hN7YTmhx7aSia4qL/quc4DlIaGMWoAhvML7u1fmo53CYxkKskfN8MOecq2vfEmL +iLu+SsVVEAufMDDFMXMJlvDsviolUSGMSNRTujkyCcJoXKYYxZSNtIiyd9etI0X3 +ctu0uhrFyrMZXCedutvXNjUolD5r9KGBFSWH1R9u2I3n3SAyFF2yzv/7idQHLJJq +74BMnx0FIq6fCpu5slAipvxZ3ZkZpEXZFr3cIBtO1gFvQWW7E/Y3ijliWJS1GQFq +058qERadHGu1yu1dojmFRo6W2KZvY9al2yIlbkpDrD5MYQIDAQABo3cwdTAJBgNV +HRMEAjAAMAsGA1UdDwQEAwIEsDAdBgNVHQ4EFgQUFZsMapgzJimzsbaBG2Tm8j5e +AzgwHQYDVR0RBBYwFIESZGpiZXJnOTZAZ21haWwuY29tMB0GA1UdEgQWMBSBEmRq +YmVyZzk2QGdtYWlsLmNvbTANBgkqhkiG9w0BAQsFAAOCAYEAW2tnYixXQtKxgGXq +/3iSWG2bLwvxS4go3srO+aRXZHrFUMlJ5W0mCxl03aazxxKTsVVpZD8QZxvK91OQ +h9zr9JBYqCLcCVbr8SkmYCi/laxIZxsNE5YI8cC8vvlLI7AMgSfPSnn/Epq1GjGY +6L1iRcEDtanGCIvjqlCXO9+BmsnCfEVehqZkQHeYczA03tpOWb6pon2wzvMKSsKH +ks0ApVdstSLz1kzzAqem/uHdG9FyXdbTAwH1G4ZPv69sQAFAOCgAqYmdnzedsQtE +1LQfaQrx0twO+CZJPcRLEESjq8ScQxWRRkfuh2VeR7cEU7L7KqT10mtUwrvw7APf +DYoeCY9KyjIBjQXfbj2ke5u1hZj94Fsq9FfbEQg8ygCgwThnmkTrrKEiMSs3alYR +ORVCZpRuCPpmC8qmqxUnARDArzucjaclkxjLWvCVHeFa9UP7K3Nl9oTjJNv+7/jM +WZs4eecIcUc4tKdHxcAJ0MO/Dkqq7hGaiHpwKY76wQ1+8xAh +-----END CERTIFICATE----- diff --git a/func_ruby/gems/ruby/3.3.0/gems/interface-1.0.5/examples/example_instance.rb b/func_ruby/gems/ruby/3.3.0/gems/interface-1.0.5/examples/example_instance.rb new file mode 100644 index 0000000..8fb2c09 --- /dev/null +++ b/func_ruby/gems/ruby/3.3.0/gems/interface-1.0.5/examples/example_instance.rb @@ -0,0 +1,30 @@ +####################################################################### +# example_instance.rb +# +# Sample program to demonstrate extending an interface to an instance +# of a class. You can run this program via the 'rake example:instance' +# task. Modify as you see fit. +####################################################################### +require 'interface' + +MyInterface = interface{ + required_methods :foo, :bar +} + +class Foo + def foo; end + def bar; end +end + +class Bar +end + +f = Foo.new +f.extend(MyInterface) + +b = Bar.new + +# This will blow up +class << b + include MyInterface +end diff --git a/func_ruby/gems/ruby/3.3.0/gems/interface-1.0.5/examples/example_interface.rb b/func_ruby/gems/ruby/3.3.0/gems/interface-1.0.5/examples/example_interface.rb new file mode 100644 index 0000000..94e5f98 --- /dev/null +++ b/func_ruby/gems/ruby/3.3.0/gems/interface-1.0.5/examples/example_interface.rb @@ -0,0 +1,28 @@ +####################################################################### +# example_interface.rb +# +# Sample test script that demonstrates a typical interface. You can +# run this example via the 'rake example:interface' task. Modify this +# code as you see fit. +####################################################################### +require 'interface' + +MyInterface = interface{ + required_methods :foo, :bar +} + +class MyClass + def foo; end + def bar; end + include MyInterface +end + +=begin +# Raises an error until bar is defined +class Foo + def foo + puts "foo" + end + include MyInterface +end +=end diff --git a/func_ruby/gems/ruby/3.3.0/gems/interface-1.0.5/examples/example_sub.rb b/func_ruby/gems/ruby/3.3.0/gems/interface-1.0.5/examples/example_sub.rb new file mode 100644 index 0000000..9437c84 --- /dev/null +++ b/func_ruby/gems/ruby/3.3.0/gems/interface-1.0.5/examples/example_sub.rb @@ -0,0 +1,34 @@ +####################################################################### +# example_sub.rb +# +# Sample program to demonstrate extending a sub-interface. You can +# run this program via the 'rake example:sub' task. Modify this code +# as you see fit. +####################################################################### +require 'interface' + +module MyInterface + extend Interface + required_methods :foo, :bar +end + +module MySubInterface + extend Interface + extend MyInterface + required_methods :baz +end + +class MyClass + def baz; end + def bar; end + def foo; end + include MySubInterface +end + +=begin +# Raises an error +class MyClass + def baz; end + include MyInterface +end +=end diff --git a/func_ruby/gems/ruby/3.3.0/gems/interface-1.0.5/examples/example_unrequire.rb b/func_ruby/gems/ruby/3.3.0/gems/interface-1.0.5/examples/example_unrequire.rb new file mode 100644 index 0000000..e8200f1 --- /dev/null +++ b/func_ruby/gems/ruby/3.3.0/gems/interface-1.0.5/examples/example_unrequire.rb @@ -0,0 +1,26 @@ +########################################################################### +# example_unrequire.rb +# +# Sample test script for to verify that unrequired_methods works properly. +# You can run this code via the 'rake example:unrequire' rake task. Modify +# this code as you see fit. +########################################################################### +require 'interface' + +MyInterface = interface{ + required_methods :foo, :bar +} + +# require foo and baz, but not bar +MySubInterface = interface{ + extends MyInterface + required_methods :baz + unrequired_methods :bar +} + +# No error +class MyClass + def foo; end + def baz; end + include MySubInterface +end diff --git a/func_ruby/gems/ruby/3.3.0/gems/interface-1.0.5/interface.gemspec b/func_ruby/gems/ruby/3.3.0/gems/interface-1.0.5/interface.gemspec new file mode 100644 index 0000000..1d6cb6b --- /dev/null +++ b/func_ruby/gems/ruby/3.3.0/gems/interface-1.0.5/interface.gemspec @@ -0,0 +1,34 @@ +require 'rubygems' + +Gem::Specification.new do |spec| + spec.name = 'interface' + spec.version = '1.0.5' + spec.author = 'Daniel J. Berger' + spec.license = 'Artistic-2.0' + spec.email = 'djberg96@gmail.com' + spec.homepage = 'http://github.com/djberg96/interface' + spec.summary = 'Java style interfaces for Ruby' + spec.test_file = 'test/test_interface.rb' + spec.files = Dir['**/*'].reject{ |f| f.include?('git') } + spec.cert_chain = Dir['certs/*'] + + spec.extra_rdoc_files = ['README', 'CHANGES', 'MANIFEST'] + + spec.add_development_dependency('test-unit') + spec.add_development_dependency('rake') + + spec.metadata = { + 'homepage_uri' => 'https://github.com/djberg96/interface', + 'bug_tracker_uri' => 'https://github.com/djberg96/interface/issues', + 'changelog_uri' => 'https://github.com/djberg96/interface/blob/master/CHANGES', + 'documentation_uri' => 'https://github.com/djberg96/interface/wiki', + 'source_code_uri' => 'https://github.com/djberg96/interface', + 'wiki_uri' => 'https://github.com/djberg96/interface/wiki' + } + + spec.description = <<-EOF + The interface library implements Java style interfaces for Ruby. + It lets you define a set a methods that must be defined in the + including class or module, or an error is raised. + EOF +end diff --git a/func_ruby/gems/ruby/3.3.0/gems/interface-1.0.5/lib/interface.rb b/func_ruby/gems/ruby/3.3.0/gems/interface-1.0.5/lib/interface.rb new file mode 100644 index 0000000..a459cfa --- /dev/null +++ b/func_ruby/gems/ruby/3.3.0/gems/interface-1.0.5/lib/interface.rb @@ -0,0 +1,106 @@ +# A module for implementing Java style interfaces in Ruby. For more information +# about Java interfaces, please see: +# +# http://java.sun.com/docs/books/tutorial/java/concepts/interface.html +# +module Interface + # The version of the interface library. + Interface::VERSION = '1.0.5'.freeze + + # Raised if a class or instance does not meet the interface requirements. + class MethodMissing < RuntimeError; end + + alias :extends :extend + + private + + def extend_object(obj) + return append_features(obj) if Interface === obj + append_features(class << obj; self end) + included(obj) + end + + def append_features(mod) + return super if Interface === mod + + # Is this a sub-interface? + inherited = (self.ancestors-[self]).select{ |x| Interface === x } + inherited = inherited.map{ |x| x.instance_variable_get('@ids') } + + # Store required method ids + ids = @ids + inherited.flatten + @unreq ||= [] + + # Iterate over the methods, minus the unrequired methods, and raise + # an error if the method has not been defined. + (ids - @unreq).uniq.each do |id| + unless mod.instance_methods(true).include?(id) + raise Interface::MethodMissing, id + end + end + + super mod + end + + public + + # Accepts an array of method names that define the interface. When this + # module is included/implemented, those method names must have already been + # defined. + # + def required_methods(*ids) + @ids = ids + end + + # Accepts an array of method names that are removed as a requirement for + # implementation. Presumably you would use this in a sub-interface where + # you only wanted a partial implementation of an existing interface. + # + def unrequired_methods(*ids) + @unreq ||= [] + @unreq += ids + end +end + +class Object + # The interface method creates an interface module which typically sets + # a list of methods that must be defined in the including class or module. + # If the methods are not defined, an Interface::MethodMissing error is raised. + # + # A interface can extend an existing interface as well. These are called + # sub-interfaces, and they can included the rules for their parent interface + # by simply extending it. + # + # Example: + # + # # Require 'alpha' and 'beta' methods + # AlphaInterface = interface{ + # required_methods :alpha, :beta + # } + # + # # A sub-interface that requires 'beta' and 'gamma' only + # GammaInterface = interface{ + # extends AlphaInterface + # required_methods :gamma + # unrequired_methods :alpha + # } + # + # # Raises an Interface::MethodMissing error because :beta is not defined. + # class MyClass + # def alpha + # # ... + # end + # implements AlphaInterface + # end + # + def interface(&block) + Module.new do |mod| + mod.extend(Interface) + mod.instance_eval(&block) + end + end +end + +class Module + alias :implements :include +end diff --git a/func_ruby/gems/ruby/3.3.0/gems/interface-1.0.5/test/test_interface.rb b/func_ruby/gems/ruby/3.3.0/gems/interface-1.0.5/test/test_interface.rb new file mode 100644 index 0000000..4ff3974 --- /dev/null +++ b/func_ruby/gems/ruby/3.3.0/gems/interface-1.0.5/test/test_interface.rb @@ -0,0 +1,64 @@ +##################################################### +# test_interface.rb +# +# Test suite for the Interface module. +##################################################### +require 'test-unit' +require 'interface' + +class TC_Interface < Test::Unit::TestCase + def self.startup + alpha_interface = interface{ + required_methods :alpha, :beta + } + + gamma_interface = interface{ + extends alpha_interface + required_methods :gamma + unrequired_methods :alpha + } + + # Workaround for 1.9.x + @@alpha_interface = alpha_interface + @@gamma_interface = gamma_interface + + eval("class A; end") + + eval(" + class B + def alpha; end + def beta; end + end + ") + + eval(" + class C + def beta; end + def gamma; end + end + ") + end + + def test_version + assert_equal('1.0.5', Interface::VERSION) + assert_true(Interface::VERSION.frozen?) + end + + def test_interface_requirements_not_met + assert_raise(Interface::MethodMissing){ A.extend(@@alpha_interface) } + assert_raise(Interface::MethodMissing){ A.new.extend(@@alpha_interface) } + end + + def test_sub_interface_requirements_not_met + assert_raise(Interface::MethodMissing){ B.extend(@@gamma_interface) } + assert_raise(Interface::MethodMissing){ B.new.extend(@@gamma_interface) } + end + + def test_alpha_interface_requirements_met + assert_nothing_raised{ B.new.extend(@@alpha_interface) } + end + + def test_gamma_interface_requirements_met + assert_nothing_raised{ C.new.extend(@@gamma_interface) } + end +end diff --git a/func_ruby/gems/ruby/3.3.0/gems/shell-0.8.1/Gemfile b/func_ruby/gems/ruby/3.3.0/gems/shell-0.8.1/Gemfile new file mode 100644 index 0000000..e89f8fd --- /dev/null +++ b/func_ruby/gems/ruby/3.3.0/gems/shell-0.8.1/Gemfile @@ -0,0 +1,11 @@ +source "https://rubygems.org" + +git_source(:github) {|repo_name| "https://github.com/#{repo_name}" } + +gemspec + +group :development do + gem "bundler" + gem "rake" + gem "test-unit" +end diff --git a/func_ruby/gems/ruby/3.3.0/gems/shell-0.8.1/LICENSE.txt b/func_ruby/gems/ruby/3.3.0/gems/shell-0.8.1/LICENSE.txt new file mode 100644 index 0000000..a009cae --- /dev/null +++ b/func_ruby/gems/ruby/3.3.0/gems/shell-0.8.1/LICENSE.txt @@ -0,0 +1,22 @@ +Copyright (C) 1993-2013 Yukihiro Matsumoto. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. diff --git a/func_ruby/gems/ruby/3.3.0/gems/shell-0.8.1/README.md b/func_ruby/gems/ruby/3.3.0/gems/shell-0.8.1/README.md new file mode 100644 index 0000000..d386543 --- /dev/null +++ b/func_ruby/gems/ruby/3.3.0/gems/shell-0.8.1/README.md @@ -0,0 +1,97 @@ +# Shell + +Shell implements an idiomatic Ruby interface for common UNIX shell commands. + +It provides users the ability to execute commands with filters and pipes, like +sh+/+csh+ by using native facilities of Ruby. + +## Installation + +Add this line to your application's Gemfile: + +```ruby +gem 'shell' +``` + +And then execute: + + $ bundle + +Or install it yourself as: + + $ gem install shell + +## Usage + +### Temp file creation + +In this example we will create three +tmpFile+'s in three different folders under the +/tmp+ directory. + +``` + sh = Shell.cd("/tmp") # Change to the /tmp directory + sh.mkdir "shell-test-1" unless sh.exists?("shell-test-1") + # make the 'shell-test-1' directory if it doesn't already exist + sh.cd("shell-test-1") # Change to the /tmp/shell-test-1 directory + for dir in ["dir1", "dir3", "dir5"] + if !sh.exists?(dir) + sh.mkdir dir # make dir if it doesn't already exist + sh.cd(dir) do + # change to the `dir` directory + f = sh.open("tmpFile", "w") # open a new file in write mode + f.print "TEST\n" # write to the file + f.close # close the file handler + end + print sh.pwd # output the process working directory + end + end +``` + +### Temp file creation with self + +This example is identical to the first, except we're using CommandProcessor#transact. + +CommandProcessor#transact executes the given block against self, in this case +sh+; our Shell object. Within the block we can substitute +sh.cd+ to +cd+, because the scope within the block uses +sh+ already. + +``` + sh = Shell.cd("/tmp") + sh.transact do + mkdir "shell-test-1" unless exists?("shell-test-1") + cd("shell-test-1") + for dir in ["dir1", "dir3", "dir5"] + if !exists?(dir) + mkdir dir + cd(dir) do + f = open("tmpFile", "w") + f.print "TEST\n" + f.close + end + print pwd + end + end + end +``` + +### Pipe /etc/printcap into a file + +In this example we will read the operating system file +/etc/printcap+, generated by +cupsd+, and then output it to a new file relative to the +pwd+ of +sh+. + +``` + sh = Shell.new + sh.cat("/etc/printcap") | sh.tee("tee1") > "tee2" + (sh.cat < "/etc/printcap") | sh.tee("tee11") > "tee12" + sh.cat("/etc/printcap") | sh.tee("tee1") >> "tee2" + (sh.cat < "/etc/printcap") | sh.tee("tee11") >> "tee12" +``` + +## Development + +After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment. + +To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org). + +## Contributing + +Bug reports and pull requests are welcome on GitHub at https://github.com/ruby/shell. + +## License + +The gem is available as open source under the terms of the [2-Clause BSD License](https://opensource.org/licenses/BSD-2-Clause). diff --git a/func_ruby/gems/ruby/3.3.0/gems/shell-0.8.1/Rakefile b/func_ruby/gems/ruby/3.3.0/gems/shell-0.8.1/Rakefile new file mode 100644 index 0000000..d81dd1f --- /dev/null +++ b/func_ruby/gems/ruby/3.3.0/gems/shell-0.8.1/Rakefile @@ -0,0 +1,17 @@ +require "bundler/gem_tasks" +require "rake/testtask" + +Rake::TestTask.new(:test) do |t| + t.libs << "test/lib" + t.ruby_opts << "-rhelper" + t.test_files = FileList["test/**/test_*.rb"] +end + +task :sync_tool do + require 'fileutils' + FileUtils.cp "../ruby/tool/lib/test/unit/core_assertions.rb", "./test/lib" + FileUtils.cp "../ruby/tool/lib/envutil.rb", "./test/lib" + FileUtils.cp "../ruby/tool/lib/find_executable.rb", "./test/lib" +end + +task :default => :test diff --git a/func_ruby/gems/ruby/3.3.0/gems/shell-0.8.1/bin/console b/func_ruby/gems/ruby/3.3.0/gems/shell-0.8.1/bin/console new file mode 100755 index 0000000..3cf6be8 --- /dev/null +++ b/func_ruby/gems/ruby/3.3.0/gems/shell-0.8.1/bin/console @@ -0,0 +1,7 @@ +#!/usr/bin/env ruby + +require "bundler/setup" +require_relative "../lib/shell" + +require "irb" +IRB.start(__FILE__) diff --git a/func_ruby/gems/ruby/3.3.0/gems/shell-0.8.1/bin/setup b/func_ruby/gems/ruby/3.3.0/gems/shell-0.8.1/bin/setup new file mode 100755 index 0000000..cf4ad25 --- /dev/null +++ b/func_ruby/gems/ruby/3.3.0/gems/shell-0.8.1/bin/setup @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +set -euo pipefail +IFS=$'\n\t' +set -vx + +bundle install diff --git a/func_ruby/gems/ruby/3.3.0/gems/shell-0.8.1/lib/shell.rb b/func_ruby/gems/ruby/3.3.0/gems/shell-0.8.1/lib/shell.rb new file mode 100644 index 0000000..0958896 --- /dev/null +++ b/func_ruby/gems/ruby/3.3.0/gems/shell-0.8.1/lib/shell.rb @@ -0,0 +1,462 @@ +# frozen_string_literal: false +# +# shell.rb - +# $Release Version: 0.7 $ +# $Revision: 1.9 $ +# by Keiju ISHITSUKA(keiju@ruby-lang.org) +# +# -- +# +# +# + +require "e2mmap" + +require "forwardable" + +require "shell/error" +require "shell/command-processor" +require "shell/process-controller" +require "shell/version" + +# Shell implements an idiomatic Ruby interface for common UNIX shell commands. +# +# It provides users the ability to execute commands with filters and pipes, +# like +sh+/+csh+ by using native facilities of Ruby. +# +# == Examples +# +# === Temp file creation +# +# In this example we will create three +tmpFile+'s in three different folders +# under the +/tmp+ directory. +# +# sh = Shell.cd("/tmp") # Change to the /tmp directory +# sh.mkdir "shell-test-1" unless sh.exists?("shell-test-1") +# # make the 'shell-test-1' directory if it doesn't already exist +# sh.cd("shell-test-1") # Change to the /tmp/shell-test-1 directory +# for dir in ["dir1", "dir3", "dir5"] +# if !sh.exists?(dir) +# sh.mkdir dir # make dir if it doesn't already exist +# sh.cd(dir) do +# # change to the `dir` directory +# f = sh.open("tmpFile", "w") # open a new file in write mode +# f.print "TEST\n" # write to the file +# f.close # close the file handler +# end +# print sh.pwd # output the process working directory +# end +# end +# +# === Temp file creation with self +# +# This example is identical to the first, except we're using +# CommandProcessor#transact. +# +# CommandProcessor#transact executes the given block against self, in this case +# +sh+; our Shell object. Within the block we can substitute +sh.cd+ to +cd+, +# because the scope within the block uses +sh+ already. +# +# sh = Shell.cd("/tmp") +# sh.transact do +# mkdir "shell-test-1" unless exists?("shell-test-1") +# cd("shell-test-1") +# for dir in ["dir1", "dir3", "dir5"] +# if !exists?(dir) +# mkdir dir +# cd(dir) do +# f = open("tmpFile", "w") +# f.print "TEST\n" +# f.close +# end +# print pwd +# end +# end +# end +# +# === Pipe /etc/printcap into a file +# +# In this example we will read the operating system file +/etc/printcap+, +# generated by +cupsd+, and then output it to a new file relative to the +pwd+ +# of +sh+. +# +# sh = Shell.new +# sh.cat("/etc/printcap") | sh.tee("tee1") > "tee2" +# (sh.cat < "/etc/printcap") | sh.tee("tee11") > "tee12" +# sh.cat("/etc/printcap") | sh.tee("tee1") >> "tee2" +# (sh.cat < "/etc/printcap") | sh.tee("tee11") >> "tee12" +# +class Shell + + include Error + extend Exception2MessageMapper + + # debug: true -> normal debug + # debug: 1 -> eval definition debug + # debug: 2 -> detail inspect debug + @debug = false + @verbose = true + + @debug_display_process_id = false + @debug_display_thread_id = true + @debug_output_mutex = Thread::Mutex.new + @default_system_path = nil + @default_record_separator = nil + + class << Shell + extend Forwardable + + attr_accessor :cascade, :verbose + attr_reader :debug + + alias debug? debug + alias verbose? verbose + @verbose = true + + def debug=(val) + @debug = val + @verbose = val if val + end + + + # call-seq: + # Shell.cd(path) + # + # Creates a new Shell instance with the current working directory + # set to +path+. + def cd(path) + new(path) + end + + # Returns the directories in the current shell's PATH environment variable + # as an array of directory names. This sets the system_path for all + # instances of Shell. + # + # Example: If in your current shell, you did: + # + # $ echo $PATH + # /usr/bin:/bin:/usr/local/bin + # + # Running this method in the above shell would then return: + # + # ["/usr/bin", "/bin", "/usr/local/bin"] + # + def default_system_path + if @default_system_path + @default_system_path + else + ENV["PATH"].split(":") + end + end + + # Sets the system_path that new instances of Shell should have as their + # initial system_path. + # + # +path+ should be an array of directory name strings. + def default_system_path=(path) + @default_system_path = path + end + + def default_record_separator + if @default_record_separator + @default_record_separator + else + $/ + end + end + + def default_record_separator=(rs) + @default_record_separator = rs + end + + # os resource mutex + mutex_methods = ["unlock", "lock", "locked?", "synchronize", "try_lock"] + for m in mutex_methods + def_delegator("@debug_output_mutex", m, "debug_output_"+m.to_s) + end + + end + + # call-seq: + # Shell.new(pwd, umask) -> obj + # + # Creates a Shell object which current directory is set to the process + # current directory, unless otherwise specified by the +pwd+ argument. + def initialize(pwd = Dir.pwd, umask = nil) + @cwd = File.expand_path(pwd) + @dir_stack = [] + @umask = umask + + @system_path = Shell.default_system_path + @record_separator = Shell.default_record_separator + + @command_processor = CommandProcessor.new(self) + @process_controller = ProcessController.new(self) + + @verbose = Shell.verbose + @debug = Shell.debug + end + + # Returns the command search path in an array + attr_reader :system_path + + # Sets the system path (the Shell instance's PATH environment variable). + # + # +path+ should be an array of directory name strings. + def system_path=(path) + @system_path = path + rehash + end + + + # Returns the umask + attr_accessor :umask + attr_accessor :record_separator + attr_accessor :verbose + attr_reader :debug + + def debug=(val) + @debug = val + @verbose = val if val + end + + alias verbose? verbose + alias debug? debug + + attr_reader :command_processor + attr_reader :process_controller + + def expand_path(path) + File.expand_path(path, @cwd) + end + + # Most Shell commands are defined via CommandProcessor + + # + # Dir related methods + # + # Shell#cwd/dir/getwd/pwd + # Shell#chdir/cd + # Shell#pushdir/pushd + # Shell#popdir/popd + # Shell#mkdir + # Shell#rmdir + + # Returns the current working directory. + attr_reader :cwd + alias dir cwd + alias getwd cwd + alias pwd cwd + + attr_reader :dir_stack + alias dirs dir_stack + + # call-seq: + # Shell.chdir(path) + # + # Creates a Shell object which current directory is set to +path+. + # + # If a block is given, it restores the current directory when the block ends. + # + # If called as iterator, it restores the current directory when the + # block ends. + def chdir(path = nil, verbose = @verbose) + check_point + + if block_given? + notify("chdir(with block) #{path}") if verbose + cwd_old = @cwd + begin + chdir(path, nil) + yield + ensure + chdir(cwd_old, nil) + end + else + notify("chdir #{path}") if verbose + path = "~" unless path + @cwd = expand_path(path) + notify "current dir: #{@cwd}" + rehash + Void.new(self) + end + end + alias cd chdir + + # call-seq: + # pushdir(path) + # pushdir(path) { &block } + # + # Pushes the current directory to the directory stack, changing the current + # directory to +path+. + # + # If +path+ is omitted, it exchanges its current directory and the top of its + # directory stack. + # + # If a block is given, it restores the current directory when the block ends. + def pushdir(path = nil, verbose = @verbose) + check_point + + if block_given? + notify("pushdir(with block) #{path}") if verbose + pushdir(path, nil) + begin + yield + ensure + popdir + end + elsif path + notify("pushdir #{path}") if verbose + @dir_stack.push @cwd + chdir(path, nil) + notify "dir stack: [#{@dir_stack.join ', '}]" + self + else + notify("pushdir") if verbose + if pop = @dir_stack.pop + @dir_stack.push @cwd + chdir pop + notify "dir stack: [#{@dir_stack.join ', '}]" + self + else + Shell.Fail DirStackEmpty + end + end + Void.new(self) + end + alias pushd pushdir + + # Pops a directory from the directory stack, and sets the current directory + # to it. + def popdir + check_point + + notify("popdir") + if pop = @dir_stack.pop + chdir pop + notify "dir stack: [#{@dir_stack.join ', '}]" + self + else + Shell.Fail DirStackEmpty + end + Void.new(self) + end + alias popd popdir + + # Returns a list of scheduled jobs. + def jobs + @process_controller.jobs + end + + # call-seq: + # kill(signal, job) + # + # Sends the given +signal+ to the given +job+ + def kill(sig, command) + @process_controller.kill_job(sig, command) + end + + # call-seq: + # def_system_command(command, path = command) + # + # Convenience method for Shell::CommandProcessor.def_system_command. + # Defines an instance method which will execute the given shell command. + # If the executable is not in Shell.default_system_path, you must + # supply the path to it. + # + # Shell.def_system_command('hostname') + # Shell.new.hostname # => localhost + # + # # How to use an executable that's not in the default path + # + # Shell.def_system_command('run_my_program', "~/hello") + # Shell.new.run_my_program # prints "Hello from a C program!" + # + def Shell.def_system_command(command, path = command) + CommandProcessor.def_system_command(command, path) + end + + # Convenience method for Shell::CommandProcessor.undef_system_command + def Shell.undef_system_command(command) + CommandProcessor.undef_system_command(command) + end + + # call-seq: + # alias_command(alias, command, *opts, &block) + # + # Convenience method for Shell::CommandProcessor.alias_command. + # Defines an instance method which will execute a command under + # an alternative name. + # + # Shell.def_system_command('date') + # Shell.alias_command('date_in_utc', 'date', '-u') + # Shell.new.date_in_utc # => Sat Jan 25 16:59:57 UTC 2014 + # + def Shell.alias_command(ali, command, *opts, &block) + CommandProcessor.alias_command(ali, command, *opts, &block) + end + + # Convenience method for Shell::CommandProcessor.unalias_command + def Shell.unalias_command(ali) + CommandProcessor.unalias_command(ali) + end + + # call-seq: + # install_system_commands(pre = "sys_") + # + # Convenience method for Shell::CommandProcessor.install_system_commands. + # Defines instance methods representing all the executable files found in + # Shell.default_system_path, with the given prefix prepended to their + # names. + # + # Shell.install_system_commands + # Shell.new.sys_echo("hello") # => hello + # + def Shell.install_system_commands(pre = "sys_") + CommandProcessor.install_system_commands(pre) + end + + # + def inspect + if debug.kind_of?(Integer) && debug > 2 + super + else + to_s + end + end + + def self.notify(*opts) + Shell::debug_output_synchronize do + if opts[-1].kind_of?(String) + yorn = verbose? + else + yorn = opts.pop + end + return unless yorn + + if @debug_display_thread_id + if @debug_display_process_id + prefix = "shell(##{Process.pid}:#{Thread.current.to_s.sub("Thread", "Th")}): " + else + prefix = "shell(#{Thread.current.to_s.sub("Thread", "Th")}): " + end + else + prefix = "shell: " + end + _head = true + STDERR.print opts.collect{|mes| + mes = mes.dup + yield mes if block_given? + if _head + _head = false + prefix + mes + else + " "* prefix.size + mes + end + }.join("\n")+"\n" + end + end + + CommandProcessor.initialize + CommandProcessor.run_config +end diff --git a/func_ruby/gems/ruby/3.3.0/gems/shell-0.8.1/lib/shell/builtin-command.rb b/func_ruby/gems/ruby/3.3.0/gems/shell-0.8.1/lib/shell/builtin-command.rb new file mode 100644 index 0000000..a6a9d23 --- /dev/null +++ b/func_ruby/gems/ruby/3.3.0/gems/shell-0.8.1/lib/shell/builtin-command.rb @@ -0,0 +1,147 @@ +# frozen_string_literal: false +# +# shell/builtin-command.rb - +# $Release Version: 0.7 $ +# $Revision$ +# by Keiju ISHITSUKA(keiju@ruby-lang.org) +# +# -- +# +# +# + +require_relative "filter" + +class Shell + class BuiltInCommand < Filter + def wait? + false + end + def active? + true + end + end + + class Void < BuiltInCommand + def initialize(sh, *opts) + super sh + end + + def each(rs = nil) + # do nothing + end + end + + class Echo < BuiltInCommand + def initialize(sh, *strings) + super sh + @strings = strings + end + + def each(rs = nil) + rs = @shell.record_separator unless rs + for str in @strings + yield str + rs + end + end + end + + class Cat < BuiltInCommand + def initialize(sh, *filenames) + super sh + @cat_files = filenames + end + + def each(rs = nil) + if @cat_files.empty? + super + else + for src in @cat_files + @shell.foreach(src, rs){|l| yield l} + end + end + end + end + + class Glob < BuiltInCommand + def initialize(sh, pattern) + super sh + + @pattern = pattern + end + + def each(rs = nil) + if @pattern[0] == ?/ + @files = Dir[@pattern] + else + prefix = @shell.pwd+"/" + @files = Dir[prefix+@pattern].collect{|p| p.sub(prefix, "")} + end + rs = @shell.record_separator unless rs + for f in @files + yield f+rs + end + end + end + + class AppendIO < BuiltInCommand + def initialize(sh, io, filter) + super sh + @input = filter + @io = io + end + + def input=(filter) + @input.input=filter + for l in @input + @io << l + end + end + + end + + class AppendFile < AppendIO + def initialize(sh, to_filename, filter) + @file_name = to_filename + io = sh.open(to_filename, "a") + super(sh, io, filter) + end + + def input=(filter) + begin + super + ensure + @io.close + end + end + end + + class Tee < BuiltInCommand + def initialize(sh, filename) + super sh + @to_filename = filename + end + + def each(rs = nil) + to = @shell.open(@to_filename, "w") + begin + super{|l| to << l; yield l} + ensure + to.close + end + end + end + + class Concat < BuiltInCommand + def initialize(sh, *jobs) + super(sh) + @jobs = jobs + end + + def each(rs = nil) + while job = @jobs.shift + job.each{|l| yield l} + end + end + end +end diff --git a/func_ruby/gems/ruby/3.3.0/gems/shell-0.8.1/lib/shell/command-processor.rb b/func_ruby/gems/ruby/3.3.0/gems/shell-0.8.1/lib/shell/command-processor.rb new file mode 100644 index 0000000..592cb26 --- /dev/null +++ b/func_ruby/gems/ruby/3.3.0/gems/shell-0.8.1/lib/shell/command-processor.rb @@ -0,0 +1,671 @@ +# frozen_string_literal: false +# +# shell/command-controller.rb - +# $Release Version: 0.7 $ +# $Revision$ +# by Keiju ISHITSUKA(keiju@ruby-lang.org) +# +# -- +# +# +# + +require "e2mmap" + +require_relative "error" +require_relative "filter" +require_relative "system-command" +require_relative "builtin-command" + +class Shell + # In order to execute a command on your OS, you need to define it as a + # Shell method. + # + # Alternatively, you can execute any command via + # Shell::CommandProcessor#system even if it is not defined. + class CommandProcessor + + # + # initialize of Shell and related classes. + # + m = [:initialize, :expand_path] + if Object.methods.first.kind_of?(String) + NoDelegateMethods = m.collect{|x| x.id2name} + else + NoDelegateMethods = m + end + + def self.initialize + + install_builtin_commands + + # define CommandProcessor#methods to Shell#methods and Filter#methods + for m in CommandProcessor.instance_methods(false) - NoDelegateMethods + add_delegate_command_to_shell(m) + end + + def self.method_added(id) + add_delegate_command_to_shell(id) + end + end + + # + # include run file. + # + def self.run_config + rc = "~/.rb_shell" + begin + load File.expand_path(rc) if ENV.key?("HOME") + rescue LoadError, Errno::ENOENT + rescue + print "load error: #{rc}\n" + print $!.class, ": ", $!, "\n" + for err in $@[0, $@.size - 2] + print "\t", err, "\n" + end + end + end + + def initialize(shell) + @shell = shell + @system_commands = {} + end + + # + # CommandProcessor#expand_path(path) + # path: String + # return: String + # returns the absolute path for + # + def expand_path(path) + @shell.expand_path(path) + end + + # call-seq: + # foreach(path, record_separator) -> Enumerator + # foreach(path, record_separator) { block } + # + # See IO.foreach when +path+ is a file. + # + # See Dir.foreach when +path+ is a directory. + # + def foreach(path = nil, *rs) + path = "." unless path + path = expand_path(path) + + if File.directory?(path) + Dir.foreach(path){|fn| yield fn} + else + IO.foreach(path, *rs){|l| yield l} + end + end + + # call-seq: + # open(path, mode, permissions) -> Enumerator + # open(path, mode, permissions) { block } + # + # See IO.open when +path+ is a file. + # + # See Dir.open when +path+ is a directory. + # + def open(path, mode = nil, perm = 0666, &b) + path = expand_path(path) + if File.directory?(path) + Dir.open(path, &b) + else + if @shell.umask + f = File.open(path, mode, perm) + File.chmod(perm & ~@shell.umask, path) + if block_given? + f.each(&b) + end + f + else + File.open(path, mode, perm, &b) + end + end + end + + # call-seq: + # unlink(path) + # + # See IO.unlink when +path+ is a file. + # + # See Dir.unlink when +path+ is a directory. + # + def unlink(path) + @shell.check_point + + path = expand_path(path) + if File.directory?(path) + Dir.unlink(path) + else + IO.unlink(path) + end + Void.new(@shell) + end + + # See Shell::CommandProcessor#test + alias top_level_test test + # call-seq: + # test(command, file1, file2) -> true or false + # [command, file1, file2] -> true or false + # + # Tests if the given +command+ exists in +file1+, or optionally +file2+. + # + # Example: + # sh[?e, "foo"] + # sh[:e, "foo"] + # sh["e", "foo"] + # sh[:exists?, "foo"] + # sh["exists?", "foo"] + # + def test(command, file1, file2=nil) + file1 = expand_path(file1) + file2 = expand_path(file2) if file2 + command = command.id2name if command.kind_of?(Symbol) + + case command + when Integer + if file2 + top_level_test(command, file1, file2) + else + top_level_test(command, file1) + end + when String + if command.size == 1 + if file2 + top_level_test(command, file1, file2) + else + top_level_test(command, file1) + end + else + unless FileTest.methods(false).include?(command.to_sym) + raise "unsupported command: #{ command }" + end + if file2 + FileTest.send(command, file1, file2) + else + FileTest.send(command, file1) + end + end + end + end + # See Shell::CommandProcessor#test + alias [] test + + # call-seq: + # mkdir(path) + # + # Same as Dir.mkdir, except multiple directories are allowed. + def mkdir(*path) + @shell.check_point + notify("mkdir #{path.join(' ')}") + + perm = nil + if path.last.kind_of?(Integer) + perm = path.pop + end + for dir in path + d = expand_path(dir) + if perm + Dir.mkdir(d, perm) + else + Dir.mkdir(d) + end + File.chmod(d, 0666 & ~@shell.umask) if @shell.umask + end + Void.new(@shell) + end + + # call-seq: + # rmdir(path) + # + # Same as Dir.rmdir, except multiple directories are allowed. + def rmdir(*path) + @shell.check_point + notify("rmdir #{path.join(' ')}") + + for dir in path + Dir.rmdir(expand_path(dir)) + end + Void.new(@shell) + end + + # call-seq: + # system(command, *options) -> SystemCommand + # + # Executes the given +command+ with the +options+ parameter. + # + # Example: + # print sh.system("ls", "-l") + # sh.system("ls", "-l") | sh.head > STDOUT + # + def system(command, *opts) + if opts.empty? + if command =~ /\*|\?|\{|\}|\[|\]|<|>|\(|\)|~|&|\||\\|\$|;|'|`|"|\n/ + return SystemCommand.new(@shell, find_system_command("sh"), "-c", command) + else + command, *opts = command.split(/\s+/) + end + end + SystemCommand.new(@shell, find_system_command(command), *opts) + end + + # call-seq: + # rehash + # + # Clears the command hash table. + def rehash + @system_commands = {} + end + + def check_point # :nodoc: + @shell.process_controller.wait_all_jobs_execution + end + alias finish_all_jobs check_point # :nodoc: + + # call-seq: + # transact { block } + # + # Executes a block as self + # + # Example: + # sh.transact { system("ls", "-l") | head > STDOUT } + def transact(&block) + begin + @shell.instance_eval(&block) + ensure + check_point + end + end + + # call-seq: + # out(device) { block } + # + # Calls device.print on the result passing the _block_ to + # #transact + def out(dev = STDOUT, &block) + dev.print transact(&block) + end + + # call-seq: + # echo(*strings) -> Echo + # + # Returns a Echo object, for the given +strings+ + def echo(*strings) + Echo.new(@shell, *strings) + end + + # call-seq: + # cat(*filename) -> Cat + # + # Returns a Cat object, for the given +filenames+ + def cat(*filenames) + Cat.new(@shell, *filenames) + end + + # def sort(*filenames) + # Sort.new(self, *filenames) + # end + # call-seq: + # glob(pattern) -> Glob + # + # Returns a Glob filter object, with the given +pattern+ object + def glob(pattern) + Glob.new(@shell, pattern) + end + + def append(to, filter) + case to + when String + AppendFile.new(@shell, to, filter) + when IO + AppendIO.new(@shell, to, filter) + else + Shell.Fail Error::CantApplyMethod, "append", to.class + end + end + + # call-seq: + # tee(file) -> Tee + # + # Returns a Tee filter object, with the given +file+ command + def tee(file) + Tee.new(@shell, file) + end + + # call-seq: + # concat(*jobs) -> Concat + # + # Returns a Concat object, for the given +jobs+ + def concat(*jobs) + Concat.new(@shell, *jobs) + end + + # %pwd, %cwd -> @pwd + def notify(*opts) + Shell.notify(*opts) {|mes| + yield mes if block_given? + + mes.gsub!("%pwd", "#{@cwd}") + mes.gsub!("%cwd", "#{@cwd}") + } + end + + # + # private functions + # + def find_system_command(command) + return command if /^\// =~ command + case path = @system_commands[command] + when String + if exists?(path) + return path + else + Shell.Fail Error::CommandNotFound, command + end + when false + Shell.Fail Error::CommandNotFound, command + end + + for p in @shell.system_path + path = join(p, command) + begin + st = File.stat(path) + rescue SystemCallError + next + else + next unless st.executable? and !st.directory? + @system_commands[command] = path + return path + end + end + @system_commands[command] = false + Shell.Fail Error::CommandNotFound, command + end + + # call-seq: + # def_system_command(command, path) -> Shell::SystemCommand + # + # Defines a command, registering +path+ as a Shell method for the given + # +command+. + # + # Shell::CommandProcessor.def_system_command "ls" + # #=> Defines ls. + # + # Shell::CommandProcessor.def_system_command "sys_sort", "sort" + # #=> Defines sys_sort as sort + # + def self.def_system_command(command, path = command) + begin + eval((d = %Q[def #{command}(*opts) + SystemCommand.new(@shell, '#{path}', *opts) + end]), nil, __FILE__, __LINE__ - 1) + rescue SyntaxError + Shell.notify "warn: Can't define #{command} path: #{path}." + end + Shell.notify "Define #{command} path: #{path}.", Shell.debug? + Shell.notify("Definition of #{command}: ", d, + Shell.debug.kind_of?(Integer) && Shell.debug > 1) + end + + # call-seq: + # undef_system_command(command) -> self + # + # Undefines a command + def self.undef_system_command(command) + command = command.id2name if command.kind_of?(Symbol) + remove_method(command) + Shell.module_eval{remove_method(command)} + Filter.module_eval{remove_method(command)} + self + end + + @alias_map = {} + # Returns a list of aliased commands + def self.alias_map + @alias_map + end + # call-seq: + # alias_command(alias, command, *options) -> self + # + # Creates a command alias at the given +alias+ for the given +command+, + # passing any +options+ along with it. + # + # Shell::CommandProcessor.alias_command "lsC", "ls", "-CBF", "--show-control-chars" + # Shell::CommandProcessor.alias_command("lsC", "ls"){|*opts| ["-CBF", "--show-control-chars", *opts]} + # + def self.alias_command(ali, command, *opts) + ali = ali.id2name if ali.kind_of?(Symbol) + command = command.id2name if command.kind_of?(Symbol) + begin + if block_given? + @alias_map[ali.intern] = proc + + eval((d = %Q[def #{ali}(*opts) + @shell.__send__(:#{command}, + *(CommandProcessor.alias_map[:#{ali}].call *opts)) + end]), nil, __FILE__, __LINE__ - 1) + + else + args = opts.collect{|opt| '"' + opt + '"'}.join(",") + eval((d = %Q[def #{ali}(*opts) + @shell.__send__(:#{command}, #{args}, *opts) + end]), nil, __FILE__, __LINE__ - 1) + end + rescue SyntaxError + Shell.notify "warn: Can't alias #{ali} command: #{command}." + Shell.notify("Definition of #{ali}: ", d) + raise + end + Shell.notify "Define #{ali} command: #{command}.", Shell.debug? + Shell.notify("Definition of #{ali}: ", d, + Shell.debug.kind_of?(Integer) && Shell.debug > 1) + self + end + + # call-seq: + # unalias_command(alias) -> self + # + # Unaliases the given +alias+ command. + def self.unalias_command(ali) + ali = ali.id2name if ali.kind_of?(Symbol) + @alias_map.delete ali.intern + undef_system_command(ali) + end + + # :nodoc: + # + # Delegates File and FileTest methods into Shell, including the following + # commands: + # + # * Shell#blockdev?(file) + # * Shell#chardev?(file) + # * Shell#directory?(file) + # * Shell#executable?(file) + # * Shell#executable_real?(file) + # * Shell#exist?(file)/Shell#exists?(file) + # * Shell#file?(file) + # * Shell#grpowned?(file) + # * Shell#owned?(file) + # * Shell#pipe?(file) + # * Shell#readable?(file) + # * Shell#readable_real?(file) + # * Shell#setgid?(file) + # * Shell#setuid?(file) + # * Shell#size(file)/Shell#size?(file) + # * Shell#socket?(file) + # * Shell#sticky?(file) + # * Shell#symlink?(file) + # * Shell#writable?(file) + # * Shell#writable_real?(file) + # * Shell#zero?(file) + # * Shell#syscopy(filename_from, filename_to) + # * Shell#copy(filename_from, filename_to) + # * Shell#move(filename_from, filename_to) + # * Shell#compare(filename_from, filename_to) + # * Shell#safe_unlink(*filenames) + # * Shell#makedirs(*filenames) + # * Shell#install(filename_from, filename_to, mode) + # + # And also, there are some aliases for convenience: + # + # * Shell#cmp <- Shell#compare + # * Shell#mv <- Shell#move + # * Shell#cp <- Shell#copy + # * Shell#rm_f <- Shell#safe_unlink + # * Shell#mkpath <- Shell#makedirs + # + def self.def_builtin_commands(delegation_class, command_specs) + for meth, args in command_specs + arg_str = args.collect{|arg| arg.downcase}.join(", ") + call_arg_str = args.collect{ + |arg| + case arg + when /^(FILENAME.*)$/ + format("expand_path(%s)", $1.downcase) + when /^(\*FILENAME.*)$/ + # \*FILENAME* -> filenames.collect{|fn| expand_path(fn)}.join(", ") + $1.downcase + '.collect{|fn| expand_path(fn)}' + else + arg + end + }.join(", ") + d = %Q[def #{meth}(#{arg_str}) + #{delegation_class}.#{meth}(#{call_arg_str}) + end] + Shell.notify "Define #{meth}(#{arg_str})", Shell.debug? + Shell.notify("Definition of #{meth}: ", d, + Shell.debug.kind_of?(Integer) && Shell.debug > 1) + eval d + end + end + + # call-seq: + # install_system_commands(prefix = "sys_") + # + # Defines all commands in the Shell.default_system_path as Shell method, + # all with given +prefix+ appended to their names. + # + # Any invalid character names are converted to +_+, and errors are passed + # to Shell.notify. + # + # Methods already defined are skipped. + def self.install_system_commands(pre = "sys_") + defined_meth = {} + for m in Shell.methods + defined_meth[m] = true + end + sh = Shell.new + for path in Shell.default_system_path + next unless sh.directory? path + sh.cd path + sh.foreach do + |cn| + if !defined_meth[pre + cn] && sh.file?(cn) && sh.executable?(cn) + command = (pre + cn).gsub(/\W/, "_").sub(/^([0-9])/, '_\1') + begin + def_system_command(command, sh.expand_path(cn)) + rescue + Shell.notify "warn: Can't define #{command} path: #{cn}" + end + defined_meth[command] = command + end + end + end + end + + def self.add_delegate_command_to_shell(id) # :nodoc: + id = id.intern if id.kind_of?(String) + name = id.id2name + if Shell.method_defined?(id) + Shell.notify "warn: override definition of Shell##{name}." + Shell.notify "warn: alias Shell##{name} to Shell##{name}_org.\n" + Shell.module_eval "alias #{name}_org #{name}" + end + Shell.notify "method added: Shell##{name}.", Shell.debug? + Shell.module_eval(%Q[def #{name}(*args, &block) + begin + @command_processor.__send__(:#{name}, *args, &block) + rescue Exception + $@.delete_if{|s| /:in `__getobj__'$/ =~ s} #` + $@.delete_if{|s| /^\\(eval\\):/ =~ s} + raise + end + end], __FILE__, __LINE__) + + if Shell::Filter.method_defined?(id) + Shell.notify "warn: override definition of Shell::Filter##{name}." + Shell.notify "warn: alias Shell##{name} to Shell::Filter##{name}_org." + Filter.module_eval "alias #{name}_org #{name}" + end + Shell.notify "method added: Shell::Filter##{name}.", Shell.debug? + Filter.module_eval(%Q[def #{name}(*args, &block) + begin + self | @shell.__send__(:#{name}, *args, &block) + rescue Exception + $@.delete_if{|s| /:in `__getobj__'$/ =~ s} #` + $@.delete_if{|s| /^\\(eval\\):/ =~ s} + raise + end + end], __FILE__, __LINE__) + end + + # Delegates File methods into Shell, including the following commands: + # + # * Shell#atime(file) + # * Shell#basename(file, *opt) + # * Shell#chmod(mode, *files) + # * Shell#chown(owner, group, *file) + # * Shell#ctime(file) + # * Shell#delete(*file) + # * Shell#dirname(file) + # * Shell#ftype(file) + # * Shell#join(*file) + # * Shell#link(file_from, file_to) + # * Shell#lstat(file) + # * Shell#mtime(file) + # * Shell#readlink(file) + # * Shell#rename(file_from, file_to) + # * Shell#split(file) + # * Shell#stat(file) + # * Shell#symlink(file_from, file_to) + # * Shell#truncate(file, length) + # * Shell#utime(atime, mtime, *file) + # + def self.install_builtin_commands + # method related File. + # (exclude open/foreach/unlink) + normal_delegation_file_methods = [ + ["atime", ["FILENAME"]], + ["basename", ["fn", "*opts"]], + ["chmod", ["mode", "*FILENAMES"]], + ["chown", ["owner", "group", "*FILENAME"]], + ["ctime", ["FILENAMES"]], + ["delete", ["*FILENAMES"]], + ["dirname", ["FILENAME"]], + ["ftype", ["FILENAME"]], + ["join", ["*items"]], + ["link", ["FILENAME_O", "FILENAME_N"]], + ["lstat", ["FILENAME"]], + ["mtime", ["FILENAME"]], + ["readlink", ["FILENAME"]], + ["rename", ["FILENAME_FROM", "FILENAME_TO"]], + ["split", ["pathname"]], + ["stat", ["FILENAME"]], + ["symlink", ["FILENAME_O", "FILENAME_N"]], + ["truncate", ["FILENAME", "length"]], + ["utime", ["atime", "mtime", "*FILENAMES"]]] + + def_builtin_commands(File, normal_delegation_file_methods) + alias_method :rm, :delete + + # method related FileTest + def_builtin_commands(FileTest, + FileTest.singleton_methods(false).collect{|m| [m, ["FILENAME"]]}) + + end + + end +end diff --git a/func_ruby/gems/ruby/3.3.0/gems/shell-0.8.1/lib/shell/error.rb b/func_ruby/gems/ruby/3.3.0/gems/shell-0.8.1/lib/shell/error.rb new file mode 100644 index 0000000..677c424 --- /dev/null +++ b/func_ruby/gems/ruby/3.3.0/gems/shell-0.8.1/lib/shell/error.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: false +# +# shell/error.rb - +# $Release Version: 0.7 $ +# $Revision$ +# by Keiju ISHITSUKA(keiju@ruby-lang.org) +# +# -- +# +# +# + +require "e2mmap" + +class Shell + module Error + extend Exception2MessageMapper + def_e2message TypeError, "wrong argument type %s (expected %s)" + + def_exception :DirStackEmpty, "Directory stack empty." + def_exception :CantDefine, "Can't define method(%s, %s)." + def_exception :CantApplyMethod, "This method(%s) does not apply to this type(%s)." + def_exception :CommandNotFound, "Command not found(%s)." + end +end + diff --git a/func_ruby/gems/ruby/3.3.0/gems/shell-0.8.1/lib/shell/filter.rb b/func_ruby/gems/ruby/3.3.0/gems/shell-0.8.1/lib/shell/filter.rb new file mode 100644 index 0000000..caa976a --- /dev/null +++ b/func_ruby/gems/ruby/3.3.0/gems/shell-0.8.1/lib/shell/filter.rb @@ -0,0 +1,138 @@ +# frozen_string_literal: false +# +# shell/filter.rb - +# $Release Version: 0.7 $ +# $Revision$ +# by Keiju ISHITSUKA(keiju@ruby-lang.org) +# +# -- +# +# +# + +class Shell #:nodoc: + # Any result of command execution is a Filter. + # + # This class includes Enumerable, therefore a Filter object can use all + # Enumerable + # facilities. + # + class Filter + include Enumerable + + def initialize(sh) + @shell = sh # parent shell + @input = nil # input filter + end + + attr_reader :input + + def input=(filter) + @input = filter + end + + # call-seq: + # each(record_separator=nil) { block } + # + # Iterates a block for each line. + def each(rs = nil) + rs = @shell.record_separator unless rs + if @input + @input.each(rs){|l| yield l} + end + end + + # call-seq: + # < source + # + # Inputs from +source+, which is either a string of a file name or an IO + # object. + def <(src) + case src + when String + cat = Cat.new(@shell, src) + cat | self + when IO + self.input = src + self + else + Shell.Fail Error::CantApplyMethod, "<", src.class + end + end + + # call-seq: + # > source + # + # Outputs from +source+, which is either a string of a file name or an IO + # object. + def >(to) + case to + when String + dst = @shell.open(to, "w") + begin + each(){|l| dst << l} + ensure + dst.close + end + when IO + each(){|l| to << l} + else + Shell.Fail Error::CantApplyMethod, ">", to.class + end + self + end + + # call-seq: + # >> source + # + # Appends the output to +source+, which is either a string of a file name + # or an IO object. + def >>(to) + begin + Shell.cd(@shell.pwd).append(to, self) + rescue CantApplyMethod + Shell.Fail Error::CantApplyMethod, ">>", to.class + end + end + + # call-seq: + # | filter + # + # Processes a pipeline. + def |(filter) + filter.input = self + if active? + @shell.process_controller.start_job filter + end + filter + end + + # call-seq: + # filter1 + filter2 + # + # Outputs +filter1+, and then +filter2+ using Join.new + def +(filter) + Join.new(@shell, self, filter) + end + + def to_a + ary = [] + each(){|l| ary.push l} + ary + end + + def to_s + str = "" + each(){|l| str.concat l} + str + end + + def inspect + if @shell.debug.kind_of?(Integer) && @shell.debug > 2 + super + else + to_s + end + end + end +end diff --git a/func_ruby/gems/ruby/3.3.0/gems/shell-0.8.1/lib/shell/process-controller.rb b/func_ruby/gems/ruby/3.3.0/gems/shell-0.8.1/lib/shell/process-controller.rb new file mode 100644 index 0000000..d54da68 --- /dev/null +++ b/func_ruby/gems/ruby/3.3.0/gems/shell-0.8.1/lib/shell/process-controller.rb @@ -0,0 +1,309 @@ +# frozen_string_literal: false +# +# shell/process-controller.rb - +# $Release Version: 0.7 $ +# $Revision$ +# by Keiju ISHITSUKA(keiju@ruby-lang.org) +# +# -- +# +# +# +require "forwardable" +require "sync" + +class Shell + class ProcessController + + @ProcessControllers = {} + @ProcessControllersMonitor = Thread::Mutex.new + @ProcessControllersCV = Thread::ConditionVariable.new + + @BlockOutputMonitor = Thread::Mutex.new + @BlockOutputCV = Thread::ConditionVariable.new + + class << self + extend Forwardable + + def_delegator("@ProcessControllersMonitor", + "synchronize", "process_controllers_exclusive") + + def active_process_controllers + process_controllers_exclusive do + @ProcessControllers.dup + end + end + + def activate(pc) + process_controllers_exclusive do + @ProcessControllers[pc] ||= 0 + @ProcessControllers[pc] += 1 + end + end + + def inactivate(pc) + process_controllers_exclusive do + if @ProcessControllers[pc] + if (@ProcessControllers[pc] -= 1) == 0 + @ProcessControllers.delete(pc) + @ProcessControllersCV.signal + end + end + end + end + + def each_active_object + process_controllers_exclusive do + for ref in @ProcessControllers.keys + yield ref + end + end + end + + def block_output_synchronize(&b) + @BlockOutputMonitor.synchronize(&b) + end + + def wait_to_finish_all_process_controllers + process_controllers_exclusive do + while !@ProcessControllers.empty? + Shell::notify("Process finishing, but active shell exists", + "You can use Shell#transact or Shell#check_point for more safe execution.") + if Shell.debug? + for pc in @ProcessControllers.keys + Shell::notify(" Not finished jobs in "+pc.shell.to_s) + for com in pc.jobs + com.notify(" Jobs: %id") + end + end + end + @ProcessControllersCV.wait(@ProcessControllersMonitor) + end + end + end + end + + # for shell-command complete finish at this process exit. + USING_AT_EXIT_WHEN_PROCESS_EXIT = true + at_exit do + wait_to_finish_all_process_controllers unless $@ + end + + def initialize(shell) + @shell = shell + @waiting_jobs = [] + @active_jobs = [] + @jobs_sync = Sync.new + + @job_monitor = Thread::Mutex.new + @job_condition = Thread::ConditionVariable.new + end + + attr_reader :shell + + def jobs + jobs = [] + @jobs_sync.synchronize(:SH) do + jobs.concat @waiting_jobs + jobs.concat @active_jobs + end + jobs + end + + def active_jobs + @active_jobs + end + + def waiting_jobs + @waiting_jobs + end + + def jobs_exist? + @jobs_sync.synchronize(:SH) do + @active_jobs.empty? or @waiting_jobs.empty? + end + end + + def active_jobs_exist? + @jobs_sync.synchronize(:SH) do + @active_jobs.empty? + end + end + + def waiting_jobs_exist? + @jobs_sync.synchronize(:SH) do + @waiting_jobs.empty? + end + end + + # schedule a command + def add_schedule(command) + @jobs_sync.synchronize(:EX) do + ProcessController.activate(self) + if @active_jobs.empty? + start_job command + else + @waiting_jobs.push(command) + end + end + end + + # start a job + def start_job(command = nil) + @jobs_sync.synchronize(:EX) do + if command + return if command.active? + @waiting_jobs.delete command + else + command = @waiting_jobs.shift + + return unless command + end + @active_jobs.push command + command.start + + # start all jobs that input from the job + for job in @waiting_jobs.dup + start_job(job) if job.input == command + end + end + end + + def waiting_job?(job) + @jobs_sync.synchronize(:SH) do + @waiting_jobs.include?(job) + end + end + + def active_job?(job) + @jobs_sync.synchronize(:SH) do + @active_jobs.include?(job) + end + end + + # terminate a job + def terminate_job(command) + @jobs_sync.synchronize(:EX) do + @active_jobs.delete command + ProcessController.inactivate(self) + if @active_jobs.empty? + command.notify("start_job in terminate_job(%id)", Shell::debug?) + start_job + end + end + end + + # kill a job + def kill_job(sig, command) + @jobs_sync.synchronize(:EX) do + if @waiting_jobs.delete command + ProcessController.inactivate(self) + return + elsif @active_jobs.include?(command) + begin + r = command.kill(sig) + ProcessController.inactivate(self) + rescue + print "Shell: Warn: $!\n" if @shell.verbose? + return nil + end + @active_jobs.delete command + r + end + end + end + + # wait for all jobs to terminate + def wait_all_jobs_execution + @job_monitor.synchronize do + begin + while !jobs.empty? + @job_condition.wait(@job_monitor) + for job in jobs + job.notify("waiting job(%id)", Shell::debug?) + end + end + ensure + redo unless jobs.empty? + end + end + end + + # simple fork + def sfork(command) + pipe_me_in, pipe_peer_out = IO.pipe + pipe_peer_in, pipe_me_out = IO.pipe + + + pid = nil + pid_mutex = Thread::Mutex.new + pid_cv = Thread::ConditionVariable.new + + Thread.start do + ProcessController.block_output_synchronize do + STDOUT.flush + ProcessController.each_active_object do |pc| + for jobs in pc.active_jobs + jobs.flush + end + end + + pid = fork { + Thread.list.each do |th| + th.kill unless Thread.current == th + end + + STDIN.reopen(pipe_peer_in) + STDOUT.reopen(pipe_peer_out) + + ObjectSpace.each_object(IO) do |io| + if ![STDIN, STDOUT, STDERR].include?(io) + io.close + end + end + + yield + } + end + pid_cv.signal + + pipe_peer_in.close + pipe_peer_out.close + command.notify "job(%name:##{pid}) start", @shell.debug? + + begin + _pid = nil + command.notify("job(%id) start to waiting finish.", @shell.debug?) + _pid = Process.waitpid(pid, nil) + rescue Errno::ECHILD + command.notify "warn: job(%id) was done already waitpid." + _pid = true + ensure + command.notify("Job(%id): Wait to finish when Process finished.", @shell.debug?) + # when the process ends, wait until the command terminates + if USING_AT_EXIT_WHEN_PROCESS_EXIT or _pid + else + command.notify("notice: Process finishing...", + "wait for Job[%id] to finish.", + "You can use Shell#transact or Shell#check_point for more safe execution.") + redo + end + + @job_monitor.synchronize do + terminate_job(command) + @job_condition.signal + command.notify "job(%id) finish.", @shell.debug? + end + end + end + + pid_mutex.synchronize do + while !pid + pid_cv.wait(pid_mutex) + end + end + + return pid, pipe_me_in, pipe_me_out + end + end +end diff --git a/func_ruby/gems/ruby/3.3.0/gems/shell-0.8.1/lib/shell/system-command.rb b/func_ruby/gems/ruby/3.3.0/gems/shell-0.8.1/lib/shell/system-command.rb new file mode 100644 index 0000000..9d1b07e --- /dev/null +++ b/func_ruby/gems/ruby/3.3.0/gems/shell-0.8.1/lib/shell/system-command.rb @@ -0,0 +1,159 @@ +# frozen_string_literal: false +# +# shell/system-command.rb - +# $Release Version: 0.7 $ +# $Revision$ +# by Keiju ISHITSUKA(keiju@ruby-lang.org) +# +# -- +# +# +# + +require_relative "filter" + +class Shell + class SystemCommand < Filter + def initialize(sh, command, *opts) + if t = opts.find{|opt| !opt.kind_of?(String) && opt.class} + Shell.Fail TypeError, t.class, "String" + end + super(sh) + @command = command + @opts = opts + + @input_queue = Thread::Queue.new + @pid = nil + + sh.process_controller.add_schedule(self) + end + + attr_reader :command + alias name command + + def wait? + @shell.process_controller.waiting_job?(self) + end + + def active? + @shell.process_controller.active_job?(self) + end + + def input=(inp) + super + if active? + start_export + end + end + + def start + notify([@command, *@opts].join(" ")) + + @pid, @pipe_in, @pipe_out = @shell.process_controller.sfork(self) { + Dir.chdir @shell.pwd + $0 = @command + exec(@command, *@opts) + } + if @input + start_export + end + start_import + end + + def flush + @pipe_out.flush if @pipe_out and !@pipe_out.closed? + end + + def terminate + begin + @pipe_in.close + rescue IOError + end + begin + @pipe_out.close + rescue IOError + end + end + + def kill(sig) + if @pid + Process.kill(sig, @pid) + end + end + + def start_import + notify "Job(%id) start imp-pipe.", @shell.debug? + _eop = true + Thread.start { + begin + while l = @pipe_in.gets + @input_queue.push l + end + _eop = false + rescue Errno::EPIPE + _eop = false + ensure + if !ProcessController::USING_AT_EXIT_WHEN_PROCESS_EXIT and _eop + notify("warn: Process finishing...", + "wait for Job[%id] to finish pipe importing.", + "You can use Shell#transact or Shell#check_point for more safe execution.") + redo + end + notify "job(%id}) close imp-pipe.", @shell.debug? + @input_queue.push :EOF + @pipe_in.close + end + } + end + + def start_export + notify "job(%id) start exp-pipe.", @shell.debug? + _eop = true + Thread.start{ + begin + @input.each do |l| + ProcessController::block_output_synchronize do + @pipe_out.print l + end + end + _eop = false + rescue Errno::EPIPE, Errno::EIO + _eop = false + ensure + if !ProcessController::USING_AT_EXIT_WHEN_PROCESS_EXIT and _eop + notify("shell: warn: Process finishing...", + "wait for Job(%id) to finish pipe exporting.", + "You can use Shell#transact or Shell#check_point for more safe execution.") + redo + end + notify "job(%id) close exp-pipe.", @shell.debug? + @pipe_out.close + end + } + end + + alias super_each each + def each(rs = nil) + while (l = @input_queue.pop) != :EOF + yield l + end + end + + # ex) + # if you wish to output: + # "shell: job(#{@command}:#{@pid}) close pipe-out." + # then + # mes: "job(%id) close pipe-out." + # yorn: Boolean(@shell.debug? or @shell.verbose?) + def notify(*opts) + @shell.notify(*opts) do |mes| + yield mes if block_given? + + mes.gsub!("%id", "#{@command}:##{@pid}") + mes.gsub!("%name", "#{@command}") + mes.gsub!("%pid", "#{@pid}") + mes + end + end + end +end diff --git a/func_ruby/gems/ruby/3.3.0/gems/shell-0.8.1/lib/shell/version.rb b/func_ruby/gems/ruby/3.3.0/gems/shell-0.8.1/lib/shell/version.rb new file mode 100644 index 0000000..4cceb71 --- /dev/null +++ b/func_ruby/gems/ruby/3.3.0/gems/shell-0.8.1/lib/shell/version.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: false +# +# version.rb - shell version definition file +# $Release Version: 0.7$ +# $Revision$ +# by Keiju ISHITSUKA(keiju@ruby-lang.org) +# +# -- +# +# +# + +class Shell # :nodoc: + VERSION = "0.8.1" + @RELEASE_VERSION = VERSION + @LAST_UPDATE_DATE = "07/03/20" +end diff --git a/func_ruby/gems/ruby/3.3.0/gems/shell-0.8.1/shell.gemspec b/func_ruby/gems/ruby/3.3.0/gems/shell-0.8.1/shell.gemspec new file mode 100644 index 0000000..17df0ed --- /dev/null +++ b/func_ruby/gems/ruby/3.3.0/gems/shell-0.8.1/shell.gemspec @@ -0,0 +1,42 @@ +begin + require_relative "lib/shell/version" +rescue LoadError + # for Ruby core repository + require_relative "version" +end + +Gem::Specification.new do |spec| + spec.name = "shell" + spec.version = Shell::VERSION + spec.authors = ["Keiju ISHITSUKA"] + spec.email = ["keiju@ruby-lang.org"] + + spec.summary = %q{An idiomatic Ruby interface for common UNIX shell commands.} + spec.description = %q{An idiomatic Ruby interface for common UNIX shell commands.} + spec.homepage = "https://github.com/ruby/shell" + spec.license = "BSD-2-Clause" + + spec.files = [ + "Gemfile", + "LICENSE.txt", + "README.md", + "Rakefile", + "bin/console", + "bin/setup", + "lib/shell.rb", + "lib/shell/builtin-command.rb", + "lib/shell/command-processor.rb", + "lib/shell/error.rb", + "lib/shell/filter.rb", + "lib/shell/process-controller.rb", + "lib/shell/system-command.rb", + "lib/shell/version.rb", + "shell.gemspec", + ] + spec.bindir = "exe" + spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } + spec.require_paths = ["lib"] + + spec.add_runtime_dependency "e2mmap" + spec.add_runtime_dependency "sync" +end diff --git a/func_ruby/gems/ruby/3.3.0/gems/sync-0.5.0/.travis.yml b/func_ruby/gems/ruby/3.3.0/gems/sync-0.5.0/.travis.yml new file mode 100644 index 0000000..c4abcbe --- /dev/null +++ b/func_ruby/gems/ruby/3.3.0/gems/sync-0.5.0/.travis.yml @@ -0,0 +1,5 @@ +sudo: false +language: ruby +rvm: + - 2.6.0 +before_install: gem install bundler -v 1.16.2 diff --git a/func_ruby/gems/ruby/3.3.0/gems/sync-0.5.0/Gemfile b/func_ruby/gems/ruby/3.3.0/gems/sync-0.5.0/Gemfile new file mode 100644 index 0000000..d2fceab --- /dev/null +++ b/func_ruby/gems/ruby/3.3.0/gems/sync-0.5.0/Gemfile @@ -0,0 +1,5 @@ +source "https://rubygems.org" + +git_source(:github) {|repo_name| "https://github.com/#{repo_name}" } + +gemspec diff --git a/func_ruby/gems/ruby/3.3.0/gems/sync-0.5.0/LICENSE.txt b/func_ruby/gems/ruby/3.3.0/gems/sync-0.5.0/LICENSE.txt new file mode 100644 index 0000000..a009cae --- /dev/null +++ b/func_ruby/gems/ruby/3.3.0/gems/sync-0.5.0/LICENSE.txt @@ -0,0 +1,22 @@ +Copyright (C) 1993-2013 Yukihiro Matsumoto. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. diff --git a/func_ruby/gems/ruby/3.3.0/gems/sync-0.5.0/README.md b/func_ruby/gems/ruby/3.3.0/gems/sync-0.5.0/README.md new file mode 100644 index 0000000..63d6289 --- /dev/null +++ b/func_ruby/gems/ruby/3.3.0/gems/sync-0.5.0/README.md @@ -0,0 +1,77 @@ +# Sync + +A module that provides a two-phase lock with a counter. + +## Installation + +Add this line to your application's Gemfile: + +```ruby +gem 'sync' +``` + +And then execute: + + $ bundle + +Or install it yourself as: + + $ gem install sync + +## Usage + +### Sync_m, Synchronizer_m + +``` +obj.extend(Sync_m) +``` + +or + +``` +class Foo + include Sync_m + : +end +``` + +``` +Sync_m#sync_mode +Sync_m#sync_locked?, locked? +Sync_m#sync_shared?, shared? +Sync_m#sync_exclusive?, sync_exclusive? +Sync_m#sync_try_lock, try_lock +Sync_m#sync_lock, lock +Sync_m#sync_unlock, unlock +``` + +### Sync, Synchronizer: + +``` +sync = Sync.new +``` + +``` +Sync#mode +Sync#locked? +Sync#shared? +Sync#exclusive? +Sync#try_lock(mode) -- mode = :EX, :SH, :UN +Sync#lock(mode) -- mode = :EX, :SH, :UN +Sync#unlock +Sync#synchronize(mode) {...} +``` + +## Development + +After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment. + +To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org). + +## Contributing + +Bug reports and pull requests are welcome on GitHub at https://github.com/ruby/sync. + +## License + +The gem is available as open source under the terms of the [2-Clause BSD License](https://opensource.org/licenses/BSD-2-Clause). diff --git a/func_ruby/gems/ruby/3.3.0/gems/sync-0.5.0/Rakefile b/func_ruby/gems/ruby/3.3.0/gems/sync-0.5.0/Rakefile new file mode 100644 index 0000000..30baabd --- /dev/null +++ b/func_ruby/gems/ruby/3.3.0/gems/sync-0.5.0/Rakefile @@ -0,0 +1,10 @@ +require "bundler/gem_tasks" +require "rake/testtask" + +Rake::TestTask.new(:test) do |t| + t.libs << "test" + t.libs << "lib" + t.test_files = FileList["test/**/test_*.rb"] +end + +task :default => :test diff --git a/func_ruby/gems/ruby/3.3.0/gems/sync-0.5.0/bin/console b/func_ruby/gems/ruby/3.3.0/gems/sync-0.5.0/bin/console new file mode 100755 index 0000000..704914f --- /dev/null +++ b/func_ruby/gems/ruby/3.3.0/gems/sync-0.5.0/bin/console @@ -0,0 +1,7 @@ +#!/usr/bin/env ruby + +require "bundler/setup" +require_relative "../lib/sync" + +require "irb" +IRB.start(__FILE__) diff --git a/func_ruby/gems/ruby/3.3.0/gems/sync-0.5.0/bin/setup b/func_ruby/gems/ruby/3.3.0/gems/sync-0.5.0/bin/setup new file mode 100755 index 0000000..cf4ad25 --- /dev/null +++ b/func_ruby/gems/ruby/3.3.0/gems/sync-0.5.0/bin/setup @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +set -euo pipefail +IFS=$'\n\t' +set -vx + +bundle install diff --git a/func_ruby/gems/ruby/3.3.0/gems/sync-0.5.0/lib/sync.rb b/func_ruby/gems/ruby/3.3.0/gems/sync-0.5.0/lib/sync.rb new file mode 100644 index 0000000..998e2b7 --- /dev/null +++ b/func_ruby/gems/ruby/3.3.0/gems/sync-0.5.0/lib/sync.rb @@ -0,0 +1,328 @@ +# frozen_string_literal: false +# +# sync.rb - 2 phase lock with counter +# $Release Version: 1.0$ +# $Revision$ +# by Keiju ISHITSUKA(keiju@ishitsuka.com) +# +# -- +# Sync_m, Synchronizer_m +# Usage: +# obj.extend(Sync_m) +# or +# class Foo +# include Sync_m +# : +# end +# +# Sync_m#sync_mode +# Sync_m#sync_locked?, locked? +# Sync_m#sync_shared?, shared? +# Sync_m#sync_exclusive?, sync_exclusive? +# Sync_m#sync_try_lock, try_lock +# Sync_m#sync_lock, lock +# Sync_m#sync_unlock, unlock +# +# Sync, Synchronizer: +# Usage: +# sync = Sync.new +# +# Sync#mode +# Sync#locked? +# Sync#shared? +# Sync#exclusive? +# Sync#try_lock(mode) -- mode = :EX, :SH, :UN +# Sync#lock(mode) -- mode = :EX, :SH, :UN +# Sync#unlock +# Sync#synchronize(mode) {...} +# +# + +## +# A module that provides a two-phase lock with a counter. + +module Sync_m + # lock mode + UN = :UN + SH = :SH + EX = :EX + + # exceptions + class Err < StandardError + def Err.Fail(*opt) + fail self, sprintf(self::Message, *opt) + end + + class UnknownLocker < Err + Message = "Thread(%s) not locked." + def UnknownLocker.Fail(th) + super(th.inspect) + end + end + + class LockModeFailer < Err + Message = "Unknown lock mode(%s)" + def LockModeFailer.Fail(mode) + if mode.id2name + mode = mode.id2name + end + super(mode) + end + end + end + + def Sync_m.define_aliases(cl) + cl.module_eval %q{ + alias locked? sync_locked? + alias shared? sync_shared? + alias exclusive? sync_exclusive? + alias lock sync_lock + alias unlock sync_unlock + alias try_lock sync_try_lock + alias synchronize sync_synchronize + } + end + + def Sync_m.append_features(cl) + super + # do nothing for Modules + # make aliases for Classes. + define_aliases(cl) unless cl.instance_of?(Module) + self + end + + def Sync_m.extend_object(obj) + super + obj.sync_extend + end + + def sync_extend + unless (defined? locked? and + defined? shared? and + defined? exclusive? and + defined? lock and + defined? unlock and + defined? try_lock and + defined? synchronize) + Sync_m.define_aliases(singleton_class) + end + sync_initialize + end + + # accessing + def sync_locked? + sync_mode != UN + end + + def sync_shared? + sync_mode == SH + end + + def sync_exclusive? + sync_mode == EX + end + + # locking methods. + def sync_try_lock(mode = EX) + return unlock if mode == UN + @sync_mutex.synchronize do + sync_try_lock_sub(mode) + end + end + + def sync_lock(m = EX) + return unlock if m == UN + Thread.handle_interrupt(StandardError => :on_blocking) do + while true + @sync_mutex.synchronize do + begin + if sync_try_lock_sub(m) + return self + else + if sync_sh_locker[Thread.current] + sync_upgrade_waiting.push [Thread.current, sync_sh_locker[Thread.current]] + sync_sh_locker.delete(Thread.current) + else + unless sync_waiting.include?(Thread.current) || sync_upgrade_waiting.reverse_each.any?{|w| w.first == Thread.current } + sync_waiting.push Thread.current + end + end + @sync_mutex.sleep + end + ensure + sync_waiting.delete(Thread.current) + end + end + end + end + self + end + + def sync_unlock(m = EX) + wakeup_threads = [] + @sync_mutex.synchronize do + if sync_mode == UN + Err::UnknownLocker.Fail(Thread.current) + end + + m = sync_mode if m == EX and sync_mode == SH + + runnable = false + case m + when UN + Err::UnknownLocker.Fail(Thread.current) + + when EX + if sync_ex_locker == Thread.current + if (self.sync_ex_count = sync_ex_count - 1) == 0 + self.sync_ex_locker = nil + if sync_sh_locker.include?(Thread.current) + self.sync_mode = SH + else + self.sync_mode = UN + end + runnable = true + end + else + Err::UnknownLocker.Fail(Thread.current) + end + + when SH + if (count = sync_sh_locker[Thread.current]).nil? + Err::UnknownLocker.Fail(Thread.current) + else + if (sync_sh_locker[Thread.current] = count - 1) == 0 + sync_sh_locker.delete(Thread.current) + if sync_sh_locker.empty? and sync_ex_count == 0 + self.sync_mode = UN + runnable = true + end + end + end + end + + if runnable + if sync_upgrade_waiting.size > 0 + th, count = sync_upgrade_waiting.shift + sync_sh_locker[th] = count + th.wakeup + wakeup_threads.push th + else + wait = sync_waiting + self.sync_waiting = [] + for th in wait + th.wakeup + wakeup_threads.push th + end + end + end + end + for th in wakeup_threads + th.run + end + self + end + + def sync_synchronize(mode = EX) + Thread.handle_interrupt(StandardError => :on_blocking) do + sync_lock(mode) + begin + yield + ensure + sync_unlock + end + end + end + + attr_accessor :sync_mode + + attr_accessor :sync_waiting + attr_accessor :sync_upgrade_waiting + attr_accessor :sync_sh_locker + attr_accessor :sync_ex_locker + attr_accessor :sync_ex_count + + def sync_inspect + sync_iv = instance_variables.select{|iv| /^@sync_/ =~ iv.id2name}.collect{|iv| iv.id2name + '=' + instance_eval(iv.id2name).inspect}.join(",") + print "<#{self.class}.extend Sync_m: #{inspect}, " + end + + private + + def sync_initialize + @sync_mode = UN + @sync_waiting = [] + @sync_upgrade_waiting = [] + @sync_sh_locker = Hash.new + @sync_ex_locker = nil + @sync_ex_count = 0 + + @sync_mutex = Thread::Mutex.new + end + + def initialize(*args) + super + sync_initialize + end + + def sync_try_lock_sub(m) + case m + when SH + case sync_mode + when UN + self.sync_mode = m + sync_sh_locker[Thread.current] = 1 + ret = true + when SH + count = 0 unless count = sync_sh_locker[Thread.current] + sync_sh_locker[Thread.current] = count + 1 + ret = true + when EX + # in EX mode, lock will upgrade to EX lock + if sync_ex_locker == Thread.current + self.sync_ex_count = sync_ex_count + 1 + ret = true + else + ret = false + end + end + when EX + if sync_mode == UN or + sync_mode == SH && sync_sh_locker.size == 1 && sync_sh_locker.include?(Thread.current) + self.sync_mode = m + self.sync_ex_locker = Thread.current + self.sync_ex_count = 1 + ret = true + elsif sync_mode == EX && sync_ex_locker == Thread.current + self.sync_ex_count = sync_ex_count + 1 + ret = true + else + ret = false + end + else + Err::LockModeFailer.Fail m + end + return ret + end +end + +## +# An alias for Sync_m from sync.rb + +Synchronizer_m = Sync_m + +## +# A class that provides two-phase lock with a counter. See Sync_m for +# details. + +class Sync + + VERSION = "0.5.0" + + include Sync_m +end + +## +# An alias for Sync from sync.rb. See Sync_m for details. + +Synchronizer = Sync diff --git a/func_ruby/gems/ruby/3.3.0/gems/sync-0.5.0/sync.gemspec b/func_ruby/gems/ruby/3.3.0/gems/sync-0.5.0/sync.gemspec new file mode 100644 index 0000000..42d40f3 --- /dev/null +++ b/func_ruby/gems/ruby/3.3.0/gems/sync-0.5.0/sync.gemspec @@ -0,0 +1,27 @@ +begin + require_relative "lib/sync" +rescue LoadError + # for Ruby core repository + require_relative "sync" +end + +Gem::Specification.new do |spec| + spec.name = "sync" + spec.version = Sync::VERSION + spec.authors = ["Keiju ISHITSUKA"] + spec.email = ["keiju@ruby-lang.org"] + + spec.summary = %q{A module that provides a two-phase lock with a counter.} + spec.description = %q{A module that provides a two-phase lock with a counter.} + spec.homepage = "https://github.com/ruby/sync" + spec.license = "BSD-2-Clause" + + spec.files = [".gitignore", ".travis.yml", "Gemfile", "LICENSE.txt", "README.md", "Rakefile", "bin/console", "bin/setup", "lib/sync.rb", "sync.gemspec"] + spec.bindir = "exe" + spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } + spec.require_paths = ["lib"] + + spec.add_development_dependency "bundler" + spec.add_development_dependency "rake" + spec.add_development_dependency "test-unit" +end diff --git a/func_ruby/gems/ruby/3.3.0/specifications/e2mmap-0.1.0.gemspec b/func_ruby/gems/ruby/3.3.0/specifications/e2mmap-0.1.0.gemspec new file mode 100644 index 0000000..4a5102b --- /dev/null +++ b/func_ruby/gems/ruby/3.3.0/specifications/e2mmap-0.1.0.gemspec @@ -0,0 +1,26 @@ +# -*- encoding: utf-8 -*- +# stub: e2mmap 0.1.0 ruby lib + +Gem::Specification.new do |s| + s.name = "e2mmap".freeze + s.version = "0.1.0".freeze + + s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= + s.require_paths = ["lib".freeze] + s.authors = ["Keiju ISHITSUKA".freeze] + s.bindir = "exe".freeze + s.date = "2018-12-04" + s.description = "Module for defining custom exceptions with specific messages.".freeze + s.email = ["keiju@ruby-lang.org".freeze] + s.homepage = "https://github.com/ruby/e2mmap".freeze + s.licenses = ["BSD-2-Clause".freeze] + s.rubygems_version = "2.7.6".freeze + s.summary = "Module for defining custom exceptions with specific messages.".freeze + + s.installed_by_version = "3.5.16".freeze if s.respond_to? :installed_by_version + + s.specification_version = 4 + + s.add_development_dependency(%q.freeze, ["~> 1.16".freeze]) + s.add_development_dependency(%q.freeze, ["~> 10.0".freeze]) +end diff --git a/func_ruby/gems/ruby/3.3.0/specifications/envbash-1.0.1.gemspec b/func_ruby/gems/ruby/3.3.0/specifications/envbash-1.0.1.gemspec new file mode 100644 index 0000000..84f4269 --- /dev/null +++ b/func_ruby/gems/ruby/3.3.0/specifications/envbash-1.0.1.gemspec @@ -0,0 +1,26 @@ +# -*- encoding: utf-8 -*- +# stub: envbash 1.0.1 ruby lib + +Gem::Specification.new do |s| + s.name = "envbash".freeze + s.version = "1.0.1".freeze + + s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= + s.require_paths = ["lib".freeze] + s.authors = ["Aron Griffis".freeze] + s.date = "2017-02-18" + s.email = "aron@scampersand.com".freeze + s.homepage = "https://github.com/scampersand/envbash-ruby".freeze + s.licenses = ["MIT".freeze] + s.rubygems_version = "2.5.2".freeze + s.summary = "Source env.bash script to update environment".freeze + + s.installed_by_version = "3.5.16".freeze if s.respond_to? :installed_by_version + + s.specification_version = 4 + + s.add_development_dependency(%q.freeze, [">= 0".freeze]) + s.add_development_dependency(%q.freeze, [">= 0".freeze]) + s.add_development_dependency(%q.freeze, [">= 0".freeze]) + s.add_development_dependency(%q.freeze, [">= 0".freeze]) +end diff --git a/func_ruby/gems/ruby/3.3.0/specifications/interface-1.0.5.gemspec b/func_ruby/gems/ruby/3.3.0/specifications/interface-1.0.5.gemspec new file mode 100644 index 0000000..d306893 --- /dev/null +++ b/func_ruby/gems/ruby/3.3.0/specifications/interface-1.0.5.gemspec @@ -0,0 +1,29 @@ +# -*- encoding: utf-8 -*- +# stub: interface 1.0.5 ruby lib + +Gem::Specification.new do |s| + s.name = "interface".freeze + s.version = "1.0.5".freeze + + s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= + s.metadata = { "bug_tracker_uri" => "https://github.com/djberg96/interface/issues", "changelog_uri" => "https://github.com/djberg96/interface/blob/master/CHANGES", "documentation_uri" => "https://github.com/djberg96/interface/wiki", "homepage_uri" => "https://github.com/djberg96/interface", "source_code_uri" => "https://github.com/djberg96/interface", "wiki_uri" => "https://github.com/djberg96/interface/wiki" } if s.respond_to? :metadata= + s.require_paths = ["lib".freeze] + s.authors = ["Daniel J. Berger".freeze] + s.cert_chain = ["-----BEGIN CERTIFICATE-----\nMIIEcDCCAtigAwIBAgIBATANBgkqhkiG9w0BAQsFADA/MREwDwYDVQQDDAhkamJl\ncmc5NjEVMBMGCgmSJomT8ixkARkWBWdtYWlsMRMwEQYKCZImiZPyLGQBGRYDY29t\nMB4XDTE4MDMxODE1MjIwN1oXDTI4MDMxNTE1MjIwN1owPzERMA8GA1UEAwwIZGpi\nZXJnOTYxFTATBgoJkiaJk/IsZAEZFgVnbWFpbDETMBEGCgmSJomT8ixkARkWA2Nv\nbTCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBALgfaroVM6CI06cxr0/h\nA+j+pc8fgpRgBVmHFaFunq28GPC3IvW7Nvc3Y8SnAW7pP1EQIbhlwRIaQzJ93/yj\nu95KpkP7tA9erypnV7dpzBkzNlX14ACaFD/6pHoXoe2ltBxk3CCyyzx70mTqJpph\n75IB03ni9a8yqn8pmse+s83bFJOAqddSj009sGPcQO+QOWiNxqYv1n5EHcvj2ebO\n6hN7YTmhx7aSia4qL/quc4DlIaGMWoAhvML7u1fmo53CYxkKskfN8MOecq2vfEmL\niLu+SsVVEAufMDDFMXMJlvDsviolUSGMSNRTujkyCcJoXKYYxZSNtIiyd9etI0X3\nctu0uhrFyrMZXCedutvXNjUolD5r9KGBFSWH1R9u2I3n3SAyFF2yzv/7idQHLJJq\n74BMnx0FIq6fCpu5slAipvxZ3ZkZpEXZFr3cIBtO1gFvQWW7E/Y3ijliWJS1GQFq\n058qERadHGu1yu1dojmFRo6W2KZvY9al2yIlbkpDrD5MYQIDAQABo3cwdTAJBgNV\nHRMEAjAAMAsGA1UdDwQEAwIEsDAdBgNVHQ4EFgQUFZsMapgzJimzsbaBG2Tm8j5e\nAzgwHQYDVR0RBBYwFIESZGpiZXJnOTZAZ21haWwuY29tMB0GA1UdEgQWMBSBEmRq\nYmVyZzk2QGdtYWlsLmNvbTANBgkqhkiG9w0BAQsFAAOCAYEAW2tnYixXQtKxgGXq\n/3iSWG2bLwvxS4go3srO+aRXZHrFUMlJ5W0mCxl03aazxxKTsVVpZD8QZxvK91OQ\nh9zr9JBYqCLcCVbr8SkmYCi/laxIZxsNE5YI8cC8vvlLI7AMgSfPSnn/Epq1GjGY\n6L1iRcEDtanGCIvjqlCXO9+BmsnCfEVehqZkQHeYczA03tpOWb6pon2wzvMKSsKH\nks0ApVdstSLz1kzzAqem/uHdG9FyXdbTAwH1G4ZPv69sQAFAOCgAqYmdnzedsQtE\n1LQfaQrx0twO+CZJPcRLEESjq8ScQxWRRkfuh2VeR7cEU7L7KqT10mtUwrvw7APf\nDYoeCY9KyjIBjQXfbj2ke5u1hZj94Fsq9FfbEQg8ygCgwThnmkTrrKEiMSs3alYR\nORVCZpRuCPpmC8qmqxUnARDArzucjaclkxjLWvCVHeFa9UP7K3Nl9oTjJNv+7/jM\nWZs4eecIcUc4tKdHxcAJ0MO/Dkqq7hGaiHpwKY76wQ1+8xAh\n-----END CERTIFICATE-----\n".freeze] + s.date = "2024-11-13" + s.description = " The interface library implements Java style interfaces for Ruby.\n It lets you define a set a methods that must be defined in the\n including class or module, or an error is raised.\n".freeze + s.email = "djberg96@gmail.com".freeze + s.extra_rdoc_files = ["README".freeze, "CHANGES".freeze, "MANIFEST".freeze] + s.files = ["CHANGES".freeze, "MANIFEST".freeze, "README".freeze] + s.homepage = "http://github.com/djberg96/interface".freeze + s.licenses = ["Artistic-2.0".freeze] + s.rubygems_version = "3.0.6".freeze + s.summary = "Java style interfaces for Ruby".freeze + + s.installed_by_version = "3.5.16".freeze if s.respond_to? :installed_by_version + + s.specification_version = 4 + + s.add_development_dependency(%q.freeze, [">= 0".freeze]) + s.add_development_dependency(%q.freeze, [">= 0".freeze]) +end diff --git a/func_ruby/gems/ruby/3.3.0/specifications/shell-0.8.1.gemspec b/func_ruby/gems/ruby/3.3.0/specifications/shell-0.8.1.gemspec new file mode 100644 index 0000000..9e410cd --- /dev/null +++ b/func_ruby/gems/ruby/3.3.0/specifications/shell-0.8.1.gemspec @@ -0,0 +1,26 @@ +# -*- encoding: utf-8 -*- +# stub: shell 0.8.1 ruby lib + +Gem::Specification.new do |s| + s.name = "shell".freeze + s.version = "0.8.1".freeze + + s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= + s.require_paths = ["lib".freeze] + s.authors = ["Keiju ISHITSUKA".freeze] + s.bindir = "exe".freeze + s.date = "2020-07-16" + s.description = "An idiomatic Ruby interface for common UNIX shell commands.".freeze + s.email = ["keiju@ruby-lang.org".freeze] + s.homepage = "https://github.com/ruby/shell".freeze + s.licenses = ["BSD-2-Clause".freeze] + s.rubygems_version = "3.2.0.pre1".freeze + s.summary = "An idiomatic Ruby interface for common UNIX shell commands.".freeze + + s.installed_by_version = "3.5.16".freeze if s.respond_to? :installed_by_version + + s.specification_version = 4 + + s.add_runtime_dependency(%q.freeze, [">= 0".freeze]) + s.add_runtime_dependency(%q.freeze, [">= 0".freeze]) +end diff --git a/func_ruby/gems/ruby/3.3.0/specifications/sync-0.5.0.gemspec b/func_ruby/gems/ruby/3.3.0/specifications/sync-0.5.0.gemspec new file mode 100644 index 0000000..a31ff83 --- /dev/null +++ b/func_ruby/gems/ruby/3.3.0/specifications/sync-0.5.0.gemspec @@ -0,0 +1,27 @@ +# -*- encoding: utf-8 -*- +# stub: sync 0.5.0 ruby lib + +Gem::Specification.new do |s| + s.name = "sync".freeze + s.version = "0.5.0".freeze + + s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= + s.require_paths = ["lib".freeze] + s.authors = ["Keiju ISHITSUKA".freeze] + s.bindir = "exe".freeze + s.date = "2018-12-04" + s.description = "A module that provides a two-phase lock with a counter.".freeze + s.email = ["keiju@ruby-lang.org".freeze] + s.homepage = "https://github.com/ruby/sync".freeze + s.licenses = ["BSD-2-Clause".freeze] + s.rubygems_version = "2.7.6".freeze + s.summary = "A module that provides a two-phase lock with a counter.".freeze + + s.installed_by_version = "3.5.16".freeze if s.respond_to? :installed_by_version + + s.specification_version = 4 + + s.add_development_dependency(%q.freeze, [">= 0".freeze]) + s.add_development_dependency(%q.freeze, [">= 0".freeze]) + s.add_development_dependency(%q.freeze, [">= 0".freeze]) +end diff --git a/func_ruby/global_options.rb b/func_ruby/global_options.rb new file mode 100644 index 0000000..f72eedc --- /dev/null +++ b/func_ruby/global_options.rb @@ -0,0 +1,16 @@ +#!/opt/brepo/ruby33/bin/ruby + +def load_ruby_options_defaults + hestiacp_ruby_func_path = "/usr/local/hestia/func_ruby" + $LOAD_PATH.unshift hestiacp_ruby_func_path + hestiacp_ruby_gem_version = "3.3.0" + Gem.paths = { + "GEM_HOME" => "#{hestiacp_ruby_func_path}/gems/ruby/#{hestiacp_ruby_gem_version}", + "GEM_PATH" => "#{hestiacp_ruby_func_path}/gems/ruby/#{hestiacp_ruby_gem_version}", + } +end + +def load_hestia_default_path_from_env + return ENV["HESTIA"] if ENV.key? "HESTIA" + "/usr/local/hestia" +end diff --git a/func_ruby/main.rb b/func_ruby/main.rb new file mode 100644 index 0000000..896a4ce --- /dev/null +++ b/func_ruby/main.rb @@ -0,0 +1,230 @@ +#!/opt/brepo/ruby33/bin/ruby + +require "date" +require "envbash" +require "interface" +require "json" +require "csv" + +date_internal = DateTime.now +di = date_internal.strftime("%d%m%Y%H%M") +# Internal variables +$HOMEDIR = "/home" +$BACKUP = "/backup" +$BACKUP_GZIP = 9 +$BACKUP_DISK_LIMIT = 95 +$BACKUP_LA_LIMIT = %x(cat /proc/cpuinfo | grep processor | wc -l) +$RRD_STEP = 300 +$BIN = "#{$HESTIA}/bin" +$HESTIA_INSTALL_DIR = "#{$HESTIA}/install/rpm" +$HESTIA_COMMON_DIR = "#{$HESTIA}/install/common" +$HESTIA_BACKUP = "/root/hst_backups/#{di}" +$HESTIA_PHP = "#{$HESTIA}/php/bin/php" +$USER_DATA = "#{$HESTIA}/data/users/#{$user}" +$WEBTPL = "#{$HESTIA}/data/templates/web" +$MAILTPL = "#{$HESTIA}/data/templates/mail" +$DNSTPL = "#{$HESTIA}/data/templates/dns" +$RRD = "#{$HESTIA}/web/rrd" +$SENDMAIL = "#{$HESTIA}/web/inc/mail-wrapper.php" +$HESTIA_GIT_REPO = "https://dev.brepo.ru/bayrepo/hestiacp" +$HESTIA_THEMES = "#{$HESTIA}/web/css/themes" +$HESTIA_THEMES_CUSTOM = "#{$HESTIA}/web/css/themes/custom" +$SCRIPT = File.basename($PROGRAM_NAME) + +# Return codes +OK = 0 +E_ARGS = 1 +E_INVALID = 2 +E_NOTEXIST = 3 +E_EXISTS = 4 +E_SUSPENDED = 5 +E_UNSUSPENDED = 6 +E_INUSE = 7 +E_LIMIT = 8 +E_PASSWORD = 9 +E_FORBIDEN = 10 +E_DISABLED = 11 +E_PARSING = 12 +E_DISK = 13 +E_LA = 14 +E_CONNECT = 15 +E_FTP = 16 +E_DB = 17 +E_RRD = 18 +E_UPDATE = 19 +E_RESTART = 20 +E_PERMISSION = 21 +E_MODULE = 22 + +$ARGUMENTS = "" +ARGV.each_with_index do |item, index| + if !$HIDE.nil? && $HIDE == index + $ARGUMENTS = "#{$ARGUMENTS} '******'" + else + $ARGUMENTS = "#{$ARGUMENTS} #{item}" + end +end + +class File + class << self + def append(path, content) + File.open(path, "a") { |f| f << content } + end + + def append!(path, content) + File.open(path, "a") { |f| f << (content + "\n") } + end + end +end + +def hestia_print_error_message_to_cli(error_message) + puts "Error: #{error_message}" +end + +def load_global_bash_variables(*scripts) + local_arr = {} + + scripts.each do |script| + EnvBash.load(script, into: local_arr) if File.exist? script + end + diff_arr = local_arr.reject { |key, _value| ENV.key? key } + + diff_arr.each do |key, val| + e_val = val.gsub(/'/) { |_c| "\\'" } + str_data = "$#{key}='#{e_val}'" + eval str_data + end +end + +def new_timestamp() + date = DateTime.now + $time = date.strftime("%T") + $date = date.strftime("%d-%m-%Y") +end + +def log_event(error_string, args) + if $time.nil? + date = DateTime.now + log_time = date.strftime("%Y-%m-%d %T") + log_time = "#{log_time} #{File.basename($PROGRAM_NAME)}" + else + log_time = "#{$date} #{$time} #{File.basename($PROGRAM_NAME)}" + end + code_number = error_string.to_i + if code_number.zero? + File.append! "#{$HESTIA}/log/system.log", "#{log_time} #{args}" unless $HESTIA.nil? + else + File.append! "#{$HESTIA}/log/error.log", "#{log_time} #{args} [Error #{error_string}]" unless $HESTIA.nil? + end +end + +def check_result(error_code:, error_message:, custom_error: -1, silent: false, callback_func: nil) + if error_code != OK + loc_error = custom_error != -1 ? custom_error : error_code + return callback_func(error_code, error_message) if callback_func + + hestia_print_error_message_to_cli error_message unless silent + log_event loc_error, $ARGUMENTS + exit error_code + end + OK +end + +def check_args(req_params, params, usage) + if req_params > params.length + puts "Usage #{File.basename($PROGRAM_NAME)} #{usage}" + check_result error_code: E_ARGS, error_message: "not enought arguments", silent: true + else + OK + end +end + +def check_hestia_demo_mode + File.open("/usr/local/hestia/conf/hestia.conf") do |f| + until f.eof? + item = f.gets.strip + conf_data = item.split("=").map(&:strip!) + if conf_data.length > 1 && conf_data[0] == "DEMO_MODE" && conf_data[1].downcase == "yes" + hestia_print_error_message_to_cli "Unable to perform operation due to security restrictions that are in place." + exit(1) + end + end + end +end + +def hestia_check_privileged_user + if Process.uid != 0 + hestia_print_error_message_to_cli "Script must run under privileged user" + log_event E_PERMISSION, $ARGUMENTS + exit(1) + end +end + +def hestia_format_cli_table(in_array) + arr_max_len = {} + in_array.each do |elem| + elem.each_with_index do |item, index| + arr_max_len[index] = item.to_s.length unless arr_max_len.key? index + arr_max_len[index] = item.to_s.length if arr_max_len.key?(index) && (arr_max_len[index] < item.to_s.length) + end + end + in_array.each do |elem| + elem.each_with_index do |item, index| + print " %s " % item.to_s.ljust(arr_max_len[index]) + end + print "\n" + end +end + +def hestia_print_array_of_hashes(in_array = nil, format = "shell", header = nil) + return if in_array.nil? && (format == "json" || format == "plain" || format == "csv") + case format + when "json" + puts in_array.to_json + when "plain" + in_array.each do |item| + data_wrapper = [] + item.each do |key, val| + data_wrapper << val.to_s + end + puts data_wrapper.join("\t") + end + when "csv" + data_wrapper = in_array.map do |row| + row.values.to_csv + end + puts data_wrapper + else + headers = nil + unless header.nil? + headers = header.split(",").map(&:strip) + end + if !in_array.nil? && headers.nil? + headers = [] + in_array.first.each_key do |key| + headers << key.to_s + end + end + data_out = [] + unless headers.nil? + data_out << headers + data_out << headers.map { |i| "-" * i.to_s.length } + end + unless in_array.nil? + in_array.each do |val| + row = [] + headers.each do |item| + row << if val.key? item + val[item] + elsif val.key? item.to_sym + val[item.to_sym] + else + "" + end + end + data_out << row + end + end + hestia_format_cli_table(data_out) + end +end diff --git a/func_ruby/modules.rb b/func_ruby/modules.rb new file mode 100644 index 0000000..59006cc --- /dev/null +++ b/func_ruby/modules.rb @@ -0,0 +1,271 @@ +#!/opt/brepo/ruby33/bin/ruby + +require "main" +require "interface" +require "json" +require "csv" +require "date" + +IPluginInterface = interface do + required_methods :info, :key, :enable, :disable, :log, :command +end + +class Kernel::PluginConfiguration + attr_accessor :key_readed + CONF_PATH = "#{$HESTIA}/conf/ext-modules.conf" + MODULES_PATH = "#{$HESTIA}/func_ruby/ext-modules" + KEY_FILE_PATH = "#{$HESTIA}/func_ruby/ext-modules/api.key" + MODULES_DATA_PATH = "#{$HESTIA}/func_ruby/ext-modules/payload" + MODULES_CONF_PATH = "#{$HESTIA}/func_ruby/ext-modules/configs" + + @@loaded_plugins = {} + + def get_loaded_plugins + @@loaded_plugins + end + + def not_implemented + raise "Not Implemented" + end + + def key_file_create + g_key = (0...10).map { ("0".."9").to_a[rand(10)] }.join + begin + f = File.new(KEY_FILE_PATH, File::CREAT | File::WRONLY, 0o600) + f.write(g_key) + f.close + rescue => e + hestia_print_error_message_to_cli "Error with ext-modules key file creation #{e.message} #{e.backtrace.first}" + log_event E_PERMISSION, $ARGUMENTS + exit(1) + end + g_key + end + + def generate_key + hestia_check_privileged_user + if File.exist?(KEY_FILE_PATH) + if (File.stat(KEY_FILE_PATH).mode & 0xFFF).to_s(8) != "600" + File.unlink(KEY_FILE_PATH) + key_file_create + end + else + key_file_create + end + begin + f = File.open(KEY_FILE_PATH) + result = f.gets + f.close + raise "incorrect length" if result.nil? || result.length != 10 + result.chomp + rescue => e + File.unlink(KEY_FILE_PATH) if File.exist?(KEY_FILE_PATH) + key_file_create + end + end + + def initialize + @key_readed = generate_key + end + + @@loaded_plugins["default"] = :not_implemented +end + +class Kernel::ModuleCoreWorker + ACTION_OK = "" + + def key + begin + File.open(Kernel::PluginConfiguration::KEY_FILE_PATH) do |f| + result = f.gets.chomp + return result + end + rescue + "" + end + end + + def get_log + "#{$HESTIA}/log/#{self.class::MODULE_ID}.log" + end + + def log(format, *args) + return if $HESTIA.nil? + + log_file = "#{$HESTIA}/log/#{self.class::MODULE_ID}.log" + date = DateTime.now + log_time = date.strftime("%Y-%m-%d %T") + log_time = "#{log_time} #{File.basename($PROGRAM_NAME)}" + out_result = format % args + + File.append! log_file, "#{log_time} #{out_result}" + end + + def check + result = self.info + if result[:REQ] == "" || result[:REQ].nil? + true + else + reqs = result[:REQ].split(",") + full_result = true + reqs.each do |mname| + nm = mname.strip + if hestia_ext_module_state_in_conf(nm, :get) == "disabled" + full_result = false + end + end + full_result + end + end + + def enable + log("#{self.class::MODULE_ID} enabled") + ACTION_OK + end + + def disable + log("#{self.class::MODULE_ID} disabled") + ACTION_OK + end + + def get_module_paydata(file_path) + "#{Kernel::PluginConfiguration::MODULES_DATA_PATH}/#{self.class::MODULE_ID}/#{file_path}" + end + + def get_module_conf(file_path) + "#{Kernel::PluginConfiguration::MODULES_CONF_PATH}/#{self.class::MODULE_ID}/#{file_path}" + end + + def command(args) + log("#{self.class::MODULE_ID} execute commands with args #{args}") + ACTION_OK + end +end + +class PluginManager + def initialize(default_plugin = "default") + @default_plugin = default_plugin + @config = PluginConfiguration.new + @loaded_modules = {} + end + + def get_loaded_plugins + @config.get_loaded_plugins + end + + def get_key + @config.key_readed + end + + def get_instance(plugin_name) + plugin_handler = case get_loaded_plugins[plugin_name] + when Symbol + @config.method(get_loaded_plugins[plugin_name]) + when Proc + get_loaded_plugins[plugin_name] + else + @config.method(get_loaded_plugins[@default_plugin]) + end + plugin_handler.call + end + + def load_plugins(filter = nil, list = nil) + Dir.glob("#{PluginConfiguration::MODULES_PATH}/*.mod").each do |f| + if File.exist?(f) && !File.directory?(f) && File.stat(f).uid.zero? && !@loaded_modules.include?(f) + begin + process_file = true + process_f = File.basename(f, ".mod") + if !list.nil? && filter.nil? + result = list.split(",").map do |nm| + nm1 = nm.strip + File.basename(nm1, ".mod") + end + process_file = result.include? process_f unless result.nil? + else + process_file = (process_f.match? Regexp.new(filter)) unless filter.nil? + end + f_name = File.basename(f, ".mod").gsub("-", "_") + eval "module PluginsContainer_#{f_name}; end" + eval "load f, PluginsContainer_#{f_name} if process_file" + @loaded_modules[f] = 1 + rescue => e + hestia_print_error_message_to_cli "Module loading #{f}: #{e.message} #{e.backtrace.first}" + log_event E_INVALID, $ARGUMENTS + exit(1) + end + end + end + end +end + +def hestia_ext_module_state_in_conf(module_id, action = :get) + case action + when :get + return "disabled" unless File.exist?(Kernel::PluginConfiguration::CONF_PATH) + File.open(Kernel::PluginConfiguration::CONF_PATH, File::RDONLY) do |fl| + fl.flock(File::LOCK_SH) + fl.each do |line| + res = line.split("=", 2) + if res.length > 1 + if res[0].strip == module_id.to_s + return "enabled" if res[1].strip == "enabled" + break + end + end + end + end + return "disabled" + when :enable + begin + File.open(Kernel::PluginConfiguration::CONF_PATH, File::RDWR | File::CREAT, 0o600) do |fl| + fl.flock(File::LOCK_EX) + strings = [] + fl.each do |line| + res = line.split("=", 2) + if res.length > 1 + unless res[0].strip == module_id.to_s + strings << line + end + end + end + strings << "#{module_id}=enabled" + fl.truncate(0) + fl.rewind + strings.each { |str| fl.puts(str) } + end + return "enabled" + rescue => e + hestia_print_error_message_to_cli "problem with config file #{e.message} #{e.backtrace.first}" + log_event E_INVALID, $ARGUMENTS + exit(1) + end + when :disable + begin + File.open(Kernel::PluginConfiguration::CONF_PATH, File::RDWR | File::CREAT, 0o600) do |fl| + fl.flock(File::LOCK_EX) + strings = [] + fl.each do |line| + res = line.split("=", 2) + if res.length > 1 + unless res[0].strip == module_id.to_s + strings << line + end + end + end + strings << "#{module_id}=disabled" + fl.truncate(0) + fl.rewind + strings.each { |str| fl.puts(str) } + end + return "disabled" + rescue => e + hestia_print_error_message_to_cli "problem with config file #{e.message} #{e.backtrace.first}" + log_event E_INVALID, $ARGUMENTS + exit(1) + end + else + hestia_print_error_message_to_cli "incorrect module state #{module_id} - #{action.to_s}" + log_event E_INVALID, $ARGUMENTS + exit(1) + end +end diff --git a/func_ruby/update_required_gems.sh b/func_ruby/update_required_gems.sh new file mode 100644 index 0000000..da0c5f2 --- /dev/null +++ b/func_ruby/update_required_gems.sh @@ -0,0 +1,7 @@ +#!/usr/bin/bash + +if [ -e /opt/brepo/ruby33/bin/bundle ]; then + /opt/brepo/ruby33/bin/bundle install +else + bundle install +fi diff --git a/install/hst-install-rhel.sh b/install/hst-install-rhel.sh index 7f4e323..599d343 100755 --- a/install/hst-install-rhel.sh +++ b/install/hst-install-rhel.sh @@ -679,7 +679,8 @@ echo # Installing Nginx repo echo "[ * ] NGINX" -dnf config-manager --add-repo https://dev.brepo.ru/bayrepo/hestiacp/raw/branch/master/install/rpm/nginx/nginx.repo +#dnf config-manager --add-repo https://dev.brepo.ru/bayrepo/hestiacp/raw/branch/master/install/rpm/nginx/nginx.repo +#nginx will be installed from hestia.repo # Installing Remi PHP repo echo "[ * ] PHP" @@ -705,7 +706,6 @@ dnf config-manager --add-repo https://dev.brepo.ru/bayrepo/hestiacp/raw/branch/m rpm --import https://repo.brepo.ru/repo/gpgkeys/repo.brepo.ru.pub check_result $? "rpm import brepo.ru GPG key failed" mkdir /var/cache/hestia-nginx/ -chown admin:admin /var/cache/hestia-nginx/ # Installing PostgreSQL repo if [ "$postgresql" = 'yes' ]; then @@ -1257,6 +1257,7 @@ $HESTIA/bin/v-change-user-shell admin nologin $HESTIA/bin/v-change-user-role admin admin $HESTIA/bin/v-change-user-language admin $lang $HESTIA/bin/v-change-sys-config-value 'POLICY_SYSTEM_PROTECTED_ADMIN' 'yes' +chown admin:admin /var/cache/hestia-nginx/ locale-gen "en_US.utf8" > /dev/null 2>&1 diff --git a/src/rpm/hestia/hestia.spec b/src/rpm/hestia/hestia.spec index bd80bfe..ff6eb00 100644 --- a/src/rpm/hestia/hestia.spec +++ b/src/rpm/hestia/hestia.spec @@ -27,9 +27,17 @@ Requires: zstd Requires: jq Requires: util-linux-user Requires: hestiacp-php-selector +Requires: alt-brepo-ruby33 +Requires: alt-brepo-ruby33-libs +Requires: alt-brepo-ruby33-rubygems +Requires: alt-brepo-ruby33-rubygem-rake +Requires: alt-brepo-ruby33-rubygem-bundler Requires(post): systemd Requires(preun): systemd Requires(postun): systemd +Requires: ruby +Requires: puppet +Requires: puppet-stdlib Provides: hestia = %{version}-%{release} Conflicts: redhat-release < 8 diff --git a/src/rpm/hestia/hestia.tmpfiles b/src/rpm/hestia/hestia.tmpfiles index 93f7e17..ab254f8 100644 --- a/src/rpm/hestia/hestia.tmpfiles +++ b/src/rpm/hestia/hestia.tmpfiles @@ -1 +1 @@ -d /run/hestia 710 root wheel +d /run/hestia 710 admin admin diff --git a/src/rpm/nginx/hestia-nginx.service b/src/rpm/nginx/hestia-nginx.service index 70d159c..9c508f9 100644 --- a/src/rpm/nginx/hestia-nginx.service +++ b/src/rpm/nginx/hestia-nginx.service @@ -7,9 +7,10 @@ After=hestia-php.service [Service] Type=forking PIDFile=/run/hestia/nginx.pid -ExecStartPre=/usr/bin/rm -f /run/nginx.pid +ExecStartPre=/usr/bin/rm -f /run/hestia/nginx.pid ExecStartPre=/usr/local/hestia/nginx/sbin/hestia-nginx -t -c /usr/local/hestia/nginx/conf/nginx.conf ExecStart=/usr/local/hestia/nginx/sbin/hestia-nginx -c /usr/local/hestia/nginx/conf/nginx.conf +ExecStartPost=/bin/bash -c "[ -e /usr/local/hestia/bin/v-oneshot-service ] && /usr/local/hestia/bin/v-oneshot-service" ExecReload=/bin/kill -s HUP $MAINPID KillSignal=SIGQUIT TimeoutStopSec=5 diff --git a/web/edit/extmodules/index.php b/web/edit/extmodules/index.php new file mode 100644 index 0000000..1667010 --- /dev/null +++ b/web/edit/extmodules/index.php @@ -0,0 +1,37 @@ + +
+
+
+ + + +
+
+
+ + +
+ +

+ +
+
+
+
+
+
+
+
+
+ + + $value) { + ++$i; + if ($data[$key]['STATE'] == 'disabled') { + $status = 'disabled'; + $module_action = 'enable'; + $module_action_title = _('Enable module'); + $module_icon = 'fa-play'; + $module_icon_class = 'icon-green'; + $module_confirmation = _('Are you sure you want to enable module %s?') ; + } else { + $status = 'enabled'; + $module_action = 'disable'; + $module_action_title = _('Disable module'); + $module_icon = 'fa-stop'; + $module_icon_class = 'icon-red'; + $module_confirmation = _('Are you sure you want to disable module %s?') ; + } + ?> +
+
+ : + +
+
+ : + + "> +
+ +
+ : + +
+
+ : + +
+
+ : + +
+
+ +
+ +
+ +
+ +
diff --git a/web/templates/pages/list_services.php b/web/templates/pages/list_services.php index 333ab7b..bb35667 100644 --- a/web/templates/pages/list_services.php +++ b/web/templates/pages/list_services.php @@ -27,6 +27,9 @@ > + + +