deploy
Signed-off-by: Jeff <jeff@gotenzing.com>
Showing
1000 changed files
with
4197 additions
and
13 deletions
Too many changes to show.
To preserve performance only 1000 of 1000+ files are displayed.
.bundle/config
0 → 100644
Capfile
100755 → 100644
File mode changed
Gemfile
100755 → 100644
Gemfile.lock
100755 → 100644
| 1 | GEM | 1 | GEM |
| 2 | remote: https://rubygems.org/ | 2 | remote: https://rubygems.org/ |
| 3 | specs: | 3 | specs: |
| 4 | capistrano (3.4.0) | 4 | airbrussh (1.4.1) |
| 5 | sshkit (>= 1.6.1, != 1.7.0) | ||
| 6 | capistrano (3.17.1) | ||
| 7 | airbrussh (>= 1.0.0) | ||
| 5 | i18n | 8 | i18n |
| 6 | rake (>= 10.0.0) | 9 | rake (>= 10.0.0) |
| 7 | sshkit (~> 1.3) | 10 | sshkit (>= 1.9.0) |
| 8 | capistrano-composer (0.0.6) | 11 | capistrano-composer (0.0.6) |
| 9 | capistrano (>= 3.0.0.pre) | 12 | capistrano (>= 3.0.0.pre) |
| 10 | i18n (0.7.0) | 13 | concurrent-ruby (1.1.10) |
| 14 | i18n (1.12.0) | ||
| 15 | concurrent-ruby (~> 1.0) | ||
| 11 | net-scp (1.2.1) | 16 | net-scp (1.2.1) |
| 12 | net-ssh (>= 2.6.5) | 17 | net-ssh (>= 2.6.5) |
| 13 | net-ssh (3.0.2) | 18 | net-ssh (7.0.1) |
| 14 | rake (10.5.0) | 19 | rake (13.0.6) |
| 15 | sshkit (1.8.1) | 20 | sshkit (1.21.2) |
| 16 | net-scp (>= 1.1.2) | 21 | net-scp (>= 1.1.2) |
| 17 | net-ssh (>= 2.8.0) | 22 | net-ssh (>= 2.8.0) |
| 18 | 23 | ||
| 19 | PLATFORMS | 24 | PLATFORMS |
| 20 | ruby | 25 | x86_64-darwin-21 |
| 26 | x86_64-darwin-22 | ||
| 21 | 27 | ||
| 22 | DEPENDENCIES | 28 | DEPENDENCIES |
| 23 | capistrano (~> 3.4.0) | 29 | capistrano (~> 3.10) |
| 24 | capistrano-composer | 30 | capistrano-composer |
| 31 | |||
| 32 | BUNDLED WITH | ||
| 33 | 2.3.21 | ... | ... |
| 1 | set :application, 'tenzing-web-2023' | 1 | set :application, 'tenzing-web-2019-staging' |
| 2 | set :repo_url, 'git@git.gotenzing.com:tenzing/Tenzing-Web-2023.git' | 2 | set :repo_url, 'git@git.gotenzing.com:tenzing/Tenzing-Web-2023.git' |
| 3 | 3 | ||
| 4 | # Branch options | 4 | # Branch options |
| ... | @@ -33,7 +33,7 @@ namespace :deploy do | ... | @@ -33,7 +33,7 @@ namespace :deploy do |
| 33 | desc 'Install composer packages' | 33 | desc 'Install composer packages' |
| 34 | task :install_composer_packages do | 34 | task :install_composer_packages do |
| 35 | on roles(:web), in: :sequence, wait: 5 do | 35 | on roles(:web), in: :sequence, wait: 5 do |
| 36 | execute("cd '#{release_path}'; composer install --no-dev --prefer-dist --no-interaction --quiet --optimize-autoloader") | 36 | execute("cd '#{release_path}'; composer update --no-dev --prefer-dist --no-interaction --quiet --optimize-autoloader") |
| 37 | end | 37 | end |
| 38 | end | 38 | end |
| 39 | end | 39 | end | ... | ... |
log/capistrano.log
0 → 100644
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/bin/bundle
0 → 100755
| 1 | #!/usr/bin/env ruby | ||
| 2 | # | ||
| 3 | # This file was generated by RubyGems. | ||
| 4 | # | ||
| 5 | # The application 'bundler' is installed as part of a gem, and | ||
| 6 | # this file is here to facilitate running it. | ||
| 7 | # | ||
| 8 | |||
| 9 | require 'rubygems' | ||
| 10 | |||
| 11 | version = ">= 0.a" | ||
| 12 | |||
| 13 | str = ARGV.first | ||
| 14 | if str | ||
| 15 | str = str.b[/\A_(.*)_\z/, 1] | ||
| 16 | if str and Gem::Version.correct?(str) | ||
| 17 | version = str | ||
| 18 | ENV['BUNDLER_VERSION'] = str | ||
| 19 | |||
| 20 | ARGV.shift | ||
| 21 | end | ||
| 22 | end | ||
| 23 | |||
| 24 | if Gem.respond_to?(:activate_bin_path) | ||
| 25 | load Gem.activate_bin_path('bundler', 'bundle', version) | ||
| 26 | else | ||
| 27 | gem "bundler", version | ||
| 28 | load Gem.bin_path("bundler", "bundle", version) | ||
| 29 | end |
vendor/bundle/ruby/3.2.0/bin/bundler
0 → 100755
| 1 | #!/usr/bin/env ruby | ||
| 2 | # | ||
| 3 | # This file was generated by RubyGems. | ||
| 4 | # | ||
| 5 | # The application 'bundler' is installed as part of a gem, and | ||
| 6 | # this file is here to facilitate running it. | ||
| 7 | # | ||
| 8 | |||
| 9 | require 'rubygems' | ||
| 10 | |||
| 11 | version = ">= 0.a" | ||
| 12 | |||
| 13 | str = ARGV.first | ||
| 14 | if str | ||
| 15 | str = str.b[/\A_(.*)_\z/, 1] | ||
| 16 | if str and Gem::Version.correct?(str) | ||
| 17 | version = str | ||
| 18 | ENV['BUNDLER_VERSION'] = str | ||
| 19 | |||
| 20 | ARGV.shift | ||
| 21 | end | ||
| 22 | end | ||
| 23 | |||
| 24 | if Gem.respond_to?(:activate_bin_path) | ||
| 25 | load Gem.activate_bin_path('bundler', 'bundler', version) | ||
| 26 | else | ||
| 27 | gem "bundler", version | ||
| 28 | load Gem.bin_path("bundler", "bundler", version) | ||
| 29 | end |
vendor/bundle/ruby/3.2.0/bin/cap
0 → 100755
| 1 | #!/usr/bin/env ruby | ||
| 2 | # | ||
| 3 | # This file was generated by RubyGems. | ||
| 4 | # | ||
| 5 | # The application 'capistrano' is installed as part of a gem, and | ||
| 6 | # this file is here to facilitate running it. | ||
| 7 | # | ||
| 8 | |||
| 9 | require 'rubygems' | ||
| 10 | |||
| 11 | Gem.use_gemdeps | ||
| 12 | |||
| 13 | version = ">= 0.a" | ||
| 14 | |||
| 15 | str = ARGV.first | ||
| 16 | if str | ||
| 17 | str = str.b[/\A_(.*)_\z/, 1] | ||
| 18 | if str and Gem::Version.correct?(str) | ||
| 19 | version = str | ||
| 20 | ARGV.shift | ||
| 21 | end | ||
| 22 | end | ||
| 23 | |||
| 24 | if Gem.respond_to?(:activate_bin_path) | ||
| 25 | load Gem.activate_bin_path('capistrano', 'cap', version) | ||
| 26 | else | ||
| 27 | gem "capistrano", version | ||
| 28 | load Gem.bin_path("capistrano", "cap", version) | ||
| 29 | end |
vendor/bundle/ruby/3.2.0/bin/capify
0 → 100755
| 1 | #!/usr/bin/env ruby | ||
| 2 | # | ||
| 3 | # This file was generated by RubyGems. | ||
| 4 | # | ||
| 5 | # The application 'capistrano' is installed as part of a gem, and | ||
| 6 | # this file is here to facilitate running it. | ||
| 7 | # | ||
| 8 | |||
| 9 | require 'rubygems' | ||
| 10 | |||
| 11 | Gem.use_gemdeps | ||
| 12 | |||
| 13 | version = ">= 0.a" | ||
| 14 | |||
| 15 | str = ARGV.first | ||
| 16 | if str | ||
| 17 | str = str.b[/\A_(.*)_\z/, 1] | ||
| 18 | if str and Gem::Version.correct?(str) | ||
| 19 | version = str | ||
| 20 | ARGV.shift | ||
| 21 | end | ||
| 22 | end | ||
| 23 | |||
| 24 | if Gem.respond_to?(:activate_bin_path) | ||
| 25 | load Gem.activate_bin_path('capistrano', 'capify', version) | ||
| 26 | else | ||
| 27 | gem "capistrano", version | ||
| 28 | load Gem.bin_path("capistrano", "capify", version) | ||
| 29 | end |
vendor/bundle/ruby/3.2.0/bin/rake
0 → 100755
| 1 | #!/usr/bin/env ruby | ||
| 2 | # | ||
| 3 | # This file was generated by RubyGems. | ||
| 4 | # | ||
| 5 | # The application 'rake' is installed as part of a gem, and | ||
| 6 | # this file is here to facilitate running it. | ||
| 7 | # | ||
| 8 | |||
| 9 | require 'rubygems' | ||
| 10 | |||
| 11 | Gem.use_gemdeps | ||
| 12 | |||
| 13 | version = ">= 0.a" | ||
| 14 | |||
| 15 | str = ARGV.first | ||
| 16 | if str | ||
| 17 | str = str.b[/\A_(.*)_\z/, 1] | ||
| 18 | if str and Gem::Version.correct?(str) | ||
| 19 | version = str | ||
| 20 | ARGV.shift | ||
| 21 | end | ||
| 22 | end | ||
| 23 | |||
| 24 | if Gem.respond_to?(:activate_bin_path) | ||
| 25 | load Gem.activate_bin_path('rake', 'rake', version) | ||
| 26 | else | ||
| 27 | gem "rake", version | ||
| 28 | load Gem.bin_path("rake", "rake", version) | ||
| 29 | end |
No preview for this file type
No preview for this file type
No preview for this file type
No preview for this file type
No preview for this file type
No preview for this file type
No preview for this file type
No preview for this file type
No preview for this file type
No preview for this file type
No preview for this file type
No preview for this file type
No preview for this file type
No preview for this file type
No preview for this file type
| 1 | version: 2.1 | ||
| 2 | |||
| 3 | executors: | ||
| 4 | ruby: | ||
| 5 | parameters: | ||
| 6 | version: | ||
| 7 | description: "Ruby version number" | ||
| 8 | default: "3.1" | ||
| 9 | type: string | ||
| 10 | docker: | ||
| 11 | - image: ruby:<< parameters.version >> | ||
| 12 | |||
| 13 | commands: | ||
| 14 | bundle_install: | ||
| 15 | description: Install Ruby dependencies with Bundler | ||
| 16 | parameters: | ||
| 17 | key: | ||
| 18 | description: "Cache key" | ||
| 19 | default: "3.1" | ||
| 20 | type: string | ||
| 21 | steps: | ||
| 22 | - restore_cache: | ||
| 23 | keys: | ||
| 24 | - bundle-v1-{{ arch }}-<< parameters.key >> | ||
| 25 | - run: | ||
| 26 | name: Install Ruby Dependencies | ||
| 27 | command: | | ||
| 28 | gem install bundler --conservative --no-document || \ | ||
| 29 | gem install rubygems-update -v '<3' && update_rubygems && gem install bundler -v '<2' --no-document | ||
| 30 | bundle config --local path vendor/bundle | ||
| 31 | bundle check || (bundle install --jobs=4 --retry=3 && bundle clean) | ||
| 32 | - save_cache: | ||
| 33 | paths: | ||
| 34 | - ./vendor/bundle | ||
| 35 | key: bundle-v1-{{ arch }}-<< parameters.key >>-{{ checksum "Gemfile.lock" }} | ||
| 36 | |||
| 37 | jobs: | ||
| 38 | rubocop: | ||
| 39 | executor: | ||
| 40 | name: ruby | ||
| 41 | version: "2.7" | ||
| 42 | steps: | ||
| 43 | - checkout | ||
| 44 | - bundle_install: | ||
| 45 | key: "2.7" | ||
| 46 | - run: bundle exec rubocop | ||
| 47 | spec: | ||
| 48 | parameters: | ||
| 49 | ruby: | ||
| 50 | description: "Ruby version number" | ||
| 51 | default: "3.1" | ||
| 52 | type: string | ||
| 53 | executor: | ||
| 54 | name: ruby | ||
| 55 | version: << parameters.ruby >> | ||
| 56 | steps: | ||
| 57 | - checkout | ||
| 58 | - run: echo sshkit=master >> $BASH_ENV | ||
| 59 | - bundle_install: | ||
| 60 | key: << parameters.ruby >> | ||
| 61 | - run: bundle exec rake test | ||
| 62 | spec_legacy_ruby: | ||
| 63 | parameters: | ||
| 64 | ruby: | ||
| 65 | description: "Ruby version number" | ||
| 66 | default: "1.9" | ||
| 67 | type: string | ||
| 68 | sshkit: | ||
| 69 | description: "sshkit version number" | ||
| 70 | default: "1.6.1" | ||
| 71 | type: string | ||
| 72 | executor: | ||
| 73 | name: ruby | ||
| 74 | version: << parameters.ruby >> | ||
| 75 | steps: | ||
| 76 | - checkout | ||
| 77 | - run: | | ||
| 78 | echo "export sshkit=<< parameters.sshkit >>" >> $BASH_ENV | ||
| 79 | if [ "<< parameters.ruby >>" == "1.9" ]; then | ||
| 80 | echo "export RUBYOPT=-Ku" >> $BASH_ENV | ||
| 81 | fi | ||
| 82 | - bundle_install: | ||
| 83 | key: << parameters.ruby >>-<< parameters.sshkit >> | ||
| 84 | - run: bundle exec rake test | ||
| 85 | |||
| 86 | workflows: | ||
| 87 | version: 2 | ||
| 88 | commit-workflow: | ||
| 89 | jobs: | ||
| 90 | - rubocop | ||
| 91 | - spec: | ||
| 92 | matrix: &matrix | ||
| 93 | parameters: | ||
| 94 | ruby: | ||
| 95 | - "2.4" | ||
| 96 | - "2.5" | ||
| 97 | - "2.6" | ||
| 98 | - "2.7" | ||
| 99 | - "3.0" | ||
| 100 | - "3.1" | ||
| 101 | - spec_legacy_ruby: | ||
| 102 | matrix: &legacy_ruby_matrix | ||
| 103 | parameters: | ||
| 104 | ruby: | ||
| 105 | - "1.9" | ||
| 106 | - "2.0" | ||
| 107 | - "2.1" | ||
| 108 | - "2.2" | ||
| 109 | - "2.3" | ||
| 110 | sshkit: | ||
| 111 | - "1.6.1" | ||
| 112 | - "1.7.1" | ||
| 113 | - master | ||
| 114 | exclude: | ||
| 115 | - ruby: "1.9" | ||
| 116 | sshkit: master | ||
| 117 | cron-workflow: | ||
| 118 | jobs: | ||
| 119 | - rubocop | ||
| 120 | - spec: | ||
| 121 | matrix: | ||
| 122 | <<: *matrix | ||
| 123 | - spec_legacy_ruby: | ||
| 124 | matrix: | ||
| 125 | <<: *legacy_ruby_matrix | ||
| 126 | triggers: | ||
| 127 | - schedule: | ||
| 128 | cron: "0 13 * * 6" | ||
| 129 | filters: | ||
| 130 | branches: | ||
| 131 | only: | ||
| 132 | - main |
| 1 | name-template: "$RESOLVED_VERSION" | ||
| 2 | tag-template: "v$RESOLVED_VERSION" | ||
| 3 | categories: | ||
| 4 | - title: "⚠️ Breaking Changes" | ||
| 5 | label: "⚠️ Breaking" | ||
| 6 | - title: "✨ New Features" | ||
| 7 | label: "✨ Feature" | ||
| 8 | - title: "🐛 Bug Fixes" | ||
| 9 | label: "🐛 Bug Fix" | ||
| 10 | - title: "📚 Documentation" | ||
| 11 | label: "📚 Docs" | ||
| 12 | - title: "🏠 Housekeeping" | ||
| 13 | label: "🏠 Housekeeping" | ||
| 14 | version-resolver: | ||
| 15 | minor: | ||
| 16 | labels: | ||
| 17 | - "⚠️ Breaking" | ||
| 18 | - "✨ Feature" | ||
| 19 | default: patch | ||
| 20 | change-template: "- $TITLE (#$NUMBER) @$AUTHOR" | ||
| 21 | no-changes-template: "- No changes" | ||
| 22 | template: | | ||
| 23 | $CHANGES | ||
| 24 | |||
| 25 | **Full Changelog:** https://github.com/$OWNER/$REPOSITORY/compare/$PREVIOUS_TAG...v$RESOLVED_VERSION |
| 1 | AllCops: | ||
| 2 | DisplayCopNames: true | ||
| 3 | DisplayStyleGuide: true | ||
| 4 | TargetRubyVersion: 1.9 | ||
| 5 | Exclude: | ||
| 6 | - "*.gemspec" | ||
| 7 | - "vendor/**/*" | ||
| 8 | |||
| 9 | Layout/EndOfLine: | ||
| 10 | Enabled: false | ||
| 11 | |||
| 12 | Layout/SpaceAroundEqualsInParameterDefault: | ||
| 13 | EnforcedStyle: no_space | ||
| 14 | |||
| 15 | Metrics/AbcSize: | ||
| 16 | Exclude: | ||
| 17 | - "test/**/*" | ||
| 18 | |||
| 19 | Metrics/MethodLength: | ||
| 20 | Exclude: | ||
| 21 | - "test/**/*" | ||
| 22 | |||
| 23 | Metrics/ClassLength: | ||
| 24 | Exclude: | ||
| 25 | - "test/**/*" | ||
| 26 | |||
| 27 | Style/BarePercentLiterals: | ||
| 28 | EnforcedStyle: percent_q | ||
| 29 | |||
| 30 | Style/ClassAndModuleChildren: | ||
| 31 | Enabled: false | ||
| 32 | |||
| 33 | Style/Documentation: | ||
| 34 | Enabled: false | ||
| 35 | |||
| 36 | Style/DoubleNegation: | ||
| 37 | Enabled: false | ||
| 38 | |||
| 39 | Style/Encoding: | ||
| 40 | Enabled: false | ||
| 41 | |||
| 42 | Style/HashSyntax: | ||
| 43 | EnforcedStyle: hash_rockets | ||
| 44 | |||
| 45 | Style/StringLiterals: | ||
| 46 | EnforcedStyle: double_quotes | ||
| 47 | |||
| 48 | Style/TrivialAccessors: | ||
| 49 | AllowPredicates: true |
| 1 | Release notes for this project are kept here: https://github.com/mattbrictson/airbrussh/releases |
| 1 | Contributor Code of Conduct | ||
| 2 | |||
| 3 | As contributors and maintainers of this project, we pledge to respect all | ||
| 4 | people who contribute through reporting issues, posting feature requests, | ||
| 5 | updating documentation, submitting pull requests or patches, and other | ||
| 6 | activities. | ||
| 7 | |||
| 8 | We are committed to making participation in this project a harassment-free | ||
| 9 | experience for everyone, regardless of level of experience, gender, gender | ||
| 10 | identity and expression, sexual orientation, disability, personal appearance, | ||
| 11 | body size, race, ethnicity, age, or religion. | ||
| 12 | |||
| 13 | Examples of unacceptable behavior by participants include the use of sexual | ||
| 14 | language or imagery, derogatory comments or personal attacks, trolling, public | ||
| 15 | or private harassment, insults, or other unprofessional conduct. | ||
| 16 | |||
| 17 | Project maintainers have the right and responsibility to remove, edit, or | ||
| 18 | reject comments, commits, code, wiki edits, issues, and other contributions | ||
| 19 | that are not aligned to this Code of Conduct. Project maintainers who do not | ||
| 20 | follow the Code of Conduct may be removed from the project team. | ||
| 21 | |||
| 22 | This code of conduct applies both within project spaces and in public spaces | ||
| 23 | when an individual is representing the project or its community. | ||
| 24 | |||
| 25 | Instances of abusive, harassing, or otherwise unacceptable behavior may be | ||
| 26 | reported by opening an issue or contacting one or more of the project | ||
| 27 | maintainers. | ||
| 28 | |||
| 29 | This Code of Conduct is adapted from the Contributor Covenant | ||
| 30 | (http://contributor-covenant.org), version 1.1.0, available at | ||
| 31 | http://contributor-covenant.org/version/1/1/0/ |
| 1 | # Contributing to airbrussh | ||
| 2 | |||
| 3 | Have a feature idea, bug fix, or refactoring suggestion? Contributions are welcome! | ||
| 4 | |||
| 5 | ## Pull requests | ||
| 6 | |||
| 7 | 1. Check [Issues][] to see if your contribution has already been discussed and/or implemented. | ||
| 8 | 2. If not, open an issue to discuss your contribution. I won't accept all changes and do not want to waste your time. | ||
| 9 | 3. Once you have the :thumbsup:, fork the repo, make your changes, and open a PR. | ||
| 10 | |||
| 11 | ## Coding guidelines | ||
| 12 | |||
| 13 | * This project has a coding style enforced by [RuboCop][]. Use hash rockets and double-quoted strings, and otherwise try to follow the [Ruby style guide][style]. | ||
| 14 | * Writing tests is strongly encouraged! This project uses Minitest. | ||
| 15 | |||
| 16 | ## Getting started | ||
| 17 | |||
| 18 | Note that Bundler 1.10 is required for development. Run `gem update bundler` to get the latest version. | ||
| 19 | |||
| 20 | After checking out the airbrussh repo, run `bin/setup` to install dependencies. Run `rake` to execute airbrussh's tests and RuboCop checks. | ||
| 21 | |||
| 22 | Airbrussh is designed to work against multiple versions of SSHKit and Ruby. In order to test this, we use the environment variable `sshkit` in order to run the tests against a specific version. The combinations of sshkit and ruby we support are specified in [.circleci/config.yml](.circleci/config.yml). | ||
| 23 | |||
| 24 | A Guardfile is also present, so if you'd like to use Guard to do a TDD workflow, then: | ||
| 25 | |||
| 26 | 1. Run `bundle install --with extras` to get the optional guard dependencies | ||
| 27 | 2. Run `guard` to monitor the filesystem and automatically run tests as you work | ||
| 28 | |||
| 29 | [Issues]: https://github.com/mattbrictson/airbrussh/issues | ||
| 30 | [RuboCop]: https://github.com/bbatsov/rubocop | ||
| 31 | [style]: https://github.com/bbatsov/ruby-style-guide |
| 1 | source "https://rubygems.org" | ||
| 2 | |||
| 3 | # Specify your gem's dependencies in airbrussh.gemspec | ||
| 4 | gemspec | ||
| 5 | |||
| 6 | if RUBY_VERSION == "1.9.3" | ||
| 7 | # These gems need specific version for Ruby 1.9 | ||
| 8 | gem "json", "~> 1.8" | ||
| 9 | gem "minitest", "~> 5.11.3" | ||
| 10 | gem "net-ssh", "~> 2.8" | ||
| 11 | gem "rake", "< 12.3" | ||
| 12 | gem "term-ansicolor", "~> 1.3.2" | ||
| 13 | gem "tins", "~> 1.6.0" | ||
| 14 | end | ||
| 15 | |||
| 16 | if RUBY_VERSION >= "2.5" | ||
| 17 | # These gems need at least Ruby 2.5 | ||
| 18 | gem "coveralls_reborn", "~> 0.24.0" | ||
| 19 | end | ||
| 20 | |||
| 21 | if RUBY_VERSION >= "2.1" | ||
| 22 | # These gems need at least Ruby 2.1 | ||
| 23 | gem "rubocop", "0.50.0" | ||
| 24 | |||
| 25 | # Optional development dependencies; requires bundler >= 1.10. | ||
| 26 | # Note that these gems assume a Ruby 2.2 environment. Install them using: | ||
| 27 | # | ||
| 28 | # bundle install --with extras | ||
| 29 | # | ||
| 30 | group :extras, :optional => true do | ||
| 31 | gem "guard", ">= 2.2.2" | ||
| 32 | gem "guard-minitest" | ||
| 33 | gem "rb-fsevent" | ||
| 34 | gem "terminal-notifier-guard" | ||
| 35 | end | ||
| 36 | end | ||
| 37 | |||
| 38 | if (sshkit_version = ENV["sshkit"]) | ||
| 39 | requirement = begin | ||
| 40 | Gem::Dependency.new("sshkit", sshkit_version).requirement | ||
| 41 | rescue ArgumentError | ||
| 42 | user, branch = | ||
| 43 | if sshkit_version.include?("#") | ||
| 44 | sshkit_version.split("#") | ||
| 45 | else | ||
| 46 | ["capistrano", sshkit_version] | ||
| 47 | end | ||
| 48 | { :git => "https://github.com/#{user}/sshkit.git", :branch => branch } | ||
| 49 | end | ||
| 50 | gem "sshkit", requirement | ||
| 51 | end |
| 1 | The MIT License (MIT) | ||
| 2 | |||
| 3 | Copyright (c) 2020 Matt Brictson | ||
| 4 | |||
| 5 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 6 | of this software and associated documentation files (the "Software"), to deal | ||
| 7 | in the Software without restriction, including without limitation the rights | ||
| 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 9 | copies of the Software, and to permit persons to whom the Software is | ||
| 10 | furnished to do so, subject to the following conditions: | ||
| 11 | |||
| 12 | The above copyright notice and this permission notice shall be included in | ||
| 13 | all copies or substantial portions of the Software. | ||
| 14 | |||
| 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
| 21 | THE SOFTWARE. |
| 1 | # Airbrussh | ||
| 2 | |||
| 3 | [](http://badge.fury.io/rb/airbrussh) | ||
| 4 | [](https://app.circleci.com/pipelines/github/mattbrictson/airbrussh?branch=main) | ||
| 5 | [](https://ci.appveyor.com/project/mattbrictson/airbrussh/branch/main) | ||
| 6 | [](https://codeclimate.com/github/mattbrictson/airbrussh) | ||
| 7 | [](https://coveralls.io/r/mattbrictson/airbrussh?branch=main) | ||
| 8 | |||
| 9 | |||
| 10 | Airbrussh is a concise log formatter for Capistrano and SSHKit. It displays well-formatted, useful log output that is easy to read. Airbrussh also saves Capistrano's verbose output to a separate log file just in case you need additional details for troubleshooting. | ||
| 11 | |||
| 12 | **As of April 2016, Airbrussh is bundled with Capistrano 3.5, and is Capistrano's default formatter! There is nothing additional to install or enable.** Continue reading to learn more about Airbrussh's features and configuration options. | ||
| 13 | |||
| 14 | If you aren't yet using Capistrano 3.5 (or wish to use Airbrussh with SSHKit directly), refer to the [advanced/legacy usage](#advancedlegacy-usage) section for installation instructions. | ||
| 15 | |||
| 16 |  | ||
| 17 | |||
| 18 | For more details on how exactly Airbrussh affects Capistrano's output and the reasoning behind it, check out the blog post: [Introducing Airbrussh](https://mattbrictson.com/airbrussh). | ||
| 19 | |||
| 20 | ----- | ||
| 21 | |||
| 22 | * [Usage](#usage) | ||
| 23 | * [Configuration](#configuration) | ||
| 24 | * [FAQ](#faq) | ||
| 25 | * [Advanced/legacy usage](#advancedlegacy-usage) | ||
| 26 | |||
| 27 | ## Usage | ||
| 28 | |||
| 29 | Airbrussh is enabled by default in Capistrano 3.5 and newer. To manually enable Airbrussh (for example, when upgrading an existing project), set the Capistrano format like this: | ||
| 30 | |||
| 31 | ```ruby | ||
| 32 | # In deploy.rb | ||
| 33 | set :format, :airbrussh | ||
| 34 | ``` | ||
| 35 | |||
| 36 | ### What's displayed | ||
| 37 | |||
| 38 | When you run a Capistrano command, Airbrussh provides the following information in its output: | ||
| 39 | |||
| 40 |  | ||
| 41 | |||
| 42 | * Name of Capistrano task being executed | ||
| 43 | * When each task started (minutes:seconds elapsed since the deploy began) | ||
| 44 | * The SSH command-line strings that are executed; for Capistrano tasks that involve running multiple commands, the numeric prefix indicates the command in the sequence, starting from `01` | ||
| 45 | * Stdout and stderr output from each command | ||
| 46 | * The duration of each command execution, per server | ||
| 47 | |||
| 48 | ### What's *not* displayed | ||
| 49 | |||
| 50 | For brevity, Airbrussh does not show *everything* that Capistrano is doing. For example, it will omit Capistrano's `test` commands, which can be noisy and confusing. Airbrussh also hides things like environment variables, as well as `cd` and `env` invocations. To see a full audit of Capistrano's execution, including *exactly* what commands were run on each server, look at `log/capistrano.log`. | ||
| 51 | |||
| 52 | ## Configuration | ||
| 53 | |||
| 54 | You can customize many aspects of Airbrussh's output. In Capistrano 3.5 and newer, this is done via the `:format_options` variable, like this: | ||
| 55 | |||
| 56 | ```ruby | ||
| 57 | # Pass options to Airbrussh | ||
| 58 | set :format_options, color: false, truncate: 80 | ||
| 59 | ``` | ||
| 60 | |||
| 61 | Here are the options you can use, and their effects (note that the defaults may be different depending on where Airbrussh is used; these are the defaults used by Capistrano 3.5): | ||
| 62 | |||
| 63 | |Option|Default|Usage| | ||
| 64 | |---|---|---| | ||
| 65 | |`banner`|`nil`|Provide a string (e.g. "Capistrano started!") that will be printed when Capistrano starts up.| | ||
| 66 | |`color`|`:auto`|Use `true` or `false` to enable or disable ansi color. If set to `:auto`, Airbrussh automatically uses color based on whether the output is a TTY, or if the SSHKIT_COLOR environment variable is set.| | ||
| 67 | |`command_output`|`true`|Set to `:stdout`, `:stderr`, or `true` to display the SSH output received via stdout, stderr, or both, respectively. Set to `false` to not show any SSH output, for a minimal look.| | ||
| 68 | |`context`|`Airbrussh::Rake::Context`|Defines the execution context. Targeted towards uses of Airbrussh outside of Rake/Capistrano. Alternate implementations should provide the definition for `current_task_name`, `register_new_command`, and `position`.| | ||
| 69 | |`log_file`|`log/capistrano.log`|Capistrano's verbose output is saved to this file to facilitate debugging. Set to `nil` to disable completely.| | ||
| 70 | |`truncate`|`:auto`|Set to a number (e.g. 80) to truncate the width of the output to that many characters, or `false` to disable truncation. If `:auto`, output is automatically truncated to the width of the terminal window, if it can be determined.| | ||
| 71 | |`task_prefix`|`nil`|A string to prefix to task output. Handy for output collapsing like [buildkite](https://buildkite.com/docs/builds/managing-log-output)'s `---` prefix| | ||
| 72 | |||
| 73 | ## FAQ | ||
| 74 | |||
| 75 | **Airbrussh is not displaying the output of my commands! For example, I run `tail` in one of my capistrano tasks and airbrussh doesn't show anything. How do I fix this?** | ||
| 76 | |||
| 77 | Make sure Airbrussh is configured to show SSH output. | ||
| 78 | |||
| 79 | ```ruby | ||
| 80 | set :format_options, command_output: true | ||
| 81 | ``` | ||
| 82 | |||
| 83 | **I haven't upgraded to Capistrano 3.5 yet. Can I still use Airbrussh?** | ||
| 84 | |||
| 85 | Yes! Capistrano 3.4.x is also supported. Refer to the [advanced/legacy usage](#advancedlegacy-usage) section for installation instructions. | ||
| 86 | |||
| 87 | **Does Airbrussh work with Capistrano 2?** | ||
| 88 | |||
| 89 | No, Capistrano 3 is required. We recommend Capistrano 3.4.0 or higher. Capistrano 3.5.0 and higher have Airbrussh enabled by default, with no installation needed. | ||
| 90 | |||
| 91 | **Does Airbrussh work with JRuby?** | ||
| 92 | |||
| 93 | JRuby is not officially supported or tested, but may work. You must disable automatic truncation to work around a known bug in the JRuby 9.0 standard library. See [#62](https://github.com/mattbrictson/airbrussh/issues/62) for more details. | ||
| 94 | |||
| 95 | ```ruby | ||
| 96 | set :format_options, truncate: false | ||
| 97 | ``` | ||
| 98 | |||
| 99 | **I have a question that’s not answered here or elsewhere in the README.** | ||
| 100 | |||
| 101 | Please [open a GitHub issue](https://github.com/mattbrictson/airbrussh/issues/new) and we’ll be happy to help! | ||
| 102 | |||
| 103 | ## Advanced/legacy usage | ||
| 104 | |||
| 105 | Although Airbrussh is built into Capistrano 3.5.0 and higher, it is also available as a plug-in for older versions. Airbrussh has been tested with MRI 1.9+, Capistrano 3.4.0+, and SSHKit 1.6.1+. | ||
| 106 | |||
| 107 | ### Capistrano 3.4.x | ||
| 108 | |||
| 109 | Add this line to your application's Gemfile: | ||
| 110 | |||
| 111 | ```ruby | ||
| 112 | gem "airbrussh", require: false | ||
| 113 | ``` | ||
| 114 | |||
| 115 | And then execute: | ||
| 116 | |||
| 117 | $ bundle | ||
| 118 | |||
| 119 | Finally, add this line to your application's Capfile: | ||
| 120 | |||
| 121 | ```ruby | ||
| 122 | require "airbrussh/capistrano" | ||
| 123 | ``` | ||
| 124 | |||
| 125 | **Important:** explicitly setting Capistrano's `:format` option in your deploy.rb will override airbrussh. Remove this line if you have it: | ||
| 126 | |||
| 127 | ```ruby | ||
| 128 | # Remove this | ||
| 129 | set :format, :pretty | ||
| 130 | ``` | ||
| 131 | |||
| 132 | Capistrano 3.4.x doesn't have the `:format_options` configuration system, so you will need to configure Airbrussh using this technique: | ||
| 133 | |||
| 134 | ```ruby | ||
| 135 | Airbrussh.configure do |config| | ||
| 136 | config.color = false | ||
| 137 | config.command_output = true | ||
| 138 | # etc. | ||
| 139 | end | ||
| 140 | ``` | ||
| 141 | |||
| 142 | Refer to the [configuration](#configuration) section above for the list of supported options. | ||
| 143 | |||
| 144 | ### SSHKit | ||
| 145 | |||
| 146 | If you are using SSHKit directly (i.e. without Capistrano), you can use Airbrussh like this: | ||
| 147 | |||
| 148 | ```ruby | ||
| 149 | require "airbrussh" | ||
| 150 | SSHKit.config.output = Airbrussh::Formatter.new($stdout) | ||
| 151 | |||
| 152 | # You can also pass configuration options like this | ||
| 153 | SSHKit.config.output = Airbrussh::Formatter.new($stdout, color: false) | ||
| 154 | ``` | ||
| 155 | |||
| 156 | ## History | ||
| 157 | |||
| 158 | Airbrussh started life as custom logging code within the [capistrano-mb][] collection of opinionated Capistrano recipes. In February 2015, the logging code was refactored into a standalone gem with its own configuration and documentation, and renamed `airbrussh`. In February 2016, Airbrussh was added as the default formatter in Capistrano 3.5.0. | ||
| 159 | |||
| 160 | ## Roadmap | ||
| 161 | |||
| 162 | Airbrussh now has a stable feature set, excellent test coverage, is being used for production deployments, and has reached 1.0.0! If you have ideas for improvements to Airbrussh, please open a [GitHub issue](https://github.com/mattbrictson/airbrussh/issues/new). | ||
| 163 | |||
| 164 | ## Contributing | ||
| 165 | |||
| 166 | Contributions are welcome! Read [CONTRIBUTING.md](CONTRIBUTING.md) to get started. | ||
| 167 | |||
| 168 | [capistrano-mb]: https://github.com/mattbrictson/capistrano-mb |
| 1 | require "bundler/gem_tasks" | ||
| 2 | |||
| 3 | require "rake/testtask" | ||
| 4 | Rake::TestTask.new(:test) do |t| | ||
| 5 | t.libs << "test" | ||
| 6 | t.libs << "lib" | ||
| 7 | t.test_files = FileList["test/**/*_test.rb"] | ||
| 8 | end | ||
| 9 | |||
| 10 | begin | ||
| 11 | require "rubocop/rake_task" | ||
| 12 | RuboCop::RakeTask.new | ||
| 13 | task :default => [:test, :rubocop] | ||
| 14 | rescue LoadError | ||
| 15 | task :default => :test | ||
| 16 | end | ||
| 17 | |||
| 18 | Rake::Task["release"].enhance do | ||
| 19 | puts "Don't forget to publish the release on GitHub!" | ||
| 20 | system "open https://github.com/mattbrictson/airbrussh/releases" | ||
| 21 | end |
| 1 | # Capistrano 3.5 upgrade guide for existing Airbrussh users | ||
| 2 | |||
| 3 | If you have been using Airbrussh with Capistrano, and are upgrading to Capistrano 3.5, then this guide is for you. | ||
| 4 | |||
| 5 | ## What changed? | ||
| 6 | |||
| 7 | * Airbrussh is built into Capistrano starting with Capistrano 3.5.0, and is enabled by default. | ||
| 8 | * Capistrano 3.5 initializes Airbrussh with a default configuration that is different than Airbrussh+Capistrano 3.4.0. | ||
| 9 | * In Capistrano 3.5, `set :format_options, ...` is now the preferred mechanism for configuring Airbrussh. | ||
| 10 | |||
| 11 | ## How to upgrade | ||
| 12 | |||
| 13 | 1. Remove `gem "airbrussh"` from your Gemfile. Airbrussh is now included automatically by Capistrano. | ||
| 14 | 2. Likewise, remove `require "capistrano/airbrussh"` from your Capfile. Capistrano now does this internally. | ||
| 15 | 3. Remove `Airbrussh.configure do ... end` from your deploy.rb and replace with `set :format_options, ...` (see below). | ||
| 16 | |||
| 17 | ## New configuration system | ||
| 18 | |||
| 19 | In Capistrano 3.5, Airbrussh is configured by assigning a configuration Hash to the `:format_options` variable. Here is a comparison of the old and new syntaxes: | ||
| 20 | |||
| 21 | ```ruby | ||
| 22 | # Old syntax | ||
| 23 | Airbrussh.configure do |config| | ||
| 24 | config.color = false | ||
| 25 | end | ||
| 26 | |||
| 27 | # New syntax | ||
| 28 | set :format_options, color: false | ||
| 29 | ``` | ||
| 30 | |||
| 31 | Although the syntax is different, the names of the configuration keys have not changed. | ||
| 32 | |||
| 33 | ## New defaults | ||
| 34 | |||
| 35 | Capistrano 3.5.0 changes Airbrussh defaults as follows: | ||
| 36 | |||
| 37 | * `banner: false` | ||
| 38 | * `command_output: true` | ||
| 39 | |||
| 40 | Therefore, after upgrading to Capistrano 3.5.0, you may notice Airbrussh's output has changed and become more verbose. To restore the defaults to what you were used to in older versions, do this: | ||
| 41 | |||
| 42 | ```ruby | ||
| 43 | set :format_options, banner: :auto, command_output: false | ||
| 44 | ``` | ||
| 45 | |||
| 46 | ## Trouble? | ||
| 47 | |||
| 48 | If you have any Airbrussh-related trouble with the upgrade, please [open an issue](https://github.com/mattbrictson/airbrussh/issues). |
| 1 | # coding: utf-8 | ||
| 2 | lib = File.expand_path("../lib", __FILE__) | ||
| 3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) | ||
| 4 | require "airbrussh/version" | ||
| 5 | |||
| 6 | Gem::Specification.new do |spec| | ||
| 7 | spec.name = "airbrussh" | ||
| 8 | spec.version = Airbrussh::VERSION | ||
| 9 | spec.license = "MIT" | ||
| 10 | spec.authors = ["Matt Brictson"] | ||
| 11 | spec.email = ["airbrussh@mattbrictson.com"] | ||
| 12 | spec.summary = "Airbrussh pretties up your SSHKit and Capistrano output" | ||
| 13 | spec.description = "A replacement log formatter for SSHKit that makes "\ | ||
| 14 | "Capistrano output much easier on the eyes. Just add "\ | ||
| 15 | "Airbrussh to your Capfile and enjoy concise, useful "\ | ||
| 16 | "log output that is easy to read." | ||
| 17 | spec.homepage = "https://github.com/mattbrictson/airbrussh" | ||
| 18 | spec.metadata = { | ||
| 19 | "bug_tracker_uri" => "https://github.com/mattbrictson/airbrussh/issues", | ||
| 20 | "changelog_uri" => "https://github.com/mattbrictson/airbrussh/releases", | ||
| 21 | "source_code_uri" => "https://github.com/mattbrictson/airbrussh", | ||
| 22 | "homepage_uri" => "https://github.com/mattbrictson/airbrussh" | ||
| 23 | } | ||
| 24 | |||
| 25 | spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/|\.(gif|png)$}) } | ||
| 26 | spec.bindir = "exe" | ||
| 27 | spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } | ||
| 28 | spec.require_paths = ["lib"] | ||
| 29 | |||
| 30 | spec.add_dependency "sshkit", [">= 1.6.1", "!= 1.7.0"] | ||
| 31 | |||
| 32 | spec.add_development_dependency "bundler" | ||
| 33 | spec.add_development_dependency "rake", "~> 12.0" | ||
| 34 | spec.add_development_dependency "minitest", "~> 5.10" | ||
| 35 | spec.add_development_dependency "minitest-reporters", "~> 1.1" | ||
| 36 | spec.add_development_dependency "mocha", "~> 1.2" | ||
| 37 | end |
| 1 | #!/usr/bin/env ruby | ||
| 2 | |||
| 3 | require "bundler/setup" | ||
| 4 | require "airbrussh" | ||
| 5 | |||
| 6 | # You can add fixtures and/or initialization code here to make experimenting | ||
| 7 | # with your gem easier. You can also use a different console, if you like. | ||
| 8 | |||
| 9 | # (If you use this, don't forget to add pry to your Gemfile!) | ||
| 10 | # require "pry" | ||
| 11 | # Pry.start | ||
| 12 | |||
| 13 | require "irb" | ||
| 14 | IRB.start |
| 1 | require "airbrussh/configuration" | ||
| 2 | require "airbrussh/formatter" | ||
| 3 | require "airbrussh/version" | ||
| 4 | |||
| 5 | module Airbrussh | ||
| 6 | def self.configuration(options={}) | ||
| 7 | return options if options.is_a?(::Airbrussh::Configuration) | ||
| 8 | @configuration ||= Configuration.new | ||
| 9 | @configuration.apply_options(options) | ||
| 10 | end | ||
| 11 | |||
| 12 | def self.configure | ||
| 13 | yield(configuration) | ||
| 14 | end | ||
| 15 | end |
| 1 | require "airbrussh/capistrano/tasks" | ||
| 2 | |||
| 3 | tasks = Airbrussh::Capistrano::Tasks.new(self) | ||
| 4 | |||
| 5 | # Hook into Capistrano's init process to set the formatter | ||
| 6 | namespace :load do | ||
| 7 | task :defaults do | ||
| 8 | tasks.load_defaults | ||
| 9 | end | ||
| 10 | end | ||
| 11 | |||
| 12 | # Capistrano failure hook | ||
| 13 | namespace :deploy do | ||
| 14 | task :failed do | ||
| 15 | tasks.deploy_failed | ||
| 16 | end | ||
| 17 | end |
| 1 | require "airbrussh" | ||
| 2 | require "airbrussh/colors" | ||
| 3 | require "airbrussh/console" | ||
| 4 | require "forwardable" | ||
| 5 | require "shellwords" | ||
| 6 | |||
| 7 | module Airbrussh | ||
| 8 | module Capistrano | ||
| 9 | # Encapsulates the rake behavior that integrates Airbrussh into Capistrano. | ||
| 10 | # This class allows us to easily test the behavior using a mock to stand in | ||
| 11 | # for the Capistrano DSL. | ||
| 12 | # | ||
| 13 | # See airbrussh/capistrano.rb to see how this class is used. | ||
| 14 | # | ||
| 15 | class Tasks | ||
| 16 | extend Forwardable | ||
| 17 | def_delegators :dsl, :set, :env | ||
| 18 | def_delegators :config, :log_file | ||
| 19 | |||
| 20 | include Airbrussh::Colors | ||
| 21 | |||
| 22 | def initialize(dsl, stderr=$stderr, config=Airbrussh.configuration) | ||
| 23 | @dsl = dsl | ||
| 24 | @stderr = stderr | ||
| 25 | @config = config | ||
| 26 | |||
| 27 | configure | ||
| 28 | warn_if_missing_dsl | ||
| 29 | end | ||
| 30 | |||
| 31 | # Behavior for the rake load:defaults task. | ||
| 32 | def load_defaults | ||
| 33 | require "sshkit/formatter/airbrussh" | ||
| 34 | set :format, :airbrussh | ||
| 35 | end | ||
| 36 | |||
| 37 | # Behavior for the rake deploy:failed task. | ||
| 38 | def deploy_failed | ||
| 39 | return unless airbrussh_is_being_used? | ||
| 40 | return if log_file.nil? | ||
| 41 | |||
| 42 | error_line | ||
| 43 | error_line(red("** DEPLOY FAILED")) | ||
| 44 | error_line(yellow("** Refer to #{log_file} for details. "\ | ||
| 45 | "Here are the last 20 lines:")) | ||
| 46 | error_line | ||
| 47 | error_line(tail_log_file) | ||
| 48 | end | ||
| 49 | |||
| 50 | private | ||
| 51 | |||
| 52 | attr_reader :dsl, :stderr, :config | ||
| 53 | |||
| 54 | # Change airbrussh's default configuration to be more appropriate for | ||
| 55 | # capistrano. | ||
| 56 | def configure | ||
| 57 | config.log_file = "log/capistrano.log" | ||
| 58 | config.monkey_patch_rake = true | ||
| 59 | end | ||
| 60 | |||
| 61 | # Verify that capistrano and rake DSLs are present | ||
| 62 | def warn_if_missing_dsl | ||
| 63 | return if %w[set namespace task].all? { |m| dsl.respond_to?(m, true) } | ||
| 64 | |||
| 65 | error_line( | ||
| 66 | red("WARNING: airbrussh/capistrano must be loaded by Capistrano in "\ | ||
| 67 | "order to work.\nRequire this gem within your application's "\ | ||
| 68 | "Capfile, as described here:\n"\ | ||
| 69 | "https://github.com/mattbrictson/airbrussh#installation") | ||
| 70 | ) | ||
| 71 | end | ||
| 72 | |||
| 73 | def err_console | ||
| 74 | @err_console ||= begin | ||
| 75 | # Ensure we do not truncate the error output | ||
| 76 | err_config = config.dup | ||
| 77 | err_config.truncate = false | ||
| 78 | Airbrussh::Console.new(stderr, err_config) | ||
| 79 | end | ||
| 80 | end | ||
| 81 | |||
| 82 | def error_line(line="\n") | ||
| 83 | line.each_line(&err_console.method(:print_line)) | ||
| 84 | end | ||
| 85 | |||
| 86 | # Returns a String containing the last 20 lines of the log file. Since | ||
| 87 | # this method uses a fixed-size buffer, fewer than 20 lines may be | ||
| 88 | # returned in cases where the lines are extremely long. | ||
| 89 | def tail_log_file | ||
| 90 | open(log_file) do |file| | ||
| 91 | file.seek(-[8192, file.size].min, IO::SEEK_END) | ||
| 92 | file.readlines.last(20).join | ||
| 93 | end | ||
| 94 | end | ||
| 95 | |||
| 96 | def airbrussh_is_being_used? | ||
| 97 | # Obtain the current formatter from the SSHKit backend | ||
| 98 | output = env.backend.config.output | ||
| 99 | output.is_a?(Airbrussh::Formatter) | ||
| 100 | end | ||
| 101 | end | ||
| 102 | end | ||
| 103 | end |
| 1 | module Airbrussh | ||
| 2 | # Very basic support for ANSI color, so that we don't have to rely on | ||
| 3 | # any external dependencies. | ||
| 4 | module Colors | ||
| 5 | ANSI_CODES = { | ||
| 6 | :red => 31, | ||
| 7 | :green => 32, | ||
| 8 | :yellow => 33, | ||
| 9 | :blue => 34, | ||
| 10 | :gray => 90 | ||
| 11 | }.freeze | ||
| 12 | |||
| 13 | # Define red, green, blue, etc. methods that return a copy of the | ||
| 14 | # String that is wrapped in the corresponding ANSI color escape | ||
| 15 | # sequence. | ||
| 16 | ANSI_CODES.each do |name, code| | ||
| 17 | define_method(name) do |string| | ||
| 18 | "\e[0;#{code};49m#{string}\e[0m" | ||
| 19 | end | ||
| 20 | module_function(name) | ||
| 21 | end | ||
| 22 | end | ||
| 23 | end |
| 1 | # encoding: UTF-8 | ||
| 2 | |||
| 3 | require "airbrussh/colors" | ||
| 4 | require "delegate" | ||
| 5 | # rubocop:disable Style/AsciiComments | ||
| 6 | |||
| 7 | module Airbrussh | ||
| 8 | # Decorates an SSHKit Command to add string output helpers and the | ||
| 9 | # command's position within currently executing rake task: | ||
| 10 | # | ||
| 11 | # * position - zero-based position of this command in the list of | ||
| 12 | # all commands that have been run in the current rake task; in | ||
| 13 | # some cases this could be nil | ||
| 14 | class CommandFormatter < SimpleDelegator | ||
| 15 | include Airbrussh::Colors | ||
| 16 | |||
| 17 | def initialize(command, position) | ||
| 18 | super(command) | ||
| 19 | @position = position | ||
| 20 | end | ||
| 21 | |||
| 22 | # Prefixes the line with the command number and removes the newline. | ||
| 23 | # | ||
| 24 | # format_output("hello\n") # => "01 hello" | ||
| 25 | # | ||
| 26 | def format_output(line) | ||
| 27 | "#{number} #{line.chomp}" | ||
| 28 | end | ||
| 29 | |||
| 30 | # Returns the abbreviated command (in yellow) with the number prefix. | ||
| 31 | # | ||
| 32 | # start_message # => "01 echo hello" | ||
| 33 | # | ||
| 34 | def start_message | ||
| 35 | "#{number} #{yellow(abbreviated)}" | ||
| 36 | end | ||
| 37 | |||
| 38 | # Returns a green (success) or red (failure) message depending on the | ||
| 39 | # exit status. | ||
| 40 | # | ||
| 41 | # exit_message # => "✔ 01 user@host 0.084s" | ||
| 42 | # exit_message # => "✘ 01 user@host 0.084s" | ||
| 43 | # | ||
| 44 | def exit_message | ||
| 45 | message = if failure? | ||
| 46 | red(failure_message) | ||
| 47 | else | ||
| 48 | green(success_message) | ||
| 49 | end | ||
| 50 | message << " #{runtime}" | ||
| 51 | end | ||
| 52 | |||
| 53 | private | ||
| 54 | |||
| 55 | def user_at_host | ||
| 56 | user_str = host.user || (host.ssh_options || {})[:user] | ||
| 57 | host_str = host.hostname | ||
| 58 | [user_str, host_str].compact.join("@") | ||
| 59 | end | ||
| 60 | |||
| 61 | def runtime | ||
| 62 | format("%5.3fs", super) | ||
| 63 | end | ||
| 64 | |||
| 65 | def abbreviated | ||
| 66 | to_s.sub(%r{^/usr/bin/env }, "") | ||
| 67 | end | ||
| 68 | |||
| 69 | def number | ||
| 70 | format("%02d", @position.to_i + 1) | ||
| 71 | end | ||
| 72 | |||
| 73 | def success_message | ||
| 74 | "✔ #{number} #{user_at_host}" | ||
| 75 | end | ||
| 76 | |||
| 77 | def failure_message | ||
| 78 | "✘ #{number} #{user_at_host}" | ||
| 79 | end | ||
| 80 | end | ||
| 81 | end |
| 1 | require "airbrussh/colors" | ||
| 2 | require "airbrussh/console_formatter" | ||
| 3 | require "airbrussh/log_file_formatter" | ||
| 4 | |||
| 5 | module Airbrussh | ||
| 6 | class Configuration | ||
| 7 | attr_accessor :log_file, :monkey_patch_rake, :color, :truncate, :banner, | ||
| 8 | :command_output, :task_prefix, :context | ||
| 9 | |||
| 10 | def initialize | ||
| 11 | self.log_file = nil | ||
| 12 | self.monkey_patch_rake = false | ||
| 13 | self.color = :auto | ||
| 14 | self.truncate = :auto | ||
| 15 | self.banner = :auto | ||
| 16 | self.command_output = false | ||
| 17 | self.task_prefix = nil | ||
| 18 | self.context = Airbrussh::Rake::Context | ||
| 19 | end | ||
| 20 | |||
| 21 | def apply_options(options) | ||
| 22 | return self if options.nil? | ||
| 23 | |||
| 24 | options.each do |key, value| | ||
| 25 | if respond_to?(writer = "#{key}=") | ||
| 26 | public_send(writer, value) | ||
| 27 | else | ||
| 28 | warn_unrecognized_key(key) | ||
| 29 | end | ||
| 30 | end | ||
| 31 | self | ||
| 32 | end | ||
| 33 | |||
| 34 | def banner_message | ||
| 35 | return nil unless banner | ||
| 36 | return banner unless banner == :auto | ||
| 37 | msg = "Using airbrussh format." | ||
| 38 | if log_file | ||
| 39 | msg << "\n" | ||
| 40 | msg << "Verbose output is being written to #{Colors.blue(log_file)}." | ||
| 41 | end | ||
| 42 | msg | ||
| 43 | end | ||
| 44 | |||
| 45 | # This returns an array of formatters appropriate for the configuration. | ||
| 46 | # Depending on whether a log file is configured, this could be just the | ||
| 47 | # Airbrussh:ConsoleFormatter, or that plus the LogFileFormatter. | ||
| 48 | def formatters(io) | ||
| 49 | fmts = [Airbrussh::ConsoleFormatter.new(io, self)] | ||
| 50 | fmts.unshift(Airbrussh::LogFileFormatter.new(log_file)) if log_file | ||
| 51 | fmts | ||
| 52 | end | ||
| 53 | |||
| 54 | def show_command_output?(sym) | ||
| 55 | command_output == true || Array(command_output).include?(sym) | ||
| 56 | end | ||
| 57 | |||
| 58 | private | ||
| 59 | |||
| 60 | def warn_unrecognized_key(key) | ||
| 61 | $stderr.puts("Ignoring unrecognized Airbrussh option: #{key}") | ||
| 62 | end | ||
| 63 | end | ||
| 64 | end |
| 1 | # encoding: UTF-8 | ||
| 2 | |||
| 3 | require "io/console" | ||
| 4 | |||
| 5 | module Airbrussh | ||
| 6 | # Helper class that wraps an IO object and provides methods for truncating | ||
| 7 | # output, assuming the IO object represents a console window. | ||
| 8 | # | ||
| 9 | # This is useful for writing log messages that will typically show up on | ||
| 10 | # an ANSI color-capable console. When a console is not present (e.g. when | ||
| 11 | # running on a CI server) the output will gracefully degrade. | ||
| 12 | class Console | ||
| 13 | attr_reader :output, :config | ||
| 14 | |||
| 15 | def initialize(output, config=Airbrussh.configuration) | ||
| 16 | @output = output | ||
| 17 | @config = config | ||
| 18 | end | ||
| 19 | |||
| 20 | # Writes to the IO after first truncating the output to fit the console | ||
| 21 | # width. If the underlying IO is not a TTY, ANSI colors are removed from | ||
| 22 | # the output. A newline is always added. Color output can be forced by | ||
| 23 | # setting the SSHKIT_COLOR environment variable. | ||
| 24 | def print_line(obj="") | ||
| 25 | string = obj.to_s | ||
| 26 | |||
| 27 | string = truncate_to_console_width(string) if console_width | ||
| 28 | string = strip_ascii_color(string) unless color_enabled? | ||
| 29 | |||
| 30 | write(string + "\n") | ||
| 31 | output.flush | ||
| 32 | end | ||
| 33 | |||
| 34 | # Writes directly through to the IO with no truncation or color logic. | ||
| 35 | # No newline is added. | ||
| 36 | def write(string) | ||
| 37 | output.write(string || "") | ||
| 38 | end | ||
| 39 | alias << write | ||
| 40 | |||
| 41 | def truncate_to_console_width(string) | ||
| 42 | string = (string || "").rstrip | ||
| 43 | ellipsis = utf8_supported?(string) ? "…" : "..." | ||
| 44 | width = console_width | ||
| 45 | |||
| 46 | if strip_ascii_color(string).length > width | ||
| 47 | width -= ellipsis.length | ||
| 48 | string.chop! while strip_ascii_color(string).length > width | ||
| 49 | string << "#{ellipsis}\e[0m" | ||
| 50 | else | ||
| 51 | string | ||
| 52 | end | ||
| 53 | end | ||
| 54 | |||
| 55 | def strip_ascii_color(string) | ||
| 56 | string ||= "" | ||
| 57 | string = to_utf8(string) unless string.valid_encoding? | ||
| 58 | |||
| 59 | string.gsub(/\033\[[0-9;]*m/, "") | ||
| 60 | end | ||
| 61 | |||
| 62 | def console_width | ||
| 63 | width = case (truncate = config.truncate) | ||
| 64 | when :auto | ||
| 65 | IO.console.winsize.last if @output.tty? | ||
| 66 | when Integer | ||
| 67 | truncate | ||
| 68 | end | ||
| 69 | |||
| 70 | width if width.to_i > 0 | ||
| 71 | end | ||
| 72 | |||
| 73 | private | ||
| 74 | |||
| 75 | def color_enabled? | ||
| 76 | case config.color | ||
| 77 | when true | ||
| 78 | true | ||
| 79 | when :auto | ||
| 80 | ENV["SSHKIT_COLOR"] || @output.tty? | ||
| 81 | else | ||
| 82 | false | ||
| 83 | end | ||
| 84 | end | ||
| 85 | |||
| 86 | def utf8_supported?(string) | ||
| 87 | string.encode("UTF-8").valid_encoding? | ||
| 88 | rescue Encoding::UndefinedConversionError | ||
| 89 | false | ||
| 90 | end | ||
| 91 | |||
| 92 | def to_utf8(string) | ||
| 93 | string.force_encoding("ASCII-8BIT") | ||
| 94 | .encode("UTF-8", :invalid => :replace, :undef => :replace) | ||
| 95 | end | ||
| 96 | end | ||
| 97 | end |
| 1 | require "airbrussh/colors" | ||
| 2 | require "airbrussh/command_formatter" | ||
| 3 | require "airbrussh/console" | ||
| 4 | require "airbrussh/rake/context" | ||
| 5 | require "sshkit" | ||
| 6 | |||
| 7 | module Airbrussh | ||
| 8 | class ConsoleFormatter < SSHKit::Formatter::Abstract | ||
| 9 | include Airbrussh::Colors | ||
| 10 | extend Forwardable | ||
| 11 | |||
| 12 | attr_reader :config, :context | ||
| 13 | def_delegators :context, :current_task_name, :register_new_command | ||
| 14 | |||
| 15 | def initialize(io, config=Airbrussh.configuration) | ||
| 16 | super(io) | ||
| 17 | |||
| 18 | @config = config | ||
| 19 | @context = config.context.new(config) | ||
| 20 | @console = Airbrussh::Console.new(original_output, config) | ||
| 21 | |||
| 22 | write_banner | ||
| 23 | end | ||
| 24 | |||
| 25 | def write_banner | ||
| 26 | print_line(config.banner_message) if config.banner_message | ||
| 27 | end | ||
| 28 | |||
| 29 | def log_command_start(command) | ||
| 30 | return if debug?(command) | ||
| 31 | first_execution = register_new_command(command) | ||
| 32 | command = decorate(command) | ||
| 33 | print_task_if_changed | ||
| 34 | print_indented_line(command.start_message) if first_execution | ||
| 35 | end | ||
| 36 | |||
| 37 | def log_command_data(command, stream_type, string) | ||
| 38 | return if debug?(command) | ||
| 39 | return unless config.show_command_output?(stream_type) | ||
| 40 | command = decorate(command) | ||
| 41 | string.each_line do |line| | ||
| 42 | print_indented_line(command.format_output(line)) | ||
| 43 | end | ||
| 44 | end | ||
| 45 | |||
| 46 | def log_command_exit(command) | ||
| 47 | return if debug?(command) | ||
| 48 | command = decorate(command) | ||
| 49 | print_indented_line(command.exit_message, -2) | ||
| 50 | end | ||
| 51 | |||
| 52 | def write(obj) | ||
| 53 | case obj | ||
| 54 | when SSHKit::Command | ||
| 55 | log_command_start(obj) | ||
| 56 | log_and_clear_command_output(obj, :stderr) | ||
| 57 | log_and_clear_command_output(obj, :stdout) | ||
| 58 | log_command_exit(obj) if obj.finished? | ||
| 59 | when SSHKit::LogMessage | ||
| 60 | write_log_message(obj) | ||
| 61 | end | ||
| 62 | end | ||
| 63 | alias << write | ||
| 64 | |||
| 65 | private | ||
| 66 | |||
| 67 | attr_accessor :last_printed_task | ||
| 68 | |||
| 69 | def write_log_message(log_message) | ||
| 70 | return if debug?(log_message) | ||
| 71 | print_task_if_changed | ||
| 72 | print_indented_line(format_log_message(log_message)) | ||
| 73 | end | ||
| 74 | |||
| 75 | def format_log_message(log_message) | ||
| 76 | case log_message.verbosity | ||
| 77 | when SSHKit::Logger::WARN | ||
| 78 | "#{yellow('WARN')} #{log_message}" | ||
| 79 | when SSHKit::Logger::ERROR | ||
| 80 | "#{red('ERROR')} #{log_message}" | ||
| 81 | when SSHKit::Logger::FATAL | ||
| 82 | "#{red('FATAL')} #{log_message}" | ||
| 83 | else | ||
| 84 | log_message.to_s | ||
| 85 | end | ||
| 86 | end | ||
| 87 | |||
| 88 | # For SSHKit versions up to and including 1.7.1, the stdout and stderr | ||
| 89 | # output was available as attributes on the Command. Print the data for | ||
| 90 | # the specified command and stream if enabled and clear the stream. | ||
| 91 | # (see Airbrussh::Configuration#command_output). | ||
| 92 | def log_and_clear_command_output(command, stream) | ||
| 93 | output = command.public_send(stream) | ||
| 94 | log_command_data(command, stream, output) | ||
| 95 | command.public_send("#{stream}=", "") | ||
| 96 | end | ||
| 97 | |||
| 98 | def print_task_if_changed | ||
| 99 | return if current_task_name.nil? | ||
| 100 | return if current_task_name == last_printed_task | ||
| 101 | |||
| 102 | self.last_printed_task = current_task_name | ||
| 103 | print_line("#{config.task_prefix}#{clock} #{blue(current_task_name)}") | ||
| 104 | end | ||
| 105 | |||
| 106 | def clock | ||
| 107 | @start_at ||= Time.now | ||
| 108 | duration = Time.now - @start_at | ||
| 109 | |||
| 110 | minutes = (duration / 60).to_i | ||
| 111 | seconds = (duration - minutes * 60).to_i | ||
| 112 | |||
| 113 | format("%02d:%02d", minutes, seconds) | ||
| 114 | end | ||
| 115 | |||
| 116 | def debug?(obj) | ||
| 117 | obj.verbosity <= SSHKit::Logger::DEBUG | ||
| 118 | end | ||
| 119 | |||
| 120 | def decorate(command) | ||
| 121 | Airbrussh::CommandFormatter.new(command, @context.position(command)) | ||
| 122 | end | ||
| 123 | |||
| 124 | def print_line(string) | ||
| 125 | @console.print_line(string) | ||
| 126 | end | ||
| 127 | |||
| 128 | def print_indented_line(string, offset=0) | ||
| 129 | indent = " " * (6 + offset) | ||
| 130 | print_line([indent, string].join) | ||
| 131 | end | ||
| 132 | end | ||
| 133 | end |
| 1 | require "sshkit" | ||
| 2 | |||
| 3 | module Airbrussh | ||
| 4 | # This class quacks like an SSHKit::Formatter, but when any formatting | ||
| 5 | # methods are called, it simply forwards them to one more more concrete | ||
| 6 | # formatters. This allows us to split out the responsibilities of | ||
| 7 | # ConsoleFormatter and LogFileFormatter into two separate classes, with | ||
| 8 | # DelegatingFormatter forwarding the logging messages to both at once. | ||
| 9 | # | ||
| 10 | class DelegatingFormatter | ||
| 11 | FORWARD_METHODS = %w[ | ||
| 12 | fatal error warn info debug log | ||
| 13 | log_command_start log_command_data log_command_exit | ||
| 14 | ].freeze | ||
| 15 | DUP_AND_FORWARD_METHODS = %w[<< write].freeze | ||
| 16 | |||
| 17 | attr_reader :formatters | ||
| 18 | |||
| 19 | def initialize(formatters) | ||
| 20 | @formatters = formatters | ||
| 21 | end | ||
| 22 | |||
| 23 | FORWARD_METHODS.each do |method| | ||
| 24 | define_method(method) do |*args| | ||
| 25 | formatters.map { |f| f.public_send(method, *args) }.last | ||
| 26 | end | ||
| 27 | end | ||
| 28 | |||
| 29 | # For versions of SSHKit up to and including 1.7.1, the LogfileFormatter | ||
| 30 | # and ConsoleFormatter (and all of SSHKit's built in formatters) clear | ||
| 31 | # the stdout and stderr data in the command obj. Therefore, ensure only | ||
| 32 | # one of the formatters (the last one) gets the original command. This is | ||
| 33 | # also the formatter whose return value is passed to the caller. | ||
| 34 | # | ||
| 35 | DUP_AND_FORWARD_METHODS.each do |method| | ||
| 36 | define_method(method) do |command_or_log_message| | ||
| 37 | formatters[0...-1].each do |f| | ||
| 38 | f.public_send(method, command_or_log_message.dup) | ||
| 39 | end | ||
| 40 | formatters.last.public_send(method, command_or_log_message) | ||
| 41 | end | ||
| 42 | end | ||
| 43 | end | ||
| 44 | end |
| 1 | require "airbrussh" | ||
| 2 | require "airbrussh/delegating_formatter" | ||
| 3 | |||
| 4 | # This is the formatter class that conforms to the SSHKit Formatter API and | ||
| 5 | # provides the airbrussh functionality to SSHKit. Note however that this class | ||
| 6 | # doesn't do much by itself; instead, it delegates to the ConsoleFormatter | ||
| 7 | # and (optionally) the LogFileFormatter, which handle the bulk of the logic. | ||
| 8 | # | ||
| 9 | module Airbrussh | ||
| 10 | class Formatter < Airbrussh::DelegatingFormatter | ||
| 11 | def initialize(io, options_or_config_object={}) | ||
| 12 | config = ::Airbrussh.configuration(options_or_config_object) | ||
| 13 | # Delegate to ConsoleFormatter and (optionally) LogFileFormatter, | ||
| 14 | # based on the configuration. | ||
| 15 | super(config.formatters(io)) | ||
| 16 | end | ||
| 17 | end | ||
| 18 | end |
| 1 | require "delegate" | ||
| 2 | require "fileutils" | ||
| 3 | require "logger" | ||
| 4 | require "sshkit" | ||
| 5 | |||
| 6 | module Airbrussh | ||
| 7 | # A Pretty formatter that sends its output to a specified log file path. | ||
| 8 | # LogFileFormatter takes care of creating the file (and its parent | ||
| 9 | # directory) if it does not already exist, opens it for appending, and writes | ||
| 10 | # a delimiter message. The file is automatically rotated if it reaches 20 MB. | ||
| 11 | # | ||
| 12 | class LogFileFormatter < SimpleDelegator | ||
| 13 | attr_reader :path | ||
| 14 | |||
| 15 | def initialize(path, formatter_class=SSHKit::Formatter::Pretty) | ||
| 16 | @path = path | ||
| 17 | ensure_directory_exists if path.is_a?(String) | ||
| 18 | super(formatter_class.new(log_file_io)) | ||
| 19 | write_delimiter | ||
| 20 | end | ||
| 21 | |||
| 22 | private | ||
| 23 | |||
| 24 | def write_delimiter | ||
| 25 | delimiter = [] | ||
| 26 | delimiter << "-" * 75 | ||
| 27 | delimiter << "START #{Time.now} cap #{ARGV.join(' ')}" | ||
| 28 | delimiter << "-" * 75 | ||
| 29 | delimiter.each do |line| | ||
| 30 | write(SSHKit::LogMessage.new(SSHKit::Logger::INFO, line)) | ||
| 31 | end | ||
| 32 | end | ||
| 33 | |||
| 34 | def ensure_directory_exists | ||
| 35 | FileUtils.mkdir_p(File.dirname(path)) | ||
| 36 | end | ||
| 37 | |||
| 38 | def log_file_io | ||
| 39 | @io ||= ::Logger.new(path, 1, 20_971_520) | ||
| 40 | end | ||
| 41 | end | ||
| 42 | end |
| 1 | module Airbrussh | ||
| 2 | module Rake | ||
| 3 | # Maintains information about what Rake task is currently being invoked, | ||
| 4 | # in order to be able to decorate SSHKit commands with additional | ||
| 5 | # context-sensitive information. Works via a monkey patch to Rake::Task, | ||
| 6 | # which can be disabled via by setting | ||
| 7 | # Airbrussh.configuration.monkey_patch_rake = false. | ||
| 8 | # | ||
| 9 | # Note that this class is not thread-safe. Normally this is not a problem, | ||
| 10 | # but some Capistrano users are known to use `invoke` to switch the Rake | ||
| 11 | # task in the middle of an SSHKit thread, which causes Context to get very | ||
| 12 | # confused. It such scenarios Context is not reliable and may return `nil` | ||
| 13 | # for the `position` of a command. | ||
| 14 | # | ||
| 15 | class Context | ||
| 16 | def initialize(config=Airbrussh.configuration) | ||
| 17 | @history = [] | ||
| 18 | @enabled = config.monkey_patch_rake | ||
| 19 | self.class.install_monkey_patch if enabled? | ||
| 20 | end | ||
| 21 | |||
| 22 | # Returns the name of the currently-executing rake task, if it can be | ||
| 23 | # determined. If monkey patching is disabled, this will be nil. | ||
| 24 | def current_task_name | ||
| 25 | return nil unless enabled? | ||
| 26 | self.class.current_task_name | ||
| 27 | end | ||
| 28 | |||
| 29 | # Update the context when a new command starts by: | ||
| 30 | # * Clearing the command history if the rake task has changed | ||
| 31 | # * Recording the command in the history | ||
| 32 | # | ||
| 33 | # Returns whether or not this command was the first execution | ||
| 34 | # of this command in the current rake task | ||
| 35 | def register_new_command(command) | ||
| 36 | reset_history_if_task_changed | ||
| 37 | |||
| 38 | first_execution = !history.include?(command.to_s) | ||
| 39 | history << command.to_s | ||
| 40 | history.uniq! | ||
| 41 | first_execution | ||
| 42 | end | ||
| 43 | |||
| 44 | # The zero-based position of the specified command in the current rake | ||
| 45 | # task. May be `nil` in certain multi-threaded scenarios, so be careful! | ||
| 46 | def position(command) | ||
| 47 | history.index(command.to_s) | ||
| 48 | end | ||
| 49 | |||
| 50 | class << self | ||
| 51 | attr_accessor :current_task_name | ||
| 52 | |||
| 53 | def install_monkey_patch | ||
| 54 | require "rake" | ||
| 55 | return if ::Rake::Task.instance_methods.include?(:_airbrussh_execute) | ||
| 56 | |||
| 57 | ::Rake::Task.class_exec do | ||
| 58 | alias_method :_airbrussh_execute, :execute | ||
| 59 | def execute(args=nil) | ||
| 60 | ::Airbrussh::Rake::Context.current_task_name = name.to_s | ||
| 61 | _airbrussh_execute(args) | ||
| 62 | end | ||
| 63 | end | ||
| 64 | end | ||
| 65 | end | ||
| 66 | |||
| 67 | private | ||
| 68 | |||
| 69 | attr_reader :history | ||
| 70 | attr_accessor :last_task_name | ||
| 71 | |||
| 72 | def reset_history_if_task_changed | ||
| 73 | history.clear if last_task_name != current_task_name | ||
| 74 | self.last_task_name = current_task_name | ||
| 75 | end | ||
| 76 | |||
| 77 | def enabled? | ||
| 78 | @enabled | ||
| 79 | end | ||
| 80 | end | ||
| 81 | end | ||
| 82 | end |
| 1 | require "airbrussh/formatter" | ||
| 2 | |||
| 3 | # Capistrano's formatter configuration requires that the formatter class | ||
| 4 | # be in the SSHKit::Formatter namespace. So we declare | ||
| 5 | # SSHKit::Formatter::Airbrussh that simply functions as an alias for | ||
| 6 | # Airbrussh::Formatter. | ||
| 7 | module SSHKit | ||
| 8 | module Formatter | ||
| 9 | class Airbrussh < Airbrussh::Formatter | ||
| 10 | end | ||
| 11 | end | ||
| 12 | end |
This diff could not be displayed because it is too large.
| 1 | The MIT License | ||
| 2 | |||
| 3 | Portions copyright (c) 2010-2019 André Arko | ||
| 4 | Portions copyright (c) 2009 Engine Yard | ||
| 5 | |||
| 6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 7 | of this software and associated documentation files (the "Software"), to deal | ||
| 8 | in the Software without restriction, including without limitation the rights | ||
| 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 10 | copies of the Software, and to permit persons to whom the Software is | ||
| 11 | furnished to do so, subject to the following conditions: | ||
| 12 | |||
| 13 | The above copyright notice and this permission notice shall be included in | ||
| 14 | all copies or substantial portions of the Software. | ||
| 15 | |||
| 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
| 22 | THE SOFTWARE. |
| 1 | [](https://rubygems.org/gems/bundler) | ||
| 2 | [](https://bundler-slackin.herokuapp.com) | ||
| 3 | |||
| 4 | # Bundler: a gem to bundle gems | ||
| 5 | |||
| 6 | Bundler makes sure Ruby applications run the same code on every machine. | ||
| 7 | |||
| 8 | It does this by managing the gems that the application depends on. Given a list of gems, it can automatically download and install those gems, as well as any other gems needed by the gems that are listed. Before installing gems, it checks the versions of every gem to make sure that they are compatible, and can all be loaded at the same time. After the gems have been installed, Bundler can help you update some or all of them when new versions become available. Finally, it records the exact versions that have been installed, so that others can install the exact same gems. | ||
| 9 | |||
| 10 | ### Installation and usage | ||
| 11 | |||
| 12 | To install (or update to the latest version): | ||
| 13 | |||
| 14 | ``` | ||
| 15 | gem install bundler | ||
| 16 | ``` | ||
| 17 | |||
| 18 | To install a prerelease version (if one is available), run `gem install bundler --pre`. To uninstall Bundler, run `gem uninstall bundler`. | ||
| 19 | |||
| 20 | Bundler is most commonly used to manage your application's dependencies. For example, these commands will allow you to use Bundler to manage the `rspec` gem for your application: | ||
| 21 | |||
| 22 | ``` | ||
| 23 | bundle init | ||
| 24 | bundle add rspec | ||
| 25 | bundle install | ||
| 26 | bundle exec rspec | ||
| 27 | ``` | ||
| 28 | |||
| 29 | See [bundler.io](https://bundler.io) for the full documentation. | ||
| 30 | |||
| 31 | ### Troubleshooting | ||
| 32 | |||
| 33 | For help with common problems, see [TROUBLESHOOTING](doc/TROUBLESHOOTING.md). | ||
| 34 | |||
| 35 | Still stuck? Try [filing an issue](https://github.com/rubygems/rubygems/issues/new?labels=Bundler&template=bundler-related-issue.md). | ||
| 36 | |||
| 37 | ### Other questions | ||
| 38 | |||
| 39 | To see what has changed in recent versions of Bundler, see the [CHANGELOG](CHANGELOG.md). | ||
| 40 | |||
| 41 | To get in touch with the Bundler core team and other Bundler users, please see [getting help](doc/contributing/GETTING_HELP.md). | ||
| 42 | |||
| 43 | ### Contributing | ||
| 44 | |||
| 45 | If you'd like to contribute to Bundler, that's awesome, and we <3 you. We've put together [the Bundler contributor guide](https://github.com/rubygems/rubygems/blob/master/bundler/doc/contributing/README.md) with all of the information you need to get started. | ||
| 46 | |||
| 47 | If you'd like to request a substantial change to Bundler or its documentation, refer to the [Bundler RFC process](https://github.com/bundler/rfcs) for more information. | ||
| 48 | |||
| 49 | While some Bundler contributors are compensated by Ruby Together, the project maintainers make decisions independent of Ruby Together. As a project, we welcome contributions regardless of the author's affiliation with Ruby Together. | ||
| 50 | |||
| 51 | ### Supporting | ||
| 52 | |||
| 53 | <a href="https://rubytogether.org/"><img src="https://rubytogether.org/images/rubies.svg" width="150"></a><br> | ||
| 54 | <a href="https://rubytogether.org/">Ruby Together</a> pays some Bundler maintainers for their ongoing work. As a grassroots initiative committed to supporting the critical Ruby infrastructure you rely on, Ruby Together is funded entirely by the Ruby community. Contribute today <a href="https://rubytogether.org/developers">as an individual</a> or (better yet) <a href="https://rubytogether.org/companies">as a company</a> to ensure that Bundler, RubyGems, and other shared tooling is around for years to come. | ||
| 55 | |||
| 56 | ### Code of Conduct | ||
| 57 | |||
| 58 | Everyone interacting in the Bundler project's codebases, issue trackers, chat rooms, and mailing lists is expected to follow the [Bundler code of conduct](https://github.com/rubygems/rubygems/blob/master/CODE_OF_CONDUCT.md). | ||
| 59 | |||
| 60 | ### License | ||
| 61 | |||
| 62 | Bundler is available under an [MIT License](https://github.com/rubygems/rubygems/blob/master/bundler/LICENSE.md). |
| 1 | # frozen_string_literal: true | ||
| 2 | |||
| 3 | begin | ||
| 4 | require_relative "lib/bundler/version" | ||
| 5 | rescue LoadError | ||
| 6 | # for Ruby core repository | ||
| 7 | require_relative "version" | ||
| 8 | end | ||
| 9 | |||
| 10 | Gem::Specification.new do |s| | ||
| 11 | s.name = "bundler" | ||
| 12 | s.version = Bundler::VERSION | ||
| 13 | s.license = "MIT" | ||
| 14 | s.authors = [ | ||
| 15 | "André Arko", "Samuel Giddins", "Colby Swandale", "Hiroshi Shibata", | ||
| 16 | "David Rodríguez", "Grey Baker", "Stephanie Morillo", "Chris Morris", "James Wen", "Tim Moore", | ||
| 17 | "André Medeiros", "Jessica Lynn Suttles", "Terence Lee", "Carl Lerche", | ||
| 18 | "Yehuda Katz" | ||
| 19 | ] | ||
| 20 | s.email = ["team@bundler.io"] | ||
| 21 | s.homepage = "https://bundler.io" | ||
| 22 | s.summary = "The best way to manage your application's dependencies" | ||
| 23 | s.description = "Bundler manages an application's dependencies through its entire life, across many machines, systematically and repeatably" | ||
| 24 | |||
| 25 | if s.respond_to?(:metadata=) | ||
| 26 | s.metadata = { | ||
| 27 | "bug_tracker_uri" => "https://github.com/rubygems/rubygems/issues?q=is%3Aopen+is%3Aissue+label%3ABundler", | ||
| 28 | "changelog_uri" => "https://github.com/rubygems/rubygems/blob/master/bundler/CHANGELOG.md", | ||
| 29 | "homepage_uri" => "https://bundler.io/", | ||
| 30 | "source_code_uri" => "https://github.com/rubygems/rubygems/", | ||
| 31 | } | ||
| 32 | end | ||
| 33 | |||
| 34 | s.required_ruby_version = ">= 2.3.0" | ||
| 35 | s.required_rubygems_version = ">= 2.5.2" | ||
| 36 | |||
| 37 | s.files = Dir.glob("lib/bundler{.rb,/**/*}", File::FNM_DOTMATCH).reject {|f| File.directory?(f) } | ||
| 38 | |||
| 39 | # include the gemspec itself because warbler breaks w/o it | ||
| 40 | s.files += %w[bundler.gemspec] | ||
| 41 | |||
| 42 | s.files += %w[CHANGELOG.md LICENSE.md README.md] | ||
| 43 | s.bindir = "exe" | ||
| 44 | s.executables = %w[bundle bundler] | ||
| 45 | s.require_paths = ["lib"] | ||
| 46 | end |
| 1 | #!/usr/bin/env ruby | ||
| 2 | # frozen_string_literal: true | ||
| 3 | |||
| 4 | # Exit cleanly from an early interrupt | ||
| 5 | Signal.trap("INT") do | ||
| 6 | Bundler.ui.debug("\n#{caller.join("\n")}") if defined?(Bundler) | ||
| 7 | exit 1 | ||
| 8 | end | ||
| 9 | |||
| 10 | base_path = File.expand_path("../lib", __dir__) | ||
| 11 | |||
| 12 | if File.exist?(base_path) | ||
| 13 | require_relative "../lib/bundler" | ||
| 14 | else | ||
| 15 | require "bundler" | ||
| 16 | end | ||
| 17 | |||
| 18 | # Workaround for non-activated bundler spec due to missing https://github.com/rubygems/rubygems/commit/4e306d7bcdee924b8d80ca9db6125aa59ee4e5a3 | ||
| 19 | gem "bundler", Bundler::VERSION if Gem.rubygems_version < Gem::Version.new("2.6.2") | ||
| 20 | |||
| 21 | if Gem.rubygems_version < Gem::Version.new("3.2.3") && Gem.ruby_version < Gem::Version.new("2.6.a") && !ENV["BUNDLER_NO_OLD_RUBYGEMS_WARNING"] | ||
| 22 | Bundler.ui.warn \ | ||
| 23 | "Your RubyGems version (#{Gem::VERSION}) has a bug that prevents " \ | ||
| 24 | "`required_ruby_version` from working for Bundler. Any scripts that use " \ | ||
| 25 | "`gem install bundler` will break as soon as Bundler drops support for " \ | ||
| 26 | "your Ruby version. Please upgrade RubyGems to avoid future breakage " \ | ||
| 27 | "and silence this warning by running `gem update --system 3.2.3`" | ||
| 28 | end | ||
| 29 | |||
| 30 | if File.exist?(base_path) | ||
| 31 | require_relative "../lib/bundler/friendly_errors" | ||
| 32 | else | ||
| 33 | require "bundler/friendly_errors" | ||
| 34 | end | ||
| 35 | |||
| 36 | Bundler.with_friendly_errors do | ||
| 37 | if File.exist?(base_path) | ||
| 38 | require_relative "../lib/bundler/cli" | ||
| 39 | else | ||
| 40 | require "bundler/cli" | ||
| 41 | end | ||
| 42 | |||
| 43 | # Allow any command to use --help flag to show help for that command | ||
| 44 | help_flags = %w[--help -h] | ||
| 45 | help_flag_used = ARGV.any? {|a| help_flags.include? a } | ||
| 46 | args = help_flag_used ? Bundler::CLI.reformatted_help_args(ARGV) : ARGV | ||
| 47 | |||
| 48 | Bundler::CLI.start(args, :debug => true) | ||
| 49 | end |
This diff is collapsed.
Click to expand it.
| 1 | # not in RDoc |
| 1 | # frozen_string_literal: true | ||
| 2 | |||
| 3 | module Bundler | ||
| 4 | # Represents metadata from when the Bundler gem was built. | ||
| 5 | module BuildMetadata | ||
| 6 | # begin ivars | ||
| 7 | @built_at = "2022-08-24".freeze | ||
| 8 | @git_commit_sha = "d54be5fdd8".freeze | ||
| 9 | @release = true | ||
| 10 | # end ivars | ||
| 11 | |||
| 12 | # A hash representation of the build metadata. | ||
| 13 | def self.to_h | ||
| 14 | { | ||
| 15 | "Built At" => built_at, | ||
| 16 | "Git SHA" => git_commit_sha, | ||
| 17 | "Released Version" => release?, | ||
| 18 | } | ||
| 19 | end | ||
| 20 | |||
| 21 | # A string representing the date the bundler gem was built. | ||
| 22 | def self.built_at | ||
| 23 | @built_at ||= Time.now.utc.strftime("%Y-%m-%d").freeze | ||
| 24 | end | ||
| 25 | |||
| 26 | # The SHA for the git commit the bundler gem was built from. | ||
| 27 | def self.git_commit_sha | ||
| 28 | return @git_commit_sha if instance_variable_defined? :@git_commit_sha | ||
| 29 | |||
| 30 | # If Bundler has been installed without its .git directory and without a | ||
| 31 | # commit instance variable then we can't determine its commits SHA. | ||
| 32 | git_dir = File.expand_path("../../../.git", __dir__) | ||
| 33 | if File.directory?(git_dir) | ||
| 34 | return @git_commit_sha = Dir.chdir(git_dir) { `git rev-parse --short HEAD`.strip.freeze } | ||
| 35 | end | ||
| 36 | |||
| 37 | @git_commit_sha ||= "unknown" | ||
| 38 | end | ||
| 39 | |||
| 40 | # Whether this is an official release build of Bundler. | ||
| 41 | def self.release? | ||
| 42 | @release | ||
| 43 | end | ||
| 44 | end | ||
| 45 | end |
| 1 | # frozen_string_literal: true | ||
| 2 | |||
| 3 | require_relative "shared_helpers" | ||
| 4 | Bundler::SharedHelpers.major_deprecation 2, | ||
| 5 | "The Bundler task for Capistrano. Please use https://github.com/capistrano/bundler" | ||
| 6 | |||
| 7 | # Capistrano task for Bundler. | ||
| 8 | # | ||
| 9 | # Add "require 'bundler/capistrano'" in your Capistrano deploy.rb, and | ||
| 10 | # Bundler will be activated after each new deployment. | ||
| 11 | require_relative "deployment" | ||
| 12 | require "capistrano/version" | ||
| 13 | |||
| 14 | if defined?(Capistrano::Version) && Gem::Version.new(Capistrano::Version).release >= Gem::Version.new("3.0") | ||
| 15 | raise "For Capistrano 3.x integration, please use https://github.com/capistrano/bundler" | ||
| 16 | end | ||
| 17 | |||
| 18 | Capistrano::Configuration.instance(:must_exist).load do | ||
| 19 | before "deploy:finalize_update", "bundle:install" | ||
| 20 | Bundler::Deployment.define_task(self, :task, :except => { :no_release => true }) | ||
| 21 | set :rake, lambda { "#{fetch(:bundle_cmd, "bundle")} exec rake" } | ||
| 22 | end |
This diff is collapsed.
Click to expand it.
| 1 | # frozen_string_literal: true | ||
| 2 | |||
| 3 | module Bundler | ||
| 4 | class CLI::Add | ||
| 5 | attr_reader :gems, :options, :version | ||
| 6 | |||
| 7 | def initialize(options, gems) | ||
| 8 | @gems = gems | ||
| 9 | @options = options | ||
| 10 | @options[:group] = options[:group].split(",").map(&:strip) unless options[:group].nil? | ||
| 11 | @version = options[:version].split(",").map(&:strip) unless options[:version].nil? | ||
| 12 | end | ||
| 13 | |||
| 14 | def run | ||
| 15 | validate_options! | ||
| 16 | inject_dependencies | ||
| 17 | perform_bundle_install unless options["skip-install"] | ||
| 18 | end | ||
| 19 | |||
| 20 | private | ||
| 21 | |||
| 22 | def perform_bundle_install | ||
| 23 | Installer.install(Bundler.root, Bundler.definition) | ||
| 24 | Bundler.load.cache if Bundler.app_cache.exist? | ||
| 25 | end | ||
| 26 | |||
| 27 | def inject_dependencies | ||
| 28 | dependencies = gems.map {|g| Bundler::Dependency.new(g, version, options) } | ||
| 29 | |||
| 30 | Injector.inject(dependencies, | ||
| 31 | :conservative_versioning => options[:version].nil?, # Perform conservative versioning only when version is not specified | ||
| 32 | :optimistic => options[:optimistic], | ||
| 33 | :strict => options[:strict]) | ||
| 34 | end | ||
| 35 | |||
| 36 | def validate_options! | ||
| 37 | raise InvalidOption, "You can not specify `--strict` and `--optimistic` at the same time." if options[:strict] && options[:optimistic] | ||
| 38 | |||
| 39 | # raise error when no gems are specified | ||
| 40 | raise InvalidOption, "Please specify gems to add." if gems.empty? | ||
| 41 | |||
| 42 | version.to_a.each do |v| | ||
| 43 | raise InvalidOption, "Invalid gem requirement pattern '#{v}'" unless Gem::Requirement::PATTERN =~ v.to_s | ||
| 44 | end | ||
| 45 | end | ||
| 46 | end | ||
| 47 | end |
| 1 | # frozen_string_literal: true | ||
| 2 | |||
| 3 | module Bundler | ||
| 4 | class CLI::Binstubs | ||
| 5 | attr_reader :options, :gems | ||
| 6 | def initialize(options, gems) | ||
| 7 | @options = options | ||
| 8 | @gems = gems | ||
| 9 | end | ||
| 10 | |||
| 11 | def run | ||
| 12 | Bundler.definition.validate_runtime! | ||
| 13 | path_option = options["path"] | ||
| 14 | path_option = nil if path_option && path_option.empty? | ||
| 15 | Bundler.settings.set_command_option :bin, path_option if options["path"] | ||
| 16 | Bundler.settings.set_command_option_if_given :shebang, options["shebang"] | ||
| 17 | installer = Installer.new(Bundler.root, Bundler.definition) | ||
| 18 | |||
| 19 | installer_opts = { | ||
| 20 | :force => options[:force], | ||
| 21 | :binstubs_cmd => true, | ||
| 22 | :all_platforms => options["all-platforms"], | ||
| 23 | } | ||
| 24 | |||
| 25 | if options[:all] | ||
| 26 | raise InvalidOption, "Cannot specify --all with specific gems" unless gems.empty? | ||
| 27 | @gems = Bundler.definition.specs.map(&:name) | ||
| 28 | installer_opts.delete(:binstubs_cmd) | ||
| 29 | elsif gems.empty? | ||
| 30 | Bundler.ui.error "`bundle binstubs` needs at least one gem to run." | ||
| 31 | exit 1 | ||
| 32 | end | ||
| 33 | |||
| 34 | gems.each do |gem_name| | ||
| 35 | spec = Bundler.definition.specs.find {|s| s.name == gem_name } | ||
| 36 | unless spec | ||
| 37 | raise GemNotFound, Bundler::CLI::Common.gem_not_found_message( | ||
| 38 | gem_name, Bundler.definition.specs | ||
| 39 | ) | ||
| 40 | end | ||
| 41 | |||
| 42 | if options[:standalone] | ||
| 43 | next Bundler.ui.warn("Sorry, Bundler can only be run via RubyGems.") if gem_name == "bundler" | ||
| 44 | Bundler.settings.temporary(:path => (Bundler.settings[:path] || Bundler.root)) do | ||
| 45 | installer.generate_standalone_bundler_executable_stubs(spec, installer_opts) | ||
| 46 | end | ||
| 47 | else | ||
| 48 | installer.generate_bundler_executable_stubs(spec, installer_opts) | ||
| 49 | end | ||
| 50 | end | ||
| 51 | end | ||
| 52 | end | ||
| 53 | end |
| 1 | # frozen_string_literal: true | ||
| 2 | |||
| 3 | module Bundler | ||
| 4 | class CLI::Cache | ||
| 5 | attr_reader :options | ||
| 6 | |||
| 7 | def initialize(options) | ||
| 8 | @options = options | ||
| 9 | end | ||
| 10 | |||
| 11 | def run | ||
| 12 | Bundler.ui.level = "warn" if options[:quiet] | ||
| 13 | Bundler.settings.set_command_option_if_given :path, options[:path] | ||
| 14 | Bundler.settings.set_command_option_if_given :cache_path, options["cache-path"] | ||
| 15 | |||
| 16 | setup_cache_all | ||
| 17 | install | ||
| 18 | |||
| 19 | # TODO: move cache contents here now that all bundles are locked | ||
| 20 | custom_path = Bundler.settings[:path] if options[:path] | ||
| 21 | |||
| 22 | Bundler.settings.temporary(:cache_all_platforms => options["all-platforms"]) do | ||
| 23 | Bundler.load.cache(custom_path) | ||
| 24 | end | ||
| 25 | end | ||
| 26 | |||
| 27 | private | ||
| 28 | |||
| 29 | def install | ||
| 30 | require_relative "install" | ||
| 31 | options = self.options.dup | ||
| 32 | options["local"] = false if Bundler.settings[:cache_all_platforms] | ||
| 33 | options["no-cache"] = true | ||
| 34 | Bundler::CLI::Install.new(options).run | ||
| 35 | end | ||
| 36 | |||
| 37 | def setup_cache_all | ||
| 38 | all = options.fetch(:all, Bundler.feature_flag.cache_all? || nil) | ||
| 39 | |||
| 40 | Bundler.settings.set_command_option_if_given :cache_all, all | ||
| 41 | end | ||
| 42 | end | ||
| 43 | end |
| 1 | # frozen_string_literal: true | ||
| 2 | |||
| 3 | module Bundler | ||
| 4 | class CLI::Check | ||
| 5 | attr_reader :options | ||
| 6 | |||
| 7 | def initialize(options) | ||
| 8 | @options = options | ||
| 9 | end | ||
| 10 | |||
| 11 | def run | ||
| 12 | Bundler.settings.set_command_option_if_given :path, options[:path] | ||
| 13 | |||
| 14 | definition = Bundler.definition | ||
| 15 | definition.validate_runtime! | ||
| 16 | |||
| 17 | begin | ||
| 18 | definition.resolve_only_locally! | ||
| 19 | not_installed = definition.missing_specs | ||
| 20 | rescue GemNotFound, VersionConflict | ||
| 21 | Bundler.ui.error "Bundler can't satisfy your Gemfile's dependencies." | ||
| 22 | Bundler.ui.warn "Install missing gems with `bundle install`." | ||
| 23 | exit 1 | ||
| 24 | end | ||
| 25 | |||
| 26 | if not_installed.any? | ||
| 27 | Bundler.ui.error "The following gems are missing" | ||
| 28 | not_installed.each {|s| Bundler.ui.error " * #{s.name} (#{s.version})" } | ||
| 29 | Bundler.ui.warn "Install missing gems with `bundle install`" | ||
| 30 | exit 1 | ||
| 31 | elsif !Bundler.default_lockfile.file? && Bundler.frozen_bundle? | ||
| 32 | Bundler.ui.error "This bundle has been frozen, but there is no #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)} present" | ||
| 33 | exit 1 | ||
| 34 | else | ||
| 35 | Bundler.load.lock(:preserve_unknown_sections => true) unless options[:"dry-run"] | ||
| 36 | Bundler.ui.info "The Gemfile's dependencies are satisfied" | ||
| 37 | end | ||
| 38 | end | ||
| 39 | end | ||
| 40 | end |
| 1 | # frozen_string_literal: true | ||
| 2 | |||
| 3 | module Bundler | ||
| 4 | class CLI::Clean | ||
| 5 | attr_reader :options | ||
| 6 | |||
| 7 | def initialize(options) | ||
| 8 | @options = options | ||
| 9 | end | ||
| 10 | |||
| 11 | def run | ||
| 12 | require_path_or_force unless options[:"dry-run"] | ||
| 13 | Bundler.load.clean(options[:"dry-run"]) | ||
| 14 | end | ||
| 15 | |||
| 16 | protected | ||
| 17 | |||
| 18 | def require_path_or_force | ||
| 19 | return unless Bundler.use_system_gems? && !options[:force] | ||
| 20 | raise InvalidOption, "Cleaning all the gems on your system is dangerous! " \ | ||
| 21 | "If you're sure you want to remove every system gem not in this " \ | ||
| 22 | "bundle, run `bundle clean --force`." | ||
| 23 | end | ||
| 24 | end | ||
| 25 | end |
| 1 | # frozen_string_literal: true | ||
| 2 | |||
| 3 | module Bundler | ||
| 4 | module CLI::Common | ||
| 5 | def self.output_post_install_messages(messages) | ||
| 6 | return if Bundler.settings["ignore_messages"] | ||
| 7 | messages.to_a.each do |name, msg| | ||
| 8 | print_post_install_message(name, msg) unless Bundler.settings["ignore_messages.#{name}"] | ||
| 9 | end | ||
| 10 | end | ||
| 11 | |||
| 12 | def self.print_post_install_message(name, msg) | ||
| 13 | Bundler.ui.confirm "Post-install message from #{name}:" | ||
| 14 | Bundler.ui.info msg | ||
| 15 | end | ||
| 16 | |||
| 17 | def self.output_fund_metadata_summary | ||
| 18 | return if Bundler.settings["ignore_funding_requests"] | ||
| 19 | definition = Bundler.definition | ||
| 20 | current_dependencies = definition.requested_dependencies | ||
| 21 | current_specs = definition.specs | ||
| 22 | |||
| 23 | count = current_dependencies.count {|dep| current_specs[dep.name].first.metadata.key?("funding_uri") } | ||
| 24 | |||
| 25 | return if count.zero? | ||
| 26 | |||
| 27 | intro = count > 1 ? "#{count} installed gems you directly depend on are" : "#{count} installed gem you directly depend on is" | ||
| 28 | message = "#{intro} looking for funding.\n Run `bundle fund` for details" | ||
| 29 | Bundler.ui.info message | ||
| 30 | end | ||
| 31 | |||
| 32 | def self.output_without_groups_message(command) | ||
| 33 | return if Bundler.settings[:without].empty? | ||
| 34 | Bundler.ui.confirm without_groups_message(command) | ||
| 35 | end | ||
| 36 | |||
| 37 | def self.without_groups_message(command) | ||
| 38 | command_in_past_tense = command == :install ? "installed" : "updated" | ||
| 39 | groups = Bundler.settings[:without] | ||
| 40 | "Gems in the #{verbalize_groups(groups)} were not #{command_in_past_tense}." | ||
| 41 | end | ||
| 42 | |||
| 43 | def self.verbalize_groups(groups) | ||
| 44 | groups.map! {|g| "'#{g}'" } | ||
| 45 | group_list = [groups[0...-1].join(", "), groups[-1..-1]]. | ||
| 46 | reject {|s| s.to_s.empty? }.join(" and ") | ||
| 47 | group_str = groups.size == 1 ? "group" : "groups" | ||
| 48 | "#{group_str} #{group_list}" | ||
| 49 | end | ||
| 50 | |||
| 51 | def self.select_spec(name, regex_match = nil) | ||
| 52 | specs = [] | ||
| 53 | regexp = Regexp.new(name) if regex_match | ||
| 54 | |||
| 55 | Bundler.definition.specs.each do |spec| | ||
| 56 | return spec if spec.name == name | ||
| 57 | specs << spec if regexp && spec.name =~ regexp | ||
| 58 | end | ||
| 59 | |||
| 60 | case specs.count | ||
| 61 | when 0 | ||
| 62 | dep_in_other_group = Bundler.definition.current_dependencies.find {|dep|dep.name == name } | ||
| 63 | |||
| 64 | if dep_in_other_group | ||
| 65 | raise GemNotFound, "Could not find gem '#{name}', because it's in the #{verbalize_groups(dep_in_other_group.groups)}, configured to be ignored." | ||
| 66 | else | ||
| 67 | raise GemNotFound, gem_not_found_message(name, Bundler.definition.dependencies) | ||
| 68 | end | ||
| 69 | when 1 | ||
| 70 | specs.first | ||
| 71 | else | ||
| 72 | ask_for_spec_from(specs) | ||
| 73 | end | ||
| 74 | rescue RegexpError | ||
| 75 | raise GemNotFound, gem_not_found_message(name, Bundler.definition.dependencies) | ||
| 76 | end | ||
| 77 | |||
| 78 | def self.ask_for_spec_from(specs) | ||
| 79 | specs.each_with_index do |spec, index| | ||
| 80 | Bundler.ui.info "#{index.succ} : #{spec.name}", true | ||
| 81 | end | ||
| 82 | Bundler.ui.info "0 : - exit -", true | ||
| 83 | |||
| 84 | num = Bundler.ui.ask("> ").to_i | ||
| 85 | num > 0 ? specs[num - 1] : nil | ||
| 86 | end | ||
| 87 | |||
| 88 | def self.gem_not_found_message(missing_gem_name, alternatives) | ||
| 89 | require_relative "../similarity_detector" | ||
| 90 | message = "Could not find gem '#{missing_gem_name}'." | ||
| 91 | alternate_names = alternatives.map {|a| a.respond_to?(:name) ? a.name : a } | ||
| 92 | suggestions = SimilarityDetector.new(alternate_names).similar_word_list(missing_gem_name) | ||
| 93 | message += "\nDid you mean #{suggestions}?" if suggestions | ||
| 94 | message | ||
| 95 | end | ||
| 96 | |||
| 97 | def self.ensure_all_gems_in_lockfile!(names, locked_gems = Bundler.locked_gems) | ||
| 98 | return unless locked_gems | ||
| 99 | |||
| 100 | locked_names = locked_gems.specs.map(&:name).uniq | ||
| 101 | names.-(locked_names).each do |g| | ||
| 102 | raise GemNotFound, gem_not_found_message(g, locked_names) | ||
| 103 | end | ||
| 104 | end | ||
| 105 | |||
| 106 | def self.configure_gem_version_promoter(definition, options) | ||
| 107 | patch_level = patch_level_options(options) | ||
| 108 | patch_level << :patch if patch_level.empty? && Bundler.settings[:prefer_patch] | ||
| 109 | raise InvalidOption, "Provide only one of the following options: #{patch_level.join(", ")}" unless patch_level.length <= 1 | ||
| 110 | |||
| 111 | definition.gem_version_promoter.tap do |gvp| | ||
| 112 | gvp.level = patch_level.first || :major | ||
| 113 | gvp.strict = options[:strict] || options["filter-strict"] | ||
| 114 | end | ||
| 115 | end | ||
| 116 | |||
| 117 | def self.patch_level_options(options) | ||
| 118 | [:major, :minor, :patch].select {|v| options.keys.include?(v.to_s) } | ||
| 119 | end | ||
| 120 | |||
| 121 | def self.clean_after_install? | ||
| 122 | clean = Bundler.settings[:clean] | ||
| 123 | return clean unless clean.nil? | ||
| 124 | clean ||= Bundler.feature_flag.auto_clean_without_path? && Bundler.settings[:path].nil? | ||
| 125 | clean &&= !Bundler.use_system_gems? | ||
| 126 | clean | ||
| 127 | end | ||
| 128 | end | ||
| 129 | end |
| 1 | # frozen_string_literal: true | ||
| 2 | |||
| 3 | module Bundler | ||
| 4 | class CLI::Config < Thor | ||
| 5 | class_option :parseable, :type => :boolean, :banner => "Use minimal formatting for more parseable output" | ||
| 6 | |||
| 7 | def self.scope_options | ||
| 8 | method_option :global, :type => :boolean, :banner => "Only change the global config" | ||
| 9 | method_option :local, :type => :boolean, :banner => "Only change the local config" | ||
| 10 | end | ||
| 11 | private_class_method :scope_options | ||
| 12 | |||
| 13 | desc "base NAME [VALUE]", "The Bundler 1 config interface", :hide => true | ||
| 14 | scope_options | ||
| 15 | method_option :delete, :type => :boolean, :banner => "delete" | ||
| 16 | def base(name = nil, *value) | ||
| 17 | new_args = | ||
| 18 | if ARGV.size == 1 | ||
| 19 | ["config", "list"] | ||
| 20 | elsif ARGV.include?("--delete") | ||
| 21 | ARGV.map {|arg| arg == "--delete" ? "unset" : arg } | ||
| 22 | elsif ARGV.include?("--global") || ARGV.include?("--local") || ARGV.size == 3 | ||
| 23 | ["config", "set", *ARGV[1..-1]] | ||
| 24 | else | ||
| 25 | ["config", "get", ARGV[1]] | ||
| 26 | end | ||
| 27 | |||
| 28 | SharedHelpers.major_deprecation 3, | ||
| 29 | "Using the `config` command without a subcommand [list, get, set, unset] is deprecated and will be removed in the future. Use `bundle #{new_args.join(" ")}` instead." | ||
| 30 | |||
| 31 | Base.new(options, name, value, self).run | ||
| 32 | end | ||
| 33 | |||
| 34 | desc "list", "List out all configured settings" | ||
| 35 | def list | ||
| 36 | Base.new(options, nil, nil, self).run | ||
| 37 | end | ||
| 38 | |||
| 39 | desc "get NAME", "Returns the value for the given key" | ||
| 40 | def get(name) | ||
| 41 | Base.new(options, name, nil, self).run | ||
| 42 | end | ||
| 43 | |||
| 44 | desc "set NAME VALUE", "Sets the given value for the given key" | ||
| 45 | scope_options | ||
| 46 | def set(name, value, *value_) | ||
| 47 | Base.new(options, name, value_.unshift(value), self).run | ||
| 48 | end | ||
| 49 | |||
| 50 | desc "unset NAME", "Unsets the value for the given key" | ||
| 51 | scope_options | ||
| 52 | def unset(name) | ||
| 53 | options[:delete] = true | ||
| 54 | Base.new(options, name, nil, self).run | ||
| 55 | end | ||
| 56 | |||
| 57 | default_task :base | ||
| 58 | |||
| 59 | class Base | ||
| 60 | attr_reader :name, :value, :options, :scope, :thor | ||
| 61 | |||
| 62 | def initialize(options, name, value, thor) | ||
| 63 | @options = options | ||
| 64 | @name = name | ||
| 65 | value = Array(value) | ||
| 66 | @value = value.empty? ? nil : value.join(" ") | ||
| 67 | @thor = thor | ||
| 68 | validate_scope! | ||
| 69 | end | ||
| 70 | |||
| 71 | def run | ||
| 72 | unless name | ||
| 73 | warn_unused_scope "Ignoring --#{scope}" | ||
| 74 | confirm_all | ||
| 75 | return | ||
| 76 | end | ||
| 77 | |||
| 78 | if options[:delete] | ||
| 79 | if !explicit_scope? || scope != "global" | ||
| 80 | Bundler.settings.set_local(name, nil) | ||
| 81 | end | ||
| 82 | if !explicit_scope? || scope != "local" | ||
| 83 | Bundler.settings.set_global(name, nil) | ||
| 84 | end | ||
| 85 | return | ||
| 86 | end | ||
| 87 | |||
| 88 | if value.nil? | ||
| 89 | warn_unused_scope "Ignoring --#{scope} since no value to set was given" | ||
| 90 | |||
| 91 | if options[:parseable] | ||
| 92 | if value = Bundler.settings[name] | ||
| 93 | Bundler.ui.info("#{name}=#{value}") | ||
| 94 | end | ||
| 95 | return | ||
| 96 | end | ||
| 97 | |||
| 98 | confirm(name) | ||
| 99 | return | ||
| 100 | end | ||
| 101 | |||
| 102 | Bundler.ui.info(message) if message | ||
| 103 | Bundler.settings.send("set_#{scope}", name, new_value) | ||
| 104 | end | ||
| 105 | |||
| 106 | def confirm_all | ||
| 107 | if @options[:parseable] | ||
| 108 | thor.with_padding do | ||
| 109 | Bundler.settings.all.each do |setting| | ||
| 110 | val = Bundler.settings[setting] | ||
| 111 | Bundler.ui.info "#{setting}=#{val}" | ||
| 112 | end | ||
| 113 | end | ||
| 114 | else | ||
| 115 | Bundler.ui.confirm "Settings are listed in order of priority. The top value will be used.\n" | ||
| 116 | Bundler.settings.all.each do |setting| | ||
| 117 | Bundler.ui.confirm setting | ||
| 118 | show_pretty_values_for(setting) | ||
| 119 | Bundler.ui.confirm "" | ||
| 120 | end | ||
| 121 | end | ||
| 122 | end | ||
| 123 | |||
| 124 | def confirm(name) | ||
| 125 | Bundler.ui.confirm "Settings for `#{name}` in order of priority. The top value will be used" | ||
| 126 | show_pretty_values_for(name) | ||
| 127 | end | ||
| 128 | |||
| 129 | def new_value | ||
| 130 | pathname = Pathname.new(value) | ||
| 131 | if name.start_with?("local.") && pathname.directory? | ||
| 132 | pathname.expand_path.to_s | ||
| 133 | else | ||
| 134 | value | ||
| 135 | end | ||
| 136 | end | ||
| 137 | |||
| 138 | def message | ||
| 139 | locations = Bundler.settings.locations(name) | ||
| 140 | if @options[:parseable] | ||
| 141 | "#{name}=#{new_value}" if new_value | ||
| 142 | elsif scope == "global" | ||
| 143 | if !locations[:local].nil? | ||
| 144 | "Your application has set #{name} to #{locations[:local].inspect}. " \ | ||
| 145 | "This will override the global value you are currently setting" | ||
| 146 | elsif locations[:env] | ||
| 147 | "You have a bundler environment variable for #{name} set to " \ | ||
| 148 | "#{locations[:env].inspect}. This will take precedence over the global value you are setting" | ||
| 149 | elsif !locations[:global].nil? && locations[:global] != value | ||
| 150 | "You are replacing the current global value of #{name}, which is currently " \ | ||
| 151 | "#{locations[:global].inspect}" | ||
| 152 | end | ||
| 153 | elsif scope == "local" && !locations[:local].nil? && locations[:local] != value | ||
| 154 | "You are replacing the current local value of #{name}, which is currently " \ | ||
| 155 | "#{locations[:local].inspect}" | ||
| 156 | end | ||
| 157 | end | ||
| 158 | |||
| 159 | def show_pretty_values_for(setting) | ||
| 160 | thor.with_padding do | ||
| 161 | Bundler.settings.pretty_values_for(setting).each do |line| | ||
| 162 | Bundler.ui.info line | ||
| 163 | end | ||
| 164 | end | ||
| 165 | end | ||
| 166 | |||
| 167 | def explicit_scope? | ||
| 168 | @explicit_scope | ||
| 169 | end | ||
| 170 | |||
| 171 | def warn_unused_scope(msg) | ||
| 172 | return unless explicit_scope? | ||
| 173 | return if options[:parseable] | ||
| 174 | |||
| 175 | Bundler.ui.warn(msg) | ||
| 176 | end | ||
| 177 | |||
| 178 | def validate_scope! | ||
| 179 | @explicit_scope = true | ||
| 180 | scopes = %w[global local].select {|s| options[s] } | ||
| 181 | case scopes.size | ||
| 182 | when 0 | ||
| 183 | @scope = inside_app? ? "local" : "global" | ||
| 184 | @explicit_scope = false | ||
| 185 | when 1 | ||
| 186 | @scope = scopes.first | ||
| 187 | else | ||
| 188 | raise InvalidOption, | ||
| 189 | "The options #{scopes.join " and "} were specified. Please only use one of the switches at a time." | ||
| 190 | end | ||
| 191 | end | ||
| 192 | |||
| 193 | private | ||
| 194 | |||
| 195 | def inside_app? | ||
| 196 | Bundler.root | ||
| 197 | true | ||
| 198 | rescue GemfileNotFound | ||
| 199 | false | ||
| 200 | end | ||
| 201 | end | ||
| 202 | end | ||
| 203 | end |
| 1 | # frozen_string_literal: true | ||
| 2 | |||
| 3 | module Bundler | ||
| 4 | class CLI::Console | ||
| 5 | attr_reader :options, :group | ||
| 6 | def initialize(options, group) | ||
| 7 | @options = options | ||
| 8 | @group = group | ||
| 9 | end | ||
| 10 | |||
| 11 | def run | ||
| 12 | Bundler::SharedHelpers.major_deprecation 2, "bundle console will be replaced " \ | ||
| 13 | "by `bin/console` generated by `bundle gem <name>`" | ||
| 14 | |||
| 15 | group ? Bundler.require(:default, *group.split(" ").map!(&:to_sym)) : Bundler.require | ||
| 16 | ARGV.clear | ||
| 17 | |||
| 18 | console = get_console(Bundler.settings[:console] || "irb") | ||
| 19 | console.start | ||
| 20 | end | ||
| 21 | |||
| 22 | def get_console(name) | ||
| 23 | require name | ||
| 24 | get_constant(name) | ||
| 25 | rescue LoadError | ||
| 26 | Bundler.ui.error "Couldn't load console #{name}, falling back to irb" | ||
| 27 | require "irb" | ||
| 28 | get_constant("irb") | ||
| 29 | end | ||
| 30 | |||
| 31 | def get_constant(name) | ||
| 32 | const_name = { | ||
| 33 | "pry" => :Pry, | ||
| 34 | "ripl" => :Ripl, | ||
| 35 | "irb" => :IRB, | ||
| 36 | }[name] | ||
| 37 | Object.const_get(const_name) | ||
| 38 | rescue NameError | ||
| 39 | Bundler.ui.error "Could not find constant #{const_name}" | ||
| 40 | exit 1 | ||
| 41 | end | ||
| 42 | end | ||
| 43 | end |
| 1 | # frozen_string_literal: true | ||
| 2 | |||
| 3 | require "rbconfig" | ||
| 4 | require "shellwords" | ||
| 5 | require "fiddle" | ||
| 6 | |||
| 7 | module Bundler | ||
| 8 | class CLI::Doctor | ||
| 9 | DARWIN_REGEX = /\s+(.+) \(compatibility /.freeze | ||
| 10 | LDD_REGEX = /\t\S+ => (\S+) \(\S+\)/.freeze | ||
| 11 | |||
| 12 | attr_reader :options | ||
| 13 | |||
| 14 | def initialize(options) | ||
| 15 | @options = options | ||
| 16 | end | ||
| 17 | |||
| 18 | def otool_available? | ||
| 19 | Bundler.which("otool") | ||
| 20 | end | ||
| 21 | |||
| 22 | def ldd_available? | ||
| 23 | Bundler.which("ldd") | ||
| 24 | end | ||
| 25 | |||
| 26 | def dylibs_darwin(path) | ||
| 27 | output = `/usr/bin/otool -L #{path.shellescape}`.chomp | ||
| 28 | dylibs = output.split("\n")[1..-1].map {|l| l.match(DARWIN_REGEX).captures[0] }.uniq | ||
| 29 | # ignore @rpath and friends | ||
| 30 | dylibs.reject {|dylib| dylib.start_with? "@" } | ||
| 31 | end | ||
| 32 | |||
| 33 | def dylibs_ldd(path) | ||
| 34 | output = `/usr/bin/ldd #{path.shellescape}`.chomp | ||
| 35 | output.split("\n").map do |l| | ||
| 36 | match = l.match(LDD_REGEX) | ||
| 37 | next if match.nil? | ||
| 38 | match.captures[0] | ||
| 39 | end.compact | ||
| 40 | end | ||
| 41 | |||
| 42 | def dylibs(path) | ||
| 43 | case RbConfig::CONFIG["host_os"] | ||
| 44 | when /darwin/ | ||
| 45 | return [] unless otool_available? | ||
| 46 | dylibs_darwin(path) | ||
| 47 | when /(linux|solaris|bsd)/ | ||
| 48 | return [] unless ldd_available? | ||
| 49 | dylibs_ldd(path) | ||
| 50 | else # Windows, etc. | ||
| 51 | Bundler.ui.warn("Dynamic library check not supported on this platform.") | ||
| 52 | [] | ||
| 53 | end | ||
| 54 | end | ||
| 55 | |||
| 56 | def bundles_for_gem(spec) | ||
| 57 | Dir.glob("#{spec.full_gem_path}/**/*.bundle") | ||
| 58 | end | ||
| 59 | |||
| 60 | def check! | ||
| 61 | require_relative "check" | ||
| 62 | Bundler::CLI::Check.new({}).run | ||
| 63 | end | ||
| 64 | |||
| 65 | def run | ||
| 66 | Bundler.ui.level = "warn" if options[:quiet] | ||
| 67 | Bundler.settings.validate! | ||
| 68 | check! | ||
| 69 | |||
| 70 | definition = Bundler.definition | ||
| 71 | broken_links = {} | ||
| 72 | |||
| 73 | definition.specs.each do |spec| | ||
| 74 | bundles_for_gem(spec).each do |bundle| | ||
| 75 | bad_paths = dylibs(bundle).select do |f| | ||
| 76 | begin | ||
| 77 | Fiddle.dlopen(f) | ||
| 78 | false | ||
| 79 | rescue Fiddle::DLError | ||
| 80 | true | ||
| 81 | end | ||
| 82 | end | ||
| 83 | if bad_paths.any? | ||
| 84 | broken_links[spec] ||= [] | ||
| 85 | broken_links[spec].concat(bad_paths) | ||
| 86 | end | ||
| 87 | end | ||
| 88 | end | ||
| 89 | |||
| 90 | permissions_valid = check_home_permissions | ||
| 91 | |||
| 92 | if broken_links.any? | ||
| 93 | message = "The following gems are missing OS dependencies:" | ||
| 94 | broken_links.map do |spec, paths| | ||
| 95 | paths.uniq.map do |path| | ||
| 96 | "\n * #{spec.name}: #{path}" | ||
| 97 | end | ||
| 98 | end.flatten.sort.each {|m| message += m } | ||
| 99 | raise ProductionError, message | ||
| 100 | elsif !permissions_valid | ||
| 101 | Bundler.ui.info "No issues found with the installed bundle" | ||
| 102 | end | ||
| 103 | end | ||
| 104 | |||
| 105 | private | ||
| 106 | |||
| 107 | def check_home_permissions | ||
| 108 | require "find" | ||
| 109 | files_not_readable_or_writable = [] | ||
| 110 | files_not_rw_and_owned_by_different_user = [] | ||
| 111 | files_not_owned_by_current_user_but_still_rw = [] | ||
| 112 | broken_symlinks = [] | ||
| 113 | Find.find(Bundler.bundle_path.to_s).each do |f| | ||
| 114 | if !File.exist?(f) | ||
| 115 | broken_symlinks << f | ||
| 116 | elsif !File.writable?(f) || !File.readable?(f) | ||
| 117 | if File.stat(f).uid != Process.uid | ||
| 118 | files_not_rw_and_owned_by_different_user << f | ||
| 119 | else | ||
| 120 | files_not_readable_or_writable << f | ||
| 121 | end | ||
| 122 | elsif File.stat(f).uid != Process.uid | ||
| 123 | files_not_owned_by_current_user_but_still_rw << f | ||
| 124 | end | ||
| 125 | end | ||
| 126 | |||
| 127 | ok = true | ||
| 128 | |||
| 129 | if broken_symlinks.any? | ||
| 130 | Bundler.ui.warn "Broken links exist in the Bundler home. Please report them to the offending gem's upstream repo. These files are:\n - #{broken_symlinks.join("\n - ")}" | ||
| 131 | |||
| 132 | ok = false | ||
| 133 | end | ||
| 134 | |||
| 135 | if files_not_owned_by_current_user_but_still_rw.any? | ||
| 136 | Bundler.ui.warn "Files exist in the Bundler home that are owned by another " \ | ||
| 137 | "user, but are still readable/writable. These files are:\n - #{files_not_owned_by_current_user_but_still_rw.join("\n - ")}" | ||
| 138 | |||
| 139 | ok = false | ||
| 140 | end | ||
| 141 | |||
| 142 | if files_not_rw_and_owned_by_different_user.any? | ||
| 143 | Bundler.ui.warn "Files exist in the Bundler home that are owned by another " \ | ||
| 144 | "user, and are not readable/writable. These files are:\n - #{files_not_rw_and_owned_by_different_user.join("\n - ")}" | ||
| 145 | |||
| 146 | ok = false | ||
| 147 | end | ||
| 148 | |||
| 149 | if files_not_readable_or_writable.any? | ||
| 150 | Bundler.ui.warn "Files exist in the Bundler home that are not " \ | ||
| 151 | "readable/writable by the current user. These files are:\n - #{files_not_readable_or_writable.join("\n - ")}" | ||
| 152 | |||
| 153 | ok = false | ||
| 154 | end | ||
| 155 | |||
| 156 | ok | ||
| 157 | end | ||
| 158 | end | ||
| 159 | end |
| 1 | # frozen_string_literal: true | ||
| 2 | |||
| 3 | require_relative "../current_ruby" | ||
| 4 | |||
| 5 | module Bundler | ||
| 6 | class CLI::Exec | ||
| 7 | attr_reader :options, :args, :cmd | ||
| 8 | |||
| 9 | TRAPPED_SIGNALS = %w[INT].freeze | ||
| 10 | |||
| 11 | def initialize(options, args) | ||
| 12 | @options = options | ||
| 13 | @cmd = args.shift | ||
| 14 | @args = args | ||
| 15 | @args << { :close_others => !options.keep_file_descriptors? } unless Bundler.current_ruby.jruby? | ||
| 16 | end | ||
| 17 | |||
| 18 | def run | ||
| 19 | validate_cmd! | ||
| 20 | SharedHelpers.set_bundle_environment | ||
| 21 | if bin_path = Bundler.which(cmd) | ||
| 22 | if !Bundler.settings[:disable_exec_load] && ruby_shebang?(bin_path) | ||
| 23 | return kernel_load(bin_path, *args) | ||
| 24 | end | ||
| 25 | kernel_exec(bin_path, *args) | ||
| 26 | else | ||
| 27 | # exec using the given command | ||
| 28 | kernel_exec(cmd, *args) | ||
| 29 | end | ||
| 30 | end | ||
| 31 | |||
| 32 | private | ||
| 33 | |||
| 34 | def validate_cmd! | ||
| 35 | return unless cmd.nil? | ||
| 36 | Bundler.ui.error "bundler: exec needs a command to run" | ||
| 37 | exit 128 | ||
| 38 | end | ||
| 39 | |||
| 40 | def kernel_exec(*args) | ||
| 41 | Kernel.exec(*args) | ||
| 42 | rescue Errno::EACCES, Errno::ENOEXEC | ||
| 43 | Bundler.ui.error "bundler: not executable: #{cmd}" | ||
| 44 | exit 126 | ||
| 45 | rescue Errno::ENOENT | ||
| 46 | Bundler.ui.error "bundler: command not found: #{cmd}" | ||
| 47 | Bundler.ui.warn "Install missing gem executables with `bundle install`" | ||
| 48 | exit 127 | ||
| 49 | end | ||
| 50 | |||
| 51 | def kernel_load(file, *args) | ||
| 52 | args.pop if args.last.is_a?(Hash) | ||
| 53 | ARGV.replace(args) | ||
| 54 | $0 = file | ||
| 55 | Process.setproctitle(process_title(file, args)) if Process.respond_to?(:setproctitle) | ||
| 56 | require_relative "../setup" | ||
| 57 | TRAPPED_SIGNALS.each {|s| trap(s, "DEFAULT") } | ||
| 58 | Kernel.load(file) | ||
| 59 | rescue SystemExit, SignalException | ||
| 60 | raise | ||
| 61 | rescue Exception # rubocop:disable Lint/RescueException | ||
| 62 | Bundler.ui.error "bundler: failed to load command: #{cmd} (#{file})" | ||
| 63 | Bundler::FriendlyErrors.disable! | ||
| 64 | raise | ||
| 65 | end | ||
| 66 | |||
| 67 | def process_title(file, args) | ||
| 68 | "#{file} #{args.join(" ")}".strip | ||
| 69 | end | ||
| 70 | |||
| 71 | def ruby_shebang?(file) | ||
| 72 | possibilities = [ | ||
| 73 | "#!/usr/bin/env ruby\n", | ||
| 74 | "#!/usr/bin/env jruby\n", | ||
| 75 | "#!/usr/bin/env truffleruby\n", | ||
| 76 | "#!#{Gem.ruby}\n", | ||
| 77 | ] | ||
| 78 | |||
| 79 | if File.zero?(file) | ||
| 80 | Bundler.ui.warn "#{file} is empty" | ||
| 81 | return false | ||
| 82 | end | ||
| 83 | |||
| 84 | first_line = File.open(file, "rb") {|f| f.read(possibilities.map(&:size).max) } | ||
| 85 | possibilities.any? {|shebang| first_line.start_with?(shebang) } | ||
| 86 | end | ||
| 87 | end | ||
| 88 | end |
| 1 | # frozen_string_literal: true | ||
| 2 | |||
| 3 | module Bundler | ||
| 4 | class CLI::Fund | ||
| 5 | attr_reader :options | ||
| 6 | |||
| 7 | def initialize(options) | ||
| 8 | @options = options | ||
| 9 | end | ||
| 10 | |||
| 11 | def run | ||
| 12 | Bundler.definition.validate_runtime! | ||
| 13 | |||
| 14 | groups = Array(options[:group]).map(&:to_sym) | ||
| 15 | |||
| 16 | deps = if groups.any? | ||
| 17 | Bundler.definition.dependencies_for(groups) | ||
| 18 | else | ||
| 19 | Bundler.definition.current_dependencies | ||
| 20 | end | ||
| 21 | |||
| 22 | fund_info = deps.each_with_object([]) do |dep, arr| | ||
| 23 | spec = Bundler.definition.specs[dep.name].first | ||
| 24 | if spec.metadata.key?("funding_uri") | ||
| 25 | arr << "* #{spec.name} (#{spec.version})\n Funding: #{spec.metadata["funding_uri"]}" | ||
| 26 | end | ||
| 27 | end | ||
| 28 | |||
| 29 | if fund_info.empty? | ||
| 30 | Bundler.ui.info "None of the installed gems you directly depend on are looking for funding." | ||
| 31 | else | ||
| 32 | Bundler.ui.info fund_info.join("\n") | ||
| 33 | end | ||
| 34 | end | ||
| 35 | end | ||
| 36 | end |
This diff is collapsed.
Click to expand it.
| 1 | # frozen_string_literal: true | ||
| 2 | |||
| 3 | module Bundler | ||
| 4 | class CLI::Info | ||
| 5 | attr_reader :gem_name, :options | ||
| 6 | def initialize(options, gem_name) | ||
| 7 | @options = options | ||
| 8 | @gem_name = gem_name | ||
| 9 | end | ||
| 10 | |||
| 11 | def run | ||
| 12 | Bundler.ui.silence do | ||
| 13 | Bundler.definition.validate_runtime! | ||
| 14 | Bundler.load.lock | ||
| 15 | end | ||
| 16 | |||
| 17 | spec = spec_for_gem(gem_name) | ||
| 18 | |||
| 19 | if spec | ||
| 20 | return print_gem_path(spec) if @options[:path] | ||
| 21 | return print_gem_version(spec) if @options[:version] | ||
| 22 | print_gem_info(spec) | ||
| 23 | end | ||
| 24 | end | ||
| 25 | |||
| 26 | private | ||
| 27 | |||
| 28 | def spec_for_gem(gem_name) | ||
| 29 | spec = Bundler.definition.specs.find {|s| s.name == gem_name } | ||
| 30 | spec || default_gem_spec(gem_name) || Bundler::CLI::Common.select_spec(gem_name, :regex_match) | ||
| 31 | end | ||
| 32 | |||
| 33 | def default_gem_spec(gem_name) | ||
| 34 | return unless Gem::Specification.respond_to?(:find_all_by_name) | ||
| 35 | gem_spec = Gem::Specification.find_all_by_name(gem_name).last | ||
| 36 | return gem_spec if gem_spec && gem_spec.respond_to?(:default_gem?) && gem_spec.default_gem? | ||
| 37 | end | ||
| 38 | |||
| 39 | def spec_not_found(gem_name) | ||
| 40 | raise GemNotFound, Bundler::CLI::Common.gem_not_found_message(gem_name, Bundler.definition.dependencies) | ||
| 41 | end | ||
| 42 | |||
| 43 | def print_gem_version(spec) | ||
| 44 | Bundler.ui.info spec.version.to_s | ||
| 45 | end | ||
| 46 | |||
| 47 | def print_gem_path(spec) | ||
| 48 | name = spec.name | ||
| 49 | if name == "bundler" | ||
| 50 | path = File.expand_path("../../..", __dir__) | ||
| 51 | else | ||
| 52 | path = spec.full_gem_path | ||
| 53 | if spec.deleted_gem? | ||
| 54 | return Bundler.ui.warn "The gem #{name} has been deleted. It was installed at: #{path}" | ||
| 55 | end | ||
| 56 | end | ||
| 57 | |||
| 58 | Bundler.ui.info path | ||
| 59 | end | ||
| 60 | |||
| 61 | def print_gem_info(spec) | ||
| 62 | metadata = spec.metadata | ||
| 63 | name = spec.name | ||
| 64 | gem_info = String.new | ||
| 65 | gem_info << " * #{name} (#{spec.version}#{spec.git_version})\n" | ||
| 66 | gem_info << "\tSummary: #{spec.summary}\n" if spec.summary | ||
| 67 | gem_info << "\tHomepage: #{spec.homepage}\n" if spec.homepage | ||
| 68 | gem_info << "\tDocumentation: #{metadata["documentation_uri"]}\n" if metadata.key?("documentation_uri") | ||
| 69 | gem_info << "\tSource Code: #{metadata["source_code_uri"]}\n" if metadata.key?("source_code_uri") | ||
| 70 | gem_info << "\tFunding: #{metadata["funding_uri"]}\n" if metadata.key?("funding_uri") | ||
| 71 | gem_info << "\tWiki: #{metadata["wiki_uri"]}\n" if metadata.key?("wiki_uri") | ||
| 72 | gem_info << "\tChangelog: #{metadata["changelog_uri"]}\n" if metadata.key?("changelog_uri") | ||
| 73 | gem_info << "\tBug Tracker: #{metadata["bug_tracker_uri"]}\n" if metadata.key?("bug_tracker_uri") | ||
| 74 | gem_info << "\tMailing List: #{metadata["mailing_list_uri"]}\n" if metadata.key?("mailing_list_uri") | ||
| 75 | gem_info << "\tPath: #{spec.full_gem_path}\n" | ||
| 76 | gem_info << "\tDefault Gem: yes\n" if spec.respond_to?(:default_gem?) && spec.default_gem? | ||
| 77 | gem_info << "\tReverse Dependencies: \n\t\t#{gem_dependencies.join("\n\t\t")}" if gem_dependencies.any? | ||
| 78 | |||
| 79 | if name != "bundler" && spec.deleted_gem? | ||
| 80 | return Bundler.ui.warn "The gem #{name} has been deleted. Gemspec information is still available though:\n#{gem_info}" | ||
| 81 | end | ||
| 82 | |||
| 83 | Bundler.ui.info gem_info | ||
| 84 | end | ||
| 85 | |||
| 86 | def gem_dependencies | ||
| 87 | @gem_dependencies ||= Bundler.definition.specs.map do |spec| | ||
| 88 | dependency = spec.dependencies.find {|dep| dep.name == gem_name } | ||
| 89 | next unless dependency | ||
| 90 | "#{spec.name} (#{spec.version}) depends on #{gem_name} (#{dependency.requirements_list.join(", ")})" | ||
| 91 | end.compact.sort | ||
| 92 | end | ||
| 93 | end | ||
| 94 | end |
| 1 | # frozen_string_literal: true | ||
| 2 | |||
| 3 | module Bundler | ||
| 4 | class CLI::Init | ||
| 5 | attr_reader :options | ||
| 6 | def initialize(options) | ||
| 7 | @options = options | ||
| 8 | end | ||
| 9 | |||
| 10 | def run | ||
| 11 | if File.exist?(gemfile) | ||
| 12 | Bundler.ui.error "#{gemfile} already exists at #{File.expand_path(gemfile)}" | ||
| 13 | exit 1 | ||
| 14 | end | ||
| 15 | |||
| 16 | unless File.writable?(Dir.pwd) | ||
| 17 | Bundler.ui.error "Can not create #{gemfile} as the current directory is not writable." | ||
| 18 | exit 1 | ||
| 19 | end | ||
| 20 | |||
| 21 | if options[:gemspec] | ||
| 22 | gemspec = File.expand_path(options[:gemspec]) | ||
| 23 | unless File.exist?(gemspec) | ||
| 24 | Bundler.ui.error "Gem specification #{gemspec} doesn't exist" | ||
| 25 | exit 1 | ||
| 26 | end | ||
| 27 | |||
| 28 | spec = Bundler.load_gemspec_uncached(gemspec) | ||
| 29 | |||
| 30 | File.open(gemfile, "wb") do |file| | ||
| 31 | file << "# Generated from #{gemspec}\n" | ||
| 32 | file << spec.to_gemfile | ||
| 33 | end | ||
| 34 | else | ||
| 35 | FileUtils.cp(File.expand_path("../templates/#{gemfile}", __dir__), gemfile) | ||
| 36 | end | ||
| 37 | |||
| 38 | puts "Writing new #{gemfile} to #{SharedHelpers.pwd}/#{gemfile}" | ||
| 39 | end | ||
| 40 | |||
| 41 | private | ||
| 42 | |||
| 43 | def gemfile | ||
| 44 | @gemfile ||= Bundler.preferred_gemfile_name | ||
| 45 | end | ||
| 46 | end | ||
| 47 | end |
| 1 | # frozen_string_literal: true | ||
| 2 | |||
| 3 | module Bundler | ||
| 4 | class CLI::Inject | ||
| 5 | attr_reader :options, :name, :version, :group, :source, :gems | ||
| 6 | def initialize(options, name, version) | ||
| 7 | @options = options | ||
| 8 | @name = name | ||
| 9 | @version = version || last_version_number | ||
| 10 | @group = options[:group].split(",") unless options[:group].nil? | ||
| 11 | @source = options[:source] | ||
| 12 | @gems = [] | ||
| 13 | end | ||
| 14 | |||
| 15 | def run | ||
| 16 | # The required arguments allow Thor to give useful feedback when the arguments | ||
| 17 | # are incorrect. This adds those first two arguments onto the list as a whole. | ||
| 18 | gems.unshift(source).unshift(group).unshift(version).unshift(name) | ||
| 19 | |||
| 20 | # Build an array of Dependency objects out of the arguments | ||
| 21 | deps = [] | ||
| 22 | # when `inject` support addition of more than one gem, then this loop will | ||
| 23 | # help. Currently this loop is running once. | ||
| 24 | gems.each_slice(4) do |gem_name, gem_version, gem_group, gem_source| | ||
| 25 | ops = Gem::Requirement::OPS.map {|key, _val| key } | ||
| 26 | has_op = ops.any? {|op| gem_version.start_with? op } | ||
| 27 | gem_version = "~> #{gem_version}" unless has_op | ||
| 28 | deps << Bundler::Dependency.new(gem_name, gem_version, "group" => gem_group, "source" => gem_source) | ||
| 29 | end | ||
| 30 | |||
| 31 | added = Injector.inject(deps, options) | ||
| 32 | |||
| 33 | if added.any? | ||
| 34 | Bundler.ui.confirm "Added to Gemfile:" | ||
| 35 | Bundler.ui.confirm(added.map do |d| | ||
| 36 | name = "'#{d.name}'" | ||
| 37 | requirement = ", '#{d.requirement}'" | ||
| 38 | group = ", :group => #{d.groups.inspect}" if d.groups != Array(:default) | ||
| 39 | source = ", :source => '#{d.source}'" unless d.source.nil? | ||
| 40 | %(gem #{name}#{requirement}#{group}#{source}) | ||
| 41 | end.join("\n")) | ||
| 42 | else | ||
| 43 | Bundler.ui.confirm "All gems were already present in the Gemfile" | ||
| 44 | end | ||
| 45 | end | ||
| 46 | |||
| 47 | private | ||
| 48 | |||
| 49 | def last_version_number | ||
| 50 | definition = Bundler.definition(true) | ||
| 51 | definition.resolve_remotely! | ||
| 52 | specs = definition.index[name].sort_by(&:version) | ||
| 53 | unless options[:pre] | ||
| 54 | specs.delete_if {|b| b.respond_to?(:version) && b.version.prerelease? } | ||
| 55 | end | ||
| 56 | spec = specs.last | ||
| 57 | spec.version.to_s | ||
| 58 | end | ||
| 59 | end | ||
| 60 | end |
| 1 | # frozen_string_literal: true | ||
| 2 | |||
| 3 | module Bundler | ||
| 4 | class CLI::Install | ||
| 5 | attr_reader :options | ||
| 6 | def initialize(options) | ||
| 7 | @options = options | ||
| 8 | end | ||
| 9 | |||
| 10 | def run | ||
| 11 | Bundler.ui.level = "warn" if options[:quiet] | ||
| 12 | |||
| 13 | warn_if_root | ||
| 14 | |||
| 15 | Bundler.self_manager.install_locked_bundler_and_restart_with_it_if_needed | ||
| 16 | |||
| 17 | Bundler::SharedHelpers.set_env "RB_USER_INSTALL", "1" if Bundler::FREEBSD | ||
| 18 | |||
| 19 | # Disable color in deployment mode | ||
| 20 | Bundler.ui.shell = Thor::Shell::Basic.new if options[:deployment] | ||
| 21 | |||
| 22 | check_for_options_conflicts | ||
| 23 | |||
| 24 | check_trust_policy | ||
| 25 | |||
| 26 | if options[:deployment] || options[:frozen] || Bundler.frozen_bundle? | ||
| 27 | unless Bundler.default_lockfile.exist? | ||
| 28 | flag = "--deployment flag" if options[:deployment] | ||
| 29 | flag ||= "--frozen flag" if options[:frozen] | ||
| 30 | flag ||= "deployment setting" | ||
| 31 | raise ProductionError, "The #{flag} requires a #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)}. Please make " \ | ||
| 32 | "sure you have checked your #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)} into version control " \ | ||
| 33 | "before deploying." | ||
| 34 | end | ||
| 35 | |||
| 36 | options[:local] = true if Bundler.app_cache.exist? | ||
| 37 | |||
| 38 | Bundler.settings.set_command_option :deployment, true if options[:deployment] | ||
| 39 | Bundler.settings.set_command_option :frozen, true if options[:frozen] | ||
| 40 | end | ||
| 41 | |||
| 42 | # When install is called with --no-deployment, disable deployment mode | ||
| 43 | if options[:deployment] == false | ||
| 44 | Bundler.settings.set_command_option :frozen, nil | ||
| 45 | options[:system] = true | ||
| 46 | end | ||
| 47 | |||
| 48 | normalize_settings | ||
| 49 | |||
| 50 | Bundler::Fetcher.disable_endpoint = options["full-index"] | ||
| 51 | |||
| 52 | if options["binstubs"] | ||
| 53 | Bundler::SharedHelpers.major_deprecation 2, | ||
| 54 | "The --binstubs option will be removed in favor of `bundle binstubs --all`" | ||
| 55 | end | ||
| 56 | |||
| 57 | Plugin.gemfile_install(Bundler.default_gemfile) if Bundler.feature_flag.plugins? | ||
| 58 | |||
| 59 | definition = Bundler.definition | ||
| 60 | definition.validate_runtime! | ||
| 61 | |||
| 62 | installer = Installer.install(Bundler.root, definition, options) | ||
| 63 | |||
| 64 | Bundler.settings.temporary(:cache_all_platforms => options[:local] ? false : Bundler.settings[:cache_all_platforms]) do | ||
| 65 | Bundler.load.cache(nil, options[:local]) if Bundler.app_cache.exist? && !options["no-cache"] && !Bundler.frozen_bundle? | ||
| 66 | end | ||
| 67 | |||
| 68 | Bundler.ui.confirm "Bundle complete! #{dependencies_count_for(definition)}, #{gems_installed_for(definition)}." | ||
| 69 | Bundler::CLI::Common.output_without_groups_message(:install) | ||
| 70 | |||
| 71 | if Bundler.use_system_gems? | ||
| 72 | Bundler.ui.confirm "Use `bundle info [gemname]` to see where a bundled gem is installed." | ||
| 73 | else | ||
| 74 | relative_path = Bundler.configured_bundle_path.base_path_relative_to_pwd | ||
| 75 | Bundler.ui.confirm "Bundled gems are installed into `#{relative_path}`" | ||
| 76 | end | ||
| 77 | |||
| 78 | Bundler::CLI::Common.output_post_install_messages installer.post_install_messages | ||
| 79 | |||
| 80 | warn_ambiguous_gems | ||
| 81 | |||
| 82 | if CLI::Common.clean_after_install? | ||
| 83 | require_relative "clean" | ||
| 84 | Bundler::CLI::Clean.new(options).run | ||
| 85 | end | ||
| 86 | |||
| 87 | Bundler::CLI::Common.output_fund_metadata_summary | ||
| 88 | rescue Gem::InvalidSpecificationException | ||
| 89 | Bundler.ui.warn "You have one or more invalid gemspecs that need to be fixed." | ||
| 90 | raise | ||
| 91 | end | ||
| 92 | |||
| 93 | private | ||
| 94 | |||
| 95 | def warn_if_root | ||
| 96 | return if Bundler.settings[:silence_root_warning] || Gem.win_platform? || !Process.uid.zero? | ||
| 97 | Bundler.ui.warn "Don't run Bundler as root. Bundler can ask for sudo " \ | ||
| 98 | "if it is needed, and installing your bundle as root will break this " \ | ||
| 99 | "application for all non-root users on this machine.", :wrap => true | ||
| 100 | end | ||
| 101 | |||
| 102 | def dependencies_count_for(definition) | ||
| 103 | count = definition.dependencies.count | ||
| 104 | "#{count} Gemfile #{count == 1 ? "dependency" : "dependencies"}" | ||
| 105 | end | ||
| 106 | |||
| 107 | def gems_installed_for(definition) | ||
| 108 | count = definition.specs.count | ||
| 109 | "#{count} #{count == 1 ? "gem" : "gems"} now installed" | ||
| 110 | end | ||
| 111 | |||
| 112 | def check_for_group_conflicts_in_cli_options | ||
| 113 | conflicting_groups = Array(options[:without]) & Array(options[:with]) | ||
| 114 | return if conflicting_groups.empty? | ||
| 115 | raise InvalidOption, "You can't list a group in both with and without." \ | ||
| 116 | " The offending groups are: #{conflicting_groups.join(", ")}." | ||
| 117 | end | ||
| 118 | |||
| 119 | def check_for_options_conflicts | ||
| 120 | if (options[:path] || options[:deployment]) && options[:system] | ||
| 121 | error_message = String.new | ||
| 122 | error_message << "You have specified both --path as well as --system. Please choose only one option.\n" if options[:path] | ||
| 123 | error_message << "You have specified both --deployment as well as --system. Please choose only one option.\n" if options[:deployment] | ||
| 124 | raise InvalidOption.new(error_message) | ||
| 125 | end | ||
| 126 | end | ||
| 127 | |||
| 128 | def check_trust_policy | ||
| 129 | trust_policy = options["trust-policy"] | ||
| 130 | unless Bundler.rubygems.security_policies.keys.unshift(nil).include?(trust_policy) | ||
| 131 | raise InvalidOption, "RubyGems doesn't know about trust policy '#{trust_policy}'. " \ | ||
| 132 | "The known policies are: #{Bundler.rubygems.security_policies.keys.join(", ")}." | ||
| 133 | end | ||
| 134 | Bundler.settings.set_command_option_if_given :"trust-policy", trust_policy | ||
| 135 | end | ||
| 136 | |||
| 137 | def normalize_groups | ||
| 138 | check_for_group_conflicts_in_cli_options | ||
| 139 | |||
| 140 | # need to nil them out first to get around validation for backwards compatibility | ||
| 141 | Bundler.settings.set_command_option :without, nil | ||
| 142 | Bundler.settings.set_command_option :with, nil | ||
| 143 | Bundler.settings.set_command_option :without, options[:without] | ||
| 144 | Bundler.settings.set_command_option :with, options[:with] | ||
| 145 | end | ||
| 146 | |||
| 147 | def normalize_settings | ||
| 148 | Bundler.settings.set_command_option :path, nil if options[:system] | ||
| 149 | Bundler.settings.set_command_option_if_given :path, options[:path] | ||
| 150 | |||
| 151 | if options["standalone"] && Bundler.settings[:path].nil? && !options["local"] | ||
| 152 | Bundler.settings.temporary(:path_relative_to_cwd => false) do | ||
| 153 | Bundler.settings.set_command_option :path, "bundle" | ||
| 154 | end | ||
| 155 | end | ||
| 156 | |||
| 157 | bin_option = options["binstubs"] | ||
| 158 | bin_option = nil if bin_option && bin_option.empty? | ||
| 159 | Bundler.settings.set_command_option :bin, bin_option if options["binstubs"] | ||
| 160 | |||
| 161 | Bundler.settings.set_command_option_if_given :shebang, options["shebang"] | ||
| 162 | |||
| 163 | Bundler.settings.set_command_option_if_given :jobs, options["jobs"] | ||
| 164 | |||
| 165 | Bundler.settings.set_command_option_if_given :no_prune, options["no-prune"] | ||
| 166 | |||
| 167 | Bundler.settings.set_command_option_if_given :no_install, options["no-install"] | ||
| 168 | |||
| 169 | Bundler.settings.set_command_option_if_given :clean, options["clean"] | ||
| 170 | |||
| 171 | normalize_groups if options[:without] || options[:with] | ||
| 172 | |||
| 173 | options[:force] = options[:redownload] | ||
| 174 | end | ||
| 175 | |||
| 176 | def warn_ambiguous_gems | ||
| 177 | # TODO: remove this when we drop Bundler 1.x support | ||
| 178 | Installer.ambiguous_gems.to_a.each do |name, installed_from_uri, *also_found_in_uris| | ||
| 179 | Bundler.ui.warn "Warning: the gem '#{name}' was found in multiple sources." | ||
| 180 | Bundler.ui.warn "Installed from: #{installed_from_uri}" | ||
| 181 | Bundler.ui.warn "Also found in:" | ||
| 182 | also_found_in_uris.each {|uri| Bundler.ui.warn " * #{uri}" } | ||
| 183 | Bundler.ui.warn "You should add a source requirement to restrict this gem to your preferred source." | ||
| 184 | Bundler.ui.warn "For example:" | ||
| 185 | Bundler.ui.warn " gem '#{name}', :source => '#{installed_from_uri}'" | ||
| 186 | Bundler.ui.warn "Then uninstall the gem '#{name}' (or delete all bundled gems) and then install again." | ||
| 187 | end | ||
| 188 | end | ||
| 189 | end | ||
| 190 | end |
| 1 | # frozen_string_literal: true | ||
| 2 | |||
| 3 | require "rbconfig" | ||
| 4 | |||
| 5 | module Bundler | ||
| 6 | class CLI::Issue | ||
| 7 | def run | ||
| 8 | Bundler.ui.info <<-EOS.gsub(/^ {8}/, "") | ||
| 9 | Did you find an issue with Bundler? Before filing a new issue, | ||
| 10 | be sure to check out these resources: | ||
| 11 | |||
| 12 | 1. Check out our troubleshooting guide for quick fixes to common issues: | ||
| 13 | https://github.com/rubygems/rubygems/blob/master/bundler/doc/TROUBLESHOOTING.md | ||
| 14 | |||
| 15 | 2. Instructions for common Bundler uses can be found on the documentation | ||
| 16 | site: https://bundler.io/ | ||
| 17 | |||
| 18 | 3. Information about each Bundler command can be found in the Bundler | ||
| 19 | man pages: https://bundler.io/man/bundle.1.html | ||
| 20 | |||
| 21 | Hopefully the troubleshooting steps above resolved your problem! If things | ||
| 22 | still aren't working the way you expect them to, please let us know so | ||
| 23 | that we can diagnose and help fix the problem you're having, by filling | ||
| 24 | in the new issue form located at | ||
| 25 | https://github.com/rubygems/rubygems/issues/new?labels=Bundler&template=bundler-related-issue.md, | ||
| 26 | and copy and pasting the information below. | ||
| 27 | |||
| 28 | EOS | ||
| 29 | |||
| 30 | Bundler.ui.info Bundler::Env.report | ||
| 31 | |||
| 32 | Bundler.ui.info "\n## Bundle Doctor" | ||
| 33 | doctor | ||
| 34 | end | ||
| 35 | |||
| 36 | def doctor | ||
| 37 | require_relative "doctor" | ||
| 38 | Bundler::CLI::Doctor.new({}).run | ||
| 39 | end | ||
| 40 | end | ||
| 41 | end |
| 1 | # frozen_string_literal: true | ||
| 2 | |||
| 3 | module Bundler | ||
| 4 | class CLI::List | ||
| 5 | def initialize(options) | ||
| 6 | @options = options | ||
| 7 | @without_group = options["without-group"].map(&:to_sym) | ||
| 8 | @only_group = options["only-group"].map(&:to_sym) | ||
| 9 | end | ||
| 10 | |||
| 11 | def run | ||
| 12 | raise InvalidOption, "The `--only-group` and `--without-group` options cannot be used together" if @only_group.any? && @without_group.any? | ||
| 13 | |||
| 14 | raise InvalidOption, "The `--name-only` and `--paths` options cannot be used together" if @options["name-only"] && @options[:paths] | ||
| 15 | |||
| 16 | specs = if @only_group.any? || @without_group.any? | ||
| 17 | filtered_specs_by_groups | ||
| 18 | else | ||
| 19 | begin | ||
| 20 | Bundler.load.specs | ||
| 21 | rescue GemNotFound => e | ||
| 22 | Bundler.ui.error e.message | ||
| 23 | Bundler.ui.warn "Install missing gems with `bundle install`." | ||
| 24 | exit 1 | ||
| 25 | end | ||
| 26 | end.reject {|s| s.name == "bundler" }.sort_by(&:name) | ||
| 27 | |||
| 28 | return Bundler.ui.info "No gems in the Gemfile" if specs.empty? | ||
| 29 | |||
| 30 | return specs.each {|s| Bundler.ui.info s.name } if @options["name-only"] | ||
| 31 | return specs.each {|s| Bundler.ui.info s.full_gem_path } if @options["paths"] | ||
| 32 | |||
| 33 | Bundler.ui.info "Gems included by the bundle:" | ||
| 34 | |||
| 35 | specs.each {|s| Bundler.ui.info " * #{s.name} (#{s.version}#{s.git_version})" } | ||
| 36 | |||
| 37 | Bundler.ui.info "Use `bundle info` to print more detailed information about a gem" | ||
| 38 | end | ||
| 39 | |||
| 40 | private | ||
| 41 | |||
| 42 | def verify_group_exists(groups) | ||
| 43 | (@without_group + @only_group).each do |group| | ||
| 44 | raise InvalidOption, "`#{group}` group could not be found." unless groups.include?(group) | ||
| 45 | end | ||
| 46 | end | ||
| 47 | |||
| 48 | def filtered_specs_by_groups | ||
| 49 | definition = Bundler.definition | ||
| 50 | groups = definition.groups | ||
| 51 | |||
| 52 | verify_group_exists(groups) | ||
| 53 | |||
| 54 | show_groups = | ||
| 55 | if @without_group.any? | ||
| 56 | groups.reject {|g| @without_group.include?(g) } | ||
| 57 | elsif @only_group.any? | ||
| 58 | groups.select {|g| @only_group.include?(g) } | ||
| 59 | else | ||
| 60 | groups | ||
| 61 | end.map(&:to_sym) | ||
| 62 | |||
| 63 | definition.specs_for(show_groups) | ||
| 64 | end | ||
| 65 | end | ||
| 66 | end |
| 1 | # frozen_string_literal: true | ||
| 2 | |||
| 3 | module Bundler | ||
| 4 | class CLI::Lock | ||
| 5 | attr_reader :options | ||
| 6 | |||
| 7 | def initialize(options) | ||
| 8 | @options = options | ||
| 9 | end | ||
| 10 | |||
| 11 | def run | ||
| 12 | unless Bundler.default_gemfile | ||
| 13 | Bundler.ui.error "Unable to find a Gemfile to lock" | ||
| 14 | exit 1 | ||
| 15 | end | ||
| 16 | |||
| 17 | print = options[:print] | ||
| 18 | ui = Bundler.ui | ||
| 19 | Bundler.ui = UI::Silent.new if print | ||
| 20 | |||
| 21 | Bundler::Fetcher.disable_endpoint = options["full-index"] | ||
| 22 | |||
| 23 | update = options[:update] | ||
| 24 | conservative = options[:conservative] | ||
| 25 | |||
| 26 | if update.is_a?(Array) # unlocking specific gems | ||
| 27 | Bundler::CLI::Common.ensure_all_gems_in_lockfile!(update) | ||
| 28 | update = { :gems => update, :conservative => conservative } | ||
| 29 | elsif update | ||
| 30 | update = { :conservative => conservative } if conservative | ||
| 31 | end | ||
| 32 | definition = Bundler.definition(update) | ||
| 33 | |||
| 34 | Bundler::CLI::Common.configure_gem_version_promoter(Bundler.definition, options) if options[:update] | ||
| 35 | |||
| 36 | options["remove-platform"].each do |platform| | ||
| 37 | definition.remove_platform(platform) | ||
| 38 | end | ||
| 39 | |||
| 40 | options["add-platform"].each do |platform_string| | ||
| 41 | platform = Gem::Platform.new(platform_string) | ||
| 42 | if platform.to_s == "unknown" | ||
| 43 | Bundler.ui.warn "The platform `#{platform_string}` is unknown to RubyGems " \ | ||
| 44 | "and adding it will likely lead to resolution errors" | ||
| 45 | end | ||
| 46 | definition.add_platform(platform) | ||
| 47 | end | ||
| 48 | |||
| 49 | if definition.platforms.empty? | ||
| 50 | raise InvalidOption, "Removing all platforms from the bundle is not allowed" | ||
| 51 | end | ||
| 52 | |||
| 53 | definition.resolve_remotely! unless options[:local] | ||
| 54 | |||
| 55 | if print | ||
| 56 | puts definition.to_lock | ||
| 57 | else | ||
| 58 | file = options[:lockfile] | ||
| 59 | file = file ? File.expand_path(file) : Bundler.default_lockfile | ||
| 60 | puts "Writing lockfile to #{file}" | ||
| 61 | definition.lock(file) | ||
| 62 | end | ||
| 63 | |||
| 64 | Bundler.ui = ui | ||
| 65 | end | ||
| 66 | end | ||
| 67 | end |
| 1 | # frozen_string_literal: true | ||
| 2 | |||
| 3 | module Bundler | ||
| 4 | class CLI::Open | ||
| 5 | attr_reader :options, :name | ||
| 6 | def initialize(options, name) | ||
| 7 | @options = options | ||
| 8 | @name = name | ||
| 9 | end | ||
| 10 | |||
| 11 | def run | ||
| 12 | editor = [ENV["BUNDLER_EDITOR"], ENV["VISUAL"], ENV["EDITOR"]].find {|e| !e.nil? && !e.empty? } | ||
| 13 | return Bundler.ui.info("To open a bundled gem, set $EDITOR or $BUNDLER_EDITOR") unless editor | ||
| 14 | return unless spec = Bundler::CLI::Common.select_spec(name, :regex_match) | ||
| 15 | if spec.default_gem? | ||
| 16 | Bundler.ui.info "Unable to open #{name} because it's a default gem, so the directory it would normally be installed to does not exist." | ||
| 17 | else | ||
| 18 | path = spec.full_gem_path | ||
| 19 | Dir.chdir(path) do | ||
| 20 | require "shellwords" | ||
| 21 | command = Shellwords.split(editor) + [path] | ||
| 22 | Bundler.with_original_env do | ||
| 23 | system(*command) | ||
| 24 | end || Bundler.ui.info("Could not run '#{command.join(" ")}'") | ||
| 25 | end | ||
| 26 | end | ||
| 27 | end | ||
| 28 | end | ||
| 29 | end |
| 1 | # frozen_string_literal: true | ||
| 2 | |||
| 3 | module Bundler | ||
| 4 | class CLI::Outdated | ||
| 5 | attr_reader :options, :gems, :options_include_groups, :filter_options_patch, :sources, :strict | ||
| 6 | attr_accessor :outdated_gems | ||
| 7 | |||
| 8 | def initialize(options, gems) | ||
| 9 | @options = options | ||
| 10 | @gems = gems | ||
| 11 | @sources = Array(options[:source]) | ||
| 12 | |||
| 13 | @filter_options_patch = options.keys & %w[filter-major filter-minor filter-patch] | ||
| 14 | |||
| 15 | @outdated_gems = [] | ||
| 16 | |||
| 17 | @options_include_groups = [:group, :groups].any? do |v| | ||
| 18 | options.keys.include?(v.to_s) | ||
| 19 | end | ||
| 20 | |||
| 21 | # the patch level options imply strict is also true. It wouldn't make | ||
| 22 | # sense otherwise. | ||
| 23 | @strict = options["filter-strict"] || Bundler::CLI::Common.patch_level_options(options).any? | ||
| 24 | end | ||
| 25 | |||
| 26 | def run | ||
| 27 | check_for_deployment_mode! | ||
| 28 | |||
| 29 | gems.each do |gem_name| | ||
| 30 | Bundler::CLI::Common.select_spec(gem_name) | ||
| 31 | end | ||
| 32 | |||
| 33 | Bundler.definition.validate_runtime! | ||
| 34 | current_specs = Bundler.ui.silence { Bundler.definition.resolve } | ||
| 35 | |||
| 36 | current_dependencies = Bundler.ui.silence do | ||
| 37 | Bundler.load.dependencies.map {|dep| [dep.name, dep] }.to_h | ||
| 38 | end | ||
| 39 | |||
| 40 | definition = if gems.empty? && sources.empty? | ||
| 41 | # We're doing a full update | ||
| 42 | Bundler.definition(true) | ||
| 43 | else | ||
| 44 | Bundler.definition(:gems => gems, :sources => sources) | ||
| 45 | end | ||
| 46 | |||
| 47 | Bundler::CLI::Common.configure_gem_version_promoter( | ||
| 48 | Bundler.definition, | ||
| 49 | options.merge(:strict => @strict) | ||
| 50 | ) | ||
| 51 | |||
| 52 | definition_resolution = proc do | ||
| 53 | options[:local] ? definition.resolve_with_cache! : definition.resolve_remotely! | ||
| 54 | end | ||
| 55 | |||
| 56 | if options[:parseable] | ||
| 57 | Bundler.ui.silence(&definition_resolution) | ||
| 58 | else | ||
| 59 | definition_resolution.call | ||
| 60 | end | ||
| 61 | |||
| 62 | Bundler.ui.info "" | ||
| 63 | |||
| 64 | # Loop through the current specs | ||
| 65 | gemfile_specs, dependency_specs = current_specs.partition do |spec| | ||
| 66 | current_dependencies.key? spec.name | ||
| 67 | end | ||
| 68 | |||
| 69 | specs = if options["only-explicit"] | ||
| 70 | gemfile_specs | ||
| 71 | else | ||
| 72 | gemfile_specs + dependency_specs | ||
| 73 | end | ||
| 74 | |||
| 75 | specs.sort_by(&:name).uniq(&:name).each do |current_spec| | ||
| 76 | next unless gems.empty? || gems.include?(current_spec.name) | ||
| 77 | |||
| 78 | active_spec = retrieve_active_spec(definition, current_spec) | ||
| 79 | next unless active_spec | ||
| 80 | |||
| 81 | next unless filter_options_patch.empty? || update_present_via_semver_portions(current_spec, active_spec, options) | ||
| 82 | |||
| 83 | gem_outdated = Gem::Version.new(active_spec.version) > Gem::Version.new(current_spec.version) | ||
| 84 | next unless gem_outdated || (current_spec.git_version != active_spec.git_version) | ||
| 85 | |||
| 86 | dependency = current_dependencies[current_spec.name] | ||
| 87 | groups = "" | ||
| 88 | if dependency && !options[:parseable] | ||
| 89 | groups = dependency.groups.join(", ") | ||
| 90 | end | ||
| 91 | |||
| 92 | outdated_gems << { | ||
| 93 | :active_spec => active_spec, | ||
| 94 | :current_spec => current_spec, | ||
| 95 | :dependency => dependency, | ||
| 96 | :groups => groups, | ||
| 97 | } | ||
| 98 | end | ||
| 99 | |||
| 100 | if outdated_gems.empty? | ||
| 101 | unless options[:parseable] | ||
| 102 | Bundler.ui.info(nothing_outdated_message) | ||
| 103 | end | ||
| 104 | else | ||
| 105 | if options_include_groups | ||
| 106 | relevant_outdated_gems = outdated_gems.group_by {|g| g[:groups] }.sort.flat_map do |groups, gems| | ||
| 107 | contains_group = groups.split(", ").include?(options[:group]) | ||
| 108 | next unless options[:groups] || contains_group | ||
| 109 | |||
| 110 | gems | ||
| 111 | end.compact | ||
| 112 | |||
| 113 | if options[:parseable] | ||
| 114 | relevant_outdated_gems.each do |gems| | ||
| 115 | print_gems(gems) | ||
| 116 | end | ||
| 117 | else | ||
| 118 | print_gems_table(relevant_outdated_gems) | ||
| 119 | end | ||
| 120 | elsif options[:parseable] | ||
| 121 | print_gems(outdated_gems) | ||
| 122 | else | ||
| 123 | print_gems_table(outdated_gems) | ||
| 124 | end | ||
| 125 | |||
| 126 | exit 1 | ||
| 127 | end | ||
| 128 | end | ||
| 129 | |||
| 130 | private | ||
| 131 | |||
| 132 | def loaded_from_for(spec) | ||
| 133 | return unless spec.respond_to?(:loaded_from) | ||
| 134 | |||
| 135 | spec.loaded_from | ||
| 136 | end | ||
| 137 | |||
| 138 | def groups_text(group_text, groups) | ||
| 139 | "#{group_text}#{groups.split(",").size > 1 ? "s" : ""} \"#{groups}\"" | ||
| 140 | end | ||
| 141 | |||
| 142 | def nothing_outdated_message | ||
| 143 | if filter_options_patch.any? | ||
| 144 | display = filter_options_patch.map do |o| | ||
| 145 | o.sub("filter-", "") | ||
| 146 | end.join(" or ") | ||
| 147 | |||
| 148 | "No #{display} updates to display.\n" | ||
| 149 | else | ||
| 150 | "Bundle up to date!\n" | ||
| 151 | end | ||
| 152 | end | ||
| 153 | |||
| 154 | def retrieve_active_spec(definition, current_spec) | ||
| 155 | active_spec = definition.resolve.find_by_name_and_platform(current_spec.name, current_spec.platform) | ||
| 156 | return unless active_spec | ||
| 157 | |||
| 158 | return active_spec if strict | ||
| 159 | |||
| 160 | active_specs = active_spec.source.specs.search(current_spec.name).select {|spec| spec.match_platform(current_spec.platform) }.sort_by(&:version) | ||
| 161 | if !current_spec.version.prerelease? && !options[:pre] && active_specs.size > 1 | ||
| 162 | active_specs.delete_if {|b| b.respond_to?(:version) && b.version.prerelease? } | ||
| 163 | end | ||
| 164 | active_specs.last | ||
| 165 | end | ||
| 166 | |||
| 167 | def print_gems(gems_list) | ||
| 168 | gems_list.each do |gem| | ||
| 169 | print_gem( | ||
| 170 | gem[:current_spec], | ||
| 171 | gem[:active_spec], | ||
| 172 | gem[:dependency], | ||
| 173 | gem[:groups], | ||
| 174 | ) | ||
| 175 | end | ||
| 176 | end | ||
| 177 | |||
| 178 | def print_gems_table(gems_list) | ||
| 179 | data = gems_list.map do |gem| | ||
| 180 | gem_column_for( | ||
| 181 | gem[:current_spec], | ||
| 182 | gem[:active_spec], | ||
| 183 | gem[:dependency], | ||
| 184 | gem[:groups], | ||
| 185 | ) | ||
| 186 | end | ||
| 187 | |||
| 188 | print_indented([table_header] + data) | ||
| 189 | end | ||
| 190 | |||
| 191 | def print_gem(current_spec, active_spec, dependency, groups) | ||
| 192 | spec_version = "#{active_spec.version}#{active_spec.git_version}" | ||
| 193 | if Bundler.ui.debug? | ||
| 194 | loaded_from = loaded_from_for(active_spec) | ||
| 195 | spec_version += " (from #{loaded_from})" if loaded_from | ||
| 196 | end | ||
| 197 | current_version = "#{current_spec.version}#{current_spec.git_version}" | ||
| 198 | |||
| 199 | if dependency && dependency.specific? | ||
| 200 | dependency_version = %(, requested #{dependency.requirement}) | ||
| 201 | end | ||
| 202 | |||
| 203 | spec_outdated_info = "#{active_spec.name} (newest #{spec_version}, " \ | ||
| 204 | "installed #{current_version}#{dependency_version})" | ||
| 205 | |||
| 206 | output_message = if options[:parseable] | ||
| 207 | spec_outdated_info.to_s | ||
| 208 | elsif options_include_groups || groups.empty? | ||
| 209 | " * #{spec_outdated_info}" | ||
| 210 | else | ||
| 211 | " * #{spec_outdated_info} in #{groups_text("group", groups)}" | ||
| 212 | end | ||
| 213 | |||
| 214 | Bundler.ui.info output_message.rstrip | ||
| 215 | end | ||
| 216 | |||
| 217 | def gem_column_for(current_spec, active_spec, dependency, groups) | ||
| 218 | current_version = "#{current_spec.version}#{current_spec.git_version}" | ||
| 219 | spec_version = "#{active_spec.version}#{active_spec.git_version}" | ||
| 220 | dependency = dependency.requirement if dependency | ||
| 221 | |||
| 222 | ret_val = [active_spec.name, current_version, spec_version, dependency.to_s, groups.to_s] | ||
| 223 | ret_val << loaded_from_for(active_spec).to_s if Bundler.ui.debug? | ||
| 224 | ret_val | ||
| 225 | end | ||
| 226 | |||
| 227 | def check_for_deployment_mode! | ||
| 228 | return unless Bundler.frozen_bundle? | ||
| 229 | suggested_command = if Bundler.settings.locations("frozen").keys.&([:global, :local]).any? | ||
| 230 | "bundle config unset frozen" | ||
| 231 | elsif Bundler.settings.locations("deployment").keys.&([:global, :local]).any? | ||
| 232 | "bundle config unset deployment" | ||
| 233 | end | ||
| 234 | raise ProductionError, "You are trying to check outdated gems in " \ | ||
| 235 | "deployment mode. Run `bundle outdated` elsewhere.\n" \ | ||
| 236 | "\nIf this is a development machine, remove the " \ | ||
| 237 | "#{Bundler.default_gemfile} freeze" \ | ||
| 238 | "\nby running `#{suggested_command}`." | ||
| 239 | end | ||
| 240 | |||
| 241 | def update_present_via_semver_portions(current_spec, active_spec, options) | ||
| 242 | current_major = current_spec.version.segments.first | ||
| 243 | active_major = active_spec.version.segments.first | ||
| 244 | |||
| 245 | update_present = false | ||
| 246 | update_present = active_major > current_major if options["filter-major"] | ||
| 247 | |||
| 248 | if !update_present && (options["filter-minor"] || options["filter-patch"]) && current_major == active_major | ||
| 249 | current_minor = get_version_semver_portion_value(current_spec, 1) | ||
| 250 | active_minor = get_version_semver_portion_value(active_spec, 1) | ||
| 251 | |||
| 252 | update_present = active_minor > current_minor if options["filter-minor"] | ||
| 253 | |||
| 254 | if !update_present && options["filter-patch"] && current_minor == active_minor | ||
| 255 | current_patch = get_version_semver_portion_value(current_spec, 2) | ||
| 256 | active_patch = get_version_semver_portion_value(active_spec, 2) | ||
| 257 | |||
| 258 | update_present = active_patch > current_patch | ||
| 259 | end | ||
| 260 | end | ||
| 261 | |||
| 262 | update_present | ||
| 263 | end | ||
| 264 | |||
| 265 | def get_version_semver_portion_value(spec, version_portion_index) | ||
| 266 | version_section = spec.version.segments[version_portion_index, 1] | ||
| 267 | version_section.to_a[0].to_i | ||
| 268 | end | ||
| 269 | |||
| 270 | def print_indented(matrix) | ||
| 271 | header = matrix[0] | ||
| 272 | data = matrix[1..-1] | ||
| 273 | |||
| 274 | column_sizes = Array.new(header.size) do |index| | ||
| 275 | matrix.max_by {|row| row[index].length }[index].length | ||
| 276 | end | ||
| 277 | |||
| 278 | Bundler.ui.info justify(header, column_sizes) | ||
| 279 | |||
| 280 | data.sort_by! {|row| row[0] } | ||
| 281 | |||
| 282 | data.each do |row| | ||
| 283 | Bundler.ui.info justify(row, column_sizes) | ||
| 284 | end | ||
| 285 | end | ||
| 286 | |||
| 287 | def table_header | ||
| 288 | header = ["Gem", "Current", "Latest", "Requested", "Groups"] | ||
| 289 | header << "Path" if Bundler.ui.debug? | ||
| 290 | header | ||
| 291 | end | ||
| 292 | |||
| 293 | def justify(row, sizes) | ||
| 294 | row.each_with_index.map do |element, index| | ||
| 295 | element.ljust(sizes[index]) | ||
| 296 | end.join(" ").strip + "\n" | ||
| 297 | end | ||
| 298 | end | ||
| 299 | end |
| 1 | # frozen_string_literal: true | ||
| 2 | |||
| 3 | module Bundler | ||
| 4 | class CLI::Platform | ||
| 5 | attr_reader :options | ||
| 6 | def initialize(options) | ||
| 7 | @options = options | ||
| 8 | end | ||
| 9 | |||
| 10 | def run | ||
| 11 | platforms, ruby_version = Bundler.ui.silence do | ||
| 12 | locked_ruby_version = Bundler.locked_gems && Bundler.locked_gems.ruby_version&.gsub(/p\d+\Z/, "") | ||
| 13 | gemfile_ruby_version = Bundler.definition.ruby_version && Bundler.definition.ruby_version.single_version_string | ||
| 14 | [Bundler.definition.platforms.map {|p| "* #{p}" }, | ||
| 15 | locked_ruby_version || gemfile_ruby_version] | ||
| 16 | end | ||
| 17 | output = [] | ||
| 18 | |||
| 19 | if options[:ruby] | ||
| 20 | if ruby_version | ||
| 21 | output << ruby_version | ||
| 22 | else | ||
| 23 | output << "No ruby version specified" | ||
| 24 | end | ||
| 25 | else | ||
| 26 | output << "Your platform is: #{Gem::Platform.local}" | ||
| 27 | output << "Your app has gems that work on these platforms:\n#{platforms.join("\n")}" | ||
| 28 | |||
| 29 | if ruby_version | ||
| 30 | output << "Your Gemfile specifies a Ruby version requirement:\n* #{ruby_version}" | ||
| 31 | |||
| 32 | begin | ||
| 33 | Bundler.definition.validate_runtime! | ||
| 34 | output << "Your current platform satisfies the Ruby version requirement." | ||
| 35 | rescue RubyVersionMismatch => e | ||
| 36 | output << e.message | ||
| 37 | end | ||
| 38 | else | ||
| 39 | output << "Your Gemfile does not specify a Ruby version requirement." | ||
| 40 | end | ||
| 41 | end | ||
| 42 | |||
| 43 | Bundler.ui.info output.join("\n\n") | ||
| 44 | end | ||
| 45 | end | ||
| 46 | end |
| 1 | # frozen_string_literal: true | ||
| 2 | |||
| 3 | require_relative "../vendored_thor" | ||
| 4 | module Bundler | ||
| 5 | class CLI::Plugin < Thor | ||
| 6 | desc "install PLUGINS", "Install the plugin from the source" | ||
| 7 | long_desc <<-D | ||
| 8 | Install plugins either from the rubygems source provided (with --source option) or from a git source provided with --git (for remote repos) or --local_git (for local repos). If no sources are provided, it uses Gem.sources | ||
| 9 | D | ||
| 10 | method_option "source", :type => :string, :default => nil, :banner => | ||
| 11 | "URL of the RubyGems source to fetch the plugin from" | ||
| 12 | method_option "version", :type => :string, :default => nil, :banner => | ||
| 13 | "The version of the plugin to fetch" | ||
| 14 | method_option "git", :type => :string, :default => nil, :banner => | ||
| 15 | "URL of the git repo to fetch from" | ||
| 16 | method_option "local_git", :type => :string, :default => nil, :banner => | ||
| 17 | "Path of the local git repo to fetch from" | ||
| 18 | method_option "branch", :type => :string, :default => nil, :banner => | ||
| 19 | "The git branch to checkout" | ||
| 20 | method_option "ref", :type => :string, :default => nil, :banner => | ||
| 21 | "The git revision to check out" | ||
| 22 | def install(*plugins) | ||
| 23 | Bundler::Plugin.install(plugins, options) | ||
| 24 | end | ||
| 25 | |||
| 26 | desc "uninstall PLUGINS", "Uninstall the plugins" | ||
| 27 | long_desc <<-D | ||
| 28 | Uninstall given list of plugins. To uninstall all the plugins, use -all option. | ||
| 29 | D | ||
| 30 | method_option "all", :type => :boolean, :default => nil, :banner => | ||
| 31 | "Uninstall all the installed plugins. If no plugin is installed, then it does nothing." | ||
| 32 | def uninstall(*plugins) | ||
| 33 | Bundler::Plugin.uninstall(plugins, options) | ||
| 34 | end | ||
| 35 | |||
| 36 | desc "list", "List the installed plugins and available commands" | ||
| 37 | def list | ||
| 38 | Bundler::Plugin.list | ||
| 39 | end | ||
| 40 | end | ||
| 41 | end |
| 1 | # frozen_string_literal: true | ||
| 2 | |||
| 3 | module Bundler | ||
| 4 | class CLI::Pristine | ||
| 5 | def initialize(gems) | ||
| 6 | @gems = gems | ||
| 7 | end | ||
| 8 | |||
| 9 | def run | ||
| 10 | CLI::Common.ensure_all_gems_in_lockfile!(@gems) | ||
| 11 | definition = Bundler.definition | ||
| 12 | definition.validate_runtime! | ||
| 13 | installer = Bundler::Installer.new(Bundler.root, definition) | ||
| 14 | |||
| 15 | Bundler.load.specs.each do |spec| | ||
| 16 | next if spec.name == "bundler" # Source::Rubygems doesn't install bundler | ||
| 17 | next if !@gems.empty? && !@gems.include?(spec.name) | ||
| 18 | |||
| 19 | gem_name = "#{spec.name} (#{spec.version}#{spec.git_version})" | ||
| 20 | gem_name += " (#{spec.platform})" if !spec.platform.nil? && spec.platform != Gem::Platform::RUBY | ||
| 21 | |||
| 22 | case source = spec.source | ||
| 23 | when Source::Rubygems | ||
| 24 | cached_gem = spec.cache_file | ||
| 25 | unless File.exist?(cached_gem) | ||
| 26 | Bundler.ui.error("Failed to pristine #{gem_name}. Cached gem #{cached_gem} does not exist.") | ||
| 27 | next | ||
| 28 | end | ||
| 29 | |||
| 30 | FileUtils.rm_rf spec.full_gem_path | ||
| 31 | when Source::Git | ||
| 32 | if source.local? | ||
| 33 | Bundler.ui.warn("Cannot pristine #{gem_name}. Gem is locally overridden.") | ||
| 34 | next | ||
| 35 | end | ||
| 36 | |||
| 37 | source.remote! | ||
| 38 | if extension_cache_path = source.extension_cache_path(spec) | ||
| 39 | FileUtils.rm_rf extension_cache_path | ||
| 40 | end | ||
| 41 | FileUtils.rm_rf spec.extension_dir | ||
| 42 | FileUtils.rm_rf spec.full_gem_path | ||
| 43 | else | ||
| 44 | Bundler.ui.warn("Cannot pristine #{gem_name}. Gem is sourced from local path.") | ||
| 45 | next | ||
| 46 | end | ||
| 47 | |||
| 48 | Bundler::GemInstaller.new(spec, installer, false, 0, true).install_from_spec | ||
| 49 | end | ||
| 50 | end | ||
| 51 | end | ||
| 52 | end |
| 1 | # frozen_string_literal: true | ||
| 2 | |||
| 3 | module Bundler | ||
| 4 | class CLI::Remove | ||
| 5 | def initialize(gems, options) | ||
| 6 | @gems = gems | ||
| 7 | @options = options | ||
| 8 | end | ||
| 9 | |||
| 10 | def run | ||
| 11 | raise InvalidOption, "Please specify gems to remove." if @gems.empty? | ||
| 12 | |||
| 13 | Injector.remove(@gems, {}) | ||
| 14 | Installer.install(Bundler.root, Bundler.definition) | ||
| 15 | end | ||
| 16 | end | ||
| 17 | end |
| 1 | # frozen_string_literal: true | ||
| 2 | |||
| 3 | module Bundler | ||
| 4 | class CLI::Show | ||
| 5 | attr_reader :options, :gem_name, :latest_specs | ||
| 6 | def initialize(options, gem_name) | ||
| 7 | @options = options | ||
| 8 | @gem_name = gem_name | ||
| 9 | @verbose = options[:verbose] || options[:outdated] | ||
| 10 | @latest_specs = fetch_latest_specs if @verbose | ||
| 11 | end | ||
| 12 | |||
| 13 | def run | ||
| 14 | Bundler.ui.silence do | ||
| 15 | Bundler.definition.validate_runtime! | ||
| 16 | Bundler.load.lock | ||
| 17 | end | ||
| 18 | |||
| 19 | if gem_name | ||
| 20 | if gem_name == "bundler" | ||
| 21 | path = File.expand_path("../../..", __dir__) | ||
| 22 | else | ||
| 23 | spec = Bundler::CLI::Common.select_spec(gem_name, :regex_match) | ||
| 24 | return unless spec | ||
| 25 | path = spec.full_gem_path | ||
| 26 | unless File.directory?(path) | ||
| 27 | return Bundler.ui.warn "The gem #{gem_name} has been deleted. It was installed at: #{path}" | ||
| 28 | end | ||
| 29 | end | ||
| 30 | return Bundler.ui.info(path) | ||
| 31 | end | ||
| 32 | |||
| 33 | if options[:paths] | ||
| 34 | Bundler.load.specs.sort_by(&:name).map do |s| | ||
| 35 | Bundler.ui.info s.full_gem_path | ||
| 36 | end | ||
| 37 | else | ||
| 38 | Bundler.ui.info "Gems included by the bundle:" | ||
| 39 | Bundler.load.specs.sort_by(&:name).each do |s| | ||
| 40 | desc = " * #{s.name} (#{s.version}#{s.git_version})" | ||
| 41 | if @verbose | ||
| 42 | latest = latest_specs.find {|l| l.name == s.name } | ||
| 43 | Bundler.ui.info <<-END.gsub(/^ +/, "") | ||
| 44 | #{desc} | ||
| 45 | \tSummary: #{s.summary || "No description available."} | ||
| 46 | \tHomepage: #{s.homepage || "No website available."} | ||
| 47 | \tStatus: #{outdated?(s, latest) ? "Outdated - #{s.version} < #{latest.version}" : "Up to date"} | ||
| 48 | END | ||
| 49 | else | ||
| 50 | Bundler.ui.info desc | ||
| 51 | end | ||
| 52 | end | ||
| 53 | end | ||
| 54 | end | ||
| 55 | |||
| 56 | private | ||
| 57 | |||
| 58 | def fetch_latest_specs | ||
| 59 | definition = Bundler.definition(true) | ||
| 60 | if options[:outdated] | ||
| 61 | Bundler.ui.info "Fetching remote specs for outdated check...\n\n" | ||
| 62 | Bundler.ui.silence { definition.resolve_remotely! } | ||
| 63 | else | ||
| 64 | definition.resolve_with_cache! | ||
| 65 | end | ||
| 66 | Bundler.reset! | ||
| 67 | definition.specs | ||
| 68 | end | ||
| 69 | |||
| 70 | def outdated?(current, latest) | ||
| 71 | return false unless latest | ||
| 72 | Gem::Version.new(current.version) < Gem::Version.new(latest.version) | ||
| 73 | end | ||
| 74 | end | ||
| 75 | end |
| 1 | # frozen_string_literal: true | ||
| 2 | |||
| 3 | module Bundler | ||
| 4 | class CLI::Update | ||
| 5 | attr_reader :options, :gems | ||
| 6 | def initialize(options, gems) | ||
| 7 | @options = options | ||
| 8 | @gems = gems | ||
| 9 | end | ||
| 10 | |||
| 11 | def run | ||
| 12 | Bundler.ui.level = "warn" if options[:quiet] | ||
| 13 | |||
| 14 | update_bundler = options[:bundler] | ||
| 15 | |||
| 16 | Bundler.self_manager.update_bundler_and_restart_with_it_if_needed(update_bundler) if update_bundler | ||
| 17 | |||
| 18 | Plugin.gemfile_install(Bundler.default_gemfile) if Bundler.feature_flag.plugins? | ||
| 19 | |||
| 20 | sources = Array(options[:source]) | ||
| 21 | groups = Array(options[:group]).map(&:to_sym) | ||
| 22 | |||
| 23 | full_update = gems.empty? && sources.empty? && groups.empty? && !options[:ruby] && !update_bundler | ||
| 24 | |||
| 25 | if full_update && !options[:all] | ||
| 26 | if Bundler.feature_flag.update_requires_all_flag? | ||
| 27 | raise InvalidOption, "To update everything, pass the `--all` flag." | ||
| 28 | end | ||
| 29 | SharedHelpers.major_deprecation 3, "Pass --all to `bundle update` to update everything" | ||
| 30 | elsif !full_update && options[:all] | ||
| 31 | raise InvalidOption, "Cannot specify --all along with specific options." | ||
| 32 | end | ||
| 33 | |||
| 34 | conservative = options[:conservative] | ||
| 35 | |||
| 36 | if full_update | ||
| 37 | if conservative | ||
| 38 | Bundler.definition(:conservative => conservative) | ||
| 39 | else | ||
| 40 | Bundler.definition(true) | ||
| 41 | end | ||
| 42 | else | ||
| 43 | unless Bundler.default_lockfile.exist? | ||
| 44 | raise GemfileLockNotFound, "This Bundle hasn't been installed yet. " \ | ||
| 45 | "Run `bundle install` to update and install the bundled gems." | ||
| 46 | end | ||
| 47 | Bundler::CLI::Common.ensure_all_gems_in_lockfile!(gems) | ||
| 48 | |||
| 49 | if groups.any? | ||
| 50 | deps = Bundler.definition.dependencies.select {|d| (d.groups & groups).any? } | ||
| 51 | gems.concat(deps.map(&:name)) | ||
| 52 | end | ||
| 53 | |||
| 54 | Bundler.definition(:gems => gems, :sources => sources, :ruby => options[:ruby], | ||
| 55 | :conservative => conservative, | ||
| 56 | :bundler => update_bundler) | ||
| 57 | end | ||
| 58 | |||
| 59 | Bundler::CLI::Common.configure_gem_version_promoter(Bundler.definition, options) | ||
| 60 | |||
| 61 | Bundler::Fetcher.disable_endpoint = options["full-index"] | ||
| 62 | |||
| 63 | opts = options.dup | ||
| 64 | opts["update"] = true | ||
| 65 | opts["local"] = options[:local] | ||
| 66 | |||
| 67 | Bundler.settings.set_command_option_if_given :jobs, opts["jobs"] | ||
| 68 | |||
| 69 | Bundler.definition.validate_runtime! | ||
| 70 | |||
| 71 | if locked_gems = Bundler.definition.locked_gems | ||
| 72 | previous_locked_info = locked_gems.specs.reduce({}) do |h, s| | ||
| 73 | h[s.name] = { :spec => s, :version => s.version, :source => s.source.identifier } | ||
| 74 | h | ||
| 75 | end | ||
| 76 | end | ||
| 77 | |||
| 78 | installer = Installer.install Bundler.root, Bundler.definition, opts | ||
| 79 | Bundler.load.cache if Bundler.app_cache.exist? | ||
| 80 | |||
| 81 | if CLI::Common.clean_after_install? | ||
| 82 | require_relative "clean" | ||
| 83 | Bundler::CLI::Clean.new(options).run | ||
| 84 | end | ||
| 85 | |||
| 86 | if locked_gems | ||
| 87 | gems.each do |name| | ||
| 88 | locked_info = previous_locked_info[name] | ||
| 89 | next unless locked_info | ||
| 90 | |||
| 91 | locked_spec = locked_info[:spec] | ||
| 92 | new_spec = Bundler.definition.specs[name].first | ||
| 93 | unless new_spec | ||
| 94 | unless locked_spec.match_platform(Bundler.local_platform) | ||
| 95 | Bundler.ui.warn "Bundler attempted to update #{name} but it was not considered because it is for a different platform from the current one" | ||
| 96 | end | ||
| 97 | |||
| 98 | next | ||
| 99 | end | ||
| 100 | |||
| 101 | locked_source = locked_info[:source] | ||
| 102 | new_source = new_spec.source.identifier | ||
| 103 | next if locked_source != new_source | ||
| 104 | |||
| 105 | new_version = new_spec.version | ||
| 106 | locked_version = locked_info[:version] | ||
| 107 | if new_version < locked_version | ||
| 108 | Bundler.ui.warn "Note: #{name} version regressed from #{locked_version} to #{new_version}" | ||
| 109 | elsif new_version == locked_version | ||
| 110 | Bundler.ui.warn "Bundler attempted to update #{name} but its version stayed the same" | ||
| 111 | end | ||
| 112 | end | ||
| 113 | end | ||
| 114 | |||
| 115 | Bundler.ui.confirm "Bundle updated!" | ||
| 116 | Bundler::CLI::Common.output_without_groups_message(:update) | ||
| 117 | Bundler::CLI::Common.output_post_install_messages installer.post_install_messages | ||
| 118 | |||
| 119 | Bundler::CLI::Common.output_fund_metadata_summary | ||
| 120 | end | ||
| 121 | end | ||
| 122 | end |
| 1 | # frozen_string_literal: true | ||
| 2 | |||
| 3 | module Bundler | ||
| 4 | class CLI::Viz | ||
| 5 | attr_reader :options, :gem_name | ||
| 6 | def initialize(options) | ||
| 7 | @options = options | ||
| 8 | end | ||
| 9 | |||
| 10 | def run | ||
| 11 | # make sure we get the right `graphviz`. There is also a `graphviz` | ||
| 12 | # gem we're not built to support | ||
| 13 | gem "ruby-graphviz" | ||
| 14 | require "graphviz" | ||
| 15 | |||
| 16 | options[:without] = options[:without].join(":").tr(" ", ":").split(":") | ||
| 17 | output_file = File.expand_path(options[:file]) | ||
| 18 | |||
| 19 | graph = Graph.new(Bundler.load, output_file, options[:version], options[:requirements], options[:format], options[:without]) | ||
| 20 | graph.viz | ||
| 21 | rescue LoadError => e | ||
| 22 | Bundler.ui.error e.inspect | ||
| 23 | Bundler.ui.warn "Make sure you have the graphviz ruby gem. You can install it with:" | ||
| 24 | Bundler.ui.warn "`gem install ruby-graphviz`" | ||
| 25 | rescue StandardError => e | ||
| 26 | raise unless e.message =~ /GraphViz not installed or dot not in PATH/ | ||
| 27 | Bundler.ui.error e.message | ||
| 28 | Bundler.ui.warn "Please install GraphViz. On a Mac with Homebrew, you can run `brew install graphviz`." | ||
| 29 | end | ||
| 30 | end | ||
| 31 | end |
| 1 | # frozen_string_literal: true | ||
| 2 | |||
| 3 | require "pathname" | ||
| 4 | require "set" | ||
| 5 | |||
| 6 | module Bundler | ||
| 7 | class CompactIndexClient | ||
| 8 | DEBUG_MUTEX = Thread::Mutex.new | ||
| 9 | def self.debug | ||
| 10 | return unless ENV["DEBUG_COMPACT_INDEX"] | ||
| 11 | DEBUG_MUTEX.synchronize { warn("[#{self}] #{yield}") } | ||
| 12 | end | ||
| 13 | |||
| 14 | class Error < StandardError; end | ||
| 15 | |||
| 16 | require_relative "compact_index_client/cache" | ||
| 17 | require_relative "compact_index_client/updater" | ||
| 18 | |||
| 19 | attr_reader :directory | ||
| 20 | |||
| 21 | def initialize(directory, fetcher) | ||
| 22 | @directory = Pathname.new(directory) | ||
| 23 | @updater = Updater.new(fetcher) | ||
| 24 | @cache = Cache.new(@directory) | ||
| 25 | @endpoints = Set.new | ||
| 26 | @info_checksums_by_name = {} | ||
| 27 | @parsed_checksums = false | ||
| 28 | @mutex = Thread::Mutex.new | ||
| 29 | end | ||
| 30 | |||
| 31 | def execution_mode=(block) | ||
| 32 | Bundler::CompactIndexClient.debug { "execution_mode=" } | ||
| 33 | @endpoints = Set.new | ||
| 34 | |||
| 35 | @execution_mode = block | ||
| 36 | end | ||
| 37 | |||
| 38 | # @return [Lambda] A lambda that takes an array of inputs and a block, and | ||
| 39 | # maps the inputs with the block in parallel. | ||
| 40 | # | ||
| 41 | def execution_mode | ||
| 42 | @execution_mode || sequentially | ||
| 43 | end | ||
| 44 | |||
| 45 | def sequential_execution_mode! | ||
| 46 | self.execution_mode = sequentially | ||
| 47 | end | ||
| 48 | |||
| 49 | def sequentially | ||
| 50 | @sequentially ||= lambda do |inputs, &blk| | ||
| 51 | inputs.map(&blk) | ||
| 52 | end | ||
| 53 | end | ||
| 54 | |||
| 55 | def names | ||
| 56 | Bundler::CompactIndexClient.debug { "/names" } | ||
| 57 | update(@cache.names_path, "names") | ||
| 58 | @cache.names | ||
| 59 | end | ||
| 60 | |||
| 61 | def versions | ||
| 62 | Bundler::CompactIndexClient.debug { "/versions" } | ||
| 63 | update(@cache.versions_path, "versions") | ||
| 64 | versions, @info_checksums_by_name = @cache.versions | ||
| 65 | versions | ||
| 66 | end | ||
| 67 | |||
| 68 | def dependencies(names) | ||
| 69 | Bundler::CompactIndexClient.debug { "dependencies(#{names})" } | ||
| 70 | execution_mode.call(names) do |name| | ||
| 71 | update_info(name) | ||
| 72 | @cache.dependencies(name).map {|d| d.unshift(name) } | ||
| 73 | end.flatten(1) | ||
| 74 | end | ||
| 75 | |||
| 76 | def update_and_parse_checksums! | ||
| 77 | Bundler::CompactIndexClient.debug { "update_and_parse_checksums!" } | ||
| 78 | return @info_checksums_by_name if @parsed_checksums | ||
| 79 | update(@cache.versions_path, "versions") | ||
| 80 | @info_checksums_by_name = @cache.checksums | ||
| 81 | @parsed_checksums = true | ||
| 82 | end | ||
| 83 | |||
| 84 | private | ||
| 85 | |||
| 86 | def update(local_path, remote_path) | ||
| 87 | Bundler::CompactIndexClient.debug { "update(#{local_path}, #{remote_path})" } | ||
| 88 | unless synchronize { @endpoints.add?(remote_path) } | ||
| 89 | Bundler::CompactIndexClient.debug { "already fetched #{remote_path}" } | ||
| 90 | return | ||
| 91 | end | ||
| 92 | @updater.update(local_path, url(remote_path)) | ||
| 93 | end | ||
| 94 | |||
| 95 | def update_info(name) | ||
| 96 | Bundler::CompactIndexClient.debug { "update_info(#{name})" } | ||
| 97 | path = @cache.info_path(name) | ||
| 98 | checksum = @updater.checksum_for_file(path) | ||
| 99 | unless existing = @info_checksums_by_name[name] | ||
| 100 | Bundler::CompactIndexClient.debug { "skipping updating info for #{name} since it is missing from versions" } | ||
| 101 | return | ||
| 102 | end | ||
| 103 | if checksum == existing | ||
| 104 | Bundler::CompactIndexClient.debug { "skipping updating info for #{name} since the versions checksum matches the local checksum" } | ||
| 105 | return | ||
| 106 | end | ||
| 107 | Bundler::CompactIndexClient.debug { "updating info for #{name} since the versions checksum #{existing} != the local checksum #{checksum}" } | ||
| 108 | update(path, "info/#{name}") | ||
| 109 | end | ||
| 110 | |||
| 111 | def url(path) | ||
| 112 | path | ||
| 113 | end | ||
| 114 | |||
| 115 | def synchronize | ||
| 116 | @mutex.synchronize { yield } | ||
| 117 | end | ||
| 118 | end | ||
| 119 | end |
| 1 | # frozen_string_literal: true | ||
| 2 | |||
| 3 | require_relative "gem_parser" | ||
| 4 | |||
| 5 | module Bundler | ||
| 6 | class CompactIndexClient | ||
| 7 | class Cache | ||
| 8 | attr_reader :directory | ||
| 9 | |||
| 10 | def initialize(directory) | ||
| 11 | @directory = Pathname.new(directory).expand_path | ||
| 12 | info_roots.each do |dir| | ||
| 13 | SharedHelpers.filesystem_access(dir) do | ||
| 14 | FileUtils.mkdir_p(dir) | ||
| 15 | end | ||
| 16 | end | ||
| 17 | end | ||
| 18 | |||
| 19 | def names | ||
| 20 | lines(names_path) | ||
| 21 | end | ||
| 22 | |||
| 23 | def names_path | ||
| 24 | directory.join("names") | ||
| 25 | end | ||
| 26 | |||
| 27 | def versions | ||
| 28 | versions_by_name = Hash.new {|hash, key| hash[key] = [] } | ||
| 29 | info_checksums_by_name = {} | ||
| 30 | |||
| 31 | lines(versions_path).each do |line| | ||
| 32 | name, versions_string, info_checksum = line.split(" ", 3) | ||
| 33 | info_checksums_by_name[name] = info_checksum || "" | ||
| 34 | versions_string.split(",").each do |version| | ||
| 35 | if version.start_with?("-") | ||
| 36 | version = version[1..-1].split("-", 2).unshift(name) | ||
| 37 | versions_by_name[name].delete(version) | ||
| 38 | else | ||
| 39 | version = version.split("-", 2).unshift(name) | ||
| 40 | versions_by_name[name] << version | ||
| 41 | end | ||
| 42 | end | ||
| 43 | end | ||
| 44 | |||
| 45 | [versions_by_name, info_checksums_by_name] | ||
| 46 | end | ||
| 47 | |||
| 48 | def versions_path | ||
| 49 | directory.join("versions") | ||
| 50 | end | ||
| 51 | |||
| 52 | def checksums | ||
| 53 | checksums = {} | ||
| 54 | |||
| 55 | lines(versions_path).each do |line| | ||
| 56 | name, _, checksum = line.split(" ", 3) | ||
| 57 | checksums[name] = checksum | ||
| 58 | end | ||
| 59 | |||
| 60 | checksums | ||
| 61 | end | ||
| 62 | |||
| 63 | def dependencies(name) | ||
| 64 | lines(info_path(name)).map do |line| | ||
| 65 | parse_gem(line) | ||
| 66 | end | ||
| 67 | end | ||
| 68 | |||
| 69 | def info_path(name) | ||
| 70 | name = name.to_s | ||
| 71 | if name =~ /[^a-z0-9_-]/ | ||
| 72 | name += "-#{SharedHelpers.digest(:MD5).hexdigest(name).downcase}" | ||
| 73 | info_roots.last.join(name) | ||
| 74 | else | ||
| 75 | info_roots.first.join(name) | ||
| 76 | end | ||
| 77 | end | ||
| 78 | |||
| 79 | private | ||
| 80 | |||
| 81 | def lines(path) | ||
| 82 | return [] unless path.file? | ||
| 83 | lines = SharedHelpers.filesystem_access(path, :read, &:read).split("\n") | ||
| 84 | header = lines.index("---") | ||
| 85 | header ? lines[header + 1..-1] : lines | ||
| 86 | end | ||
| 87 | |||
| 88 | def parse_gem(line) | ||
| 89 | @dependency_parser ||= GemParser.new | ||
| 90 | @dependency_parser.parse(line) | ||
| 91 | end | ||
| 92 | |||
| 93 | def info_roots | ||
| 94 | [ | ||
| 95 | directory.join("info"), | ||
| 96 | directory.join("info-special-characters"), | ||
| 97 | ] | ||
| 98 | end | ||
| 99 | end | ||
| 100 | end | ||
| 101 | end |
vendor/bundle/ruby/3.2.0/gems/bundler-2.3.21/lib/bundler/compact_index_client/gem_parser.rb
0 → 100644
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/bundler-2.3.21/lib/bundler/templates/newgem/CHANGELOG.md.tt
0 → 100644
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/bundler-2.3.21/lib/bundler/templates/newgem/CODE_OF_CONDUCT.md.tt
0 → 100644
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/bundler-2.3.21/lib/bundler/templates/newgem/circleci/config.yml.tt
0 → 100644
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/bundler-2.3.21/lib/bundler/templates/newgem/ext/newgem/extconf.rb.tt
0 → 100644
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/bundler-2.3.21/lib/bundler/templates/newgem/ext/newgem/newgem.c.tt
0 → 100644
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/bundler-2.3.21/lib/bundler/templates/newgem/ext/newgem/newgem.h.tt
0 → 100644
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/bundler-2.3.21/lib/bundler/templates/newgem/gitlab-ci.yml.tt
0 → 100644
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/bundler-2.3.21/lib/bundler/templates/newgem/lib/newgem.rb.tt
0 → 100644
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/bundler-2.3.21/lib/bundler/templates/newgem/lib/newgem/version.rb.tt
0 → 100644
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/bundler-2.3.21/lib/bundler/templates/newgem/newgem.gemspec.tt
0 → 100644
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/bundler-2.3.21/lib/bundler/templates/newgem/sig/newgem.rbs.tt
0 → 100644
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/bundler-2.3.21/lib/bundler/templates/newgem/spec/newgem_spec.rb.tt
0 → 100644
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/bundler-2.3.21/lib/bundler/templates/newgem/spec/spec_helper.rb.tt
0 → 100644
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/bundler-2.3.21/lib/bundler/templates/newgem/standard.yml.tt
0 → 100644
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/bundler-2.3.21/lib/bundler/vendor/fileutils/lib/fileutils.rb
0 → 100644
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/bundler-2.3.21/lib/bundler/vendor/molinillo/lib/molinillo.rb
0 → 100644
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/bundler-2.3.21/lib/bundler/vendor/molinillo/lib/molinillo/errors.rb
0 → 100644
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/bundler-2.3.21/lib/bundler/vendor/molinillo/lib/molinillo/resolver.rb
0 → 100644
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/bundler-2.3.21/lib/bundler/vendor/molinillo/lib/molinillo/state.rb
0 → 100644
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/bundler-2.3.21/lib/bundler/vendor/net-http-persistent/README.rdoc
0 → 100644
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/bundler-2.3.21/lib/bundler/vendor/thor/lib/thor/actions/create_file.rb
0 → 100644
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/bundler-2.3.21/lib/bundler/vendor/thor/lib/thor/actions/create_link.rb
0 → 100644
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/bundler-2.3.21/lib/bundler/vendor/thor/lib/thor/actions/directory.rb
0 → 100644
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/bundler-2.3.21/lib/bundler/vendor/thor/lib/thor/invocation.rb
0 → 100644
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/bundler-2.3.21/lib/bundler/vendor/thor/lib/thor/line_editor.rb
0 → 100644
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/bundler-2.3.21/lib/bundler/vendor/thor/lib/thor/line_editor/basic.rb
0 → 100644
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/bundler-2.3.21/lib/bundler/vendor/thor/lib/thor/nested_context.rb
0 → 100644
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/bundler-2.3.21/lib/bundler/vendor/thor/lib/thor/parser/argument.rb
0 → 100644
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/bundler-2.3.21/lib/bundler/vendor/thor/lib/thor/parser/arguments.rb
0 → 100644
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/bundler-2.3.21/lib/bundler/vendor/thor/lib/thor/parser/option.rb
0 → 100644
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/bundler-2.3.21/lib/bundler/vendor/thor/lib/thor/parser/options.rb
0 → 100644
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/bundler-2.3.21/lib/bundler/vendor/thor/lib/thor/rake_compat.rb
0 → 100644
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/bundler-2.3.21/lib/bundler/vendor/thor/lib/thor/shell/basic.rb
0 → 100644
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/bundler-2.3.21/lib/bundler/vendor/thor/lib/thor/shell/color.rb
0 → 100644
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/bundler-2.3.21/lib/bundler/vendor/thor/lib/thor/shell/html.rb
0 → 100644
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/bundler-2.3.21/lib/bundler/vendor/uri/lib/uri/rfc2396_parser.rb
0 → 100644
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/bundler-2.3.21/lib/bundler/vendor/uri/lib/uri/rfc3986_parser.rb
0 → 100644
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/capistrano-3.17.1/features/step_definitions/cap_commands.rb
0 → 100644
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/capistrano-3.17.1/features/support/remote_command_helpers.rb
0 → 100644
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/capistrano-3.17.1/lib/capistrano/configuration/empty_filter.rb
0 → 100644
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/capistrano-3.17.1/lib/capistrano/configuration/host_filter.rb
0 → 100644
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/capistrano-3.17.1/lib/capistrano/configuration/null_filter.rb
0 → 100644
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/capistrano-3.17.1/lib/capistrano/configuration/plugin_installer.rb
0 → 100644
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/capistrano-3.17.1/lib/capistrano/configuration/role_filter.rb
0 → 100644
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/capistrano-3.17.1/lib/capistrano/configuration/scm_resolver.rb
0 → 100644
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/capistrano-3.17.1/lib/capistrano/configuration/validated_variables.rb
0 → 100644
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/capistrano-3.17.1/lib/capistrano/configuration/variables.rb
0 → 100644
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/capistrano-3.17.1/lib/capistrano/doctor/environment_doctor.rb
0 → 100644
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/capistrano-3.17.1/lib/capistrano/doctor/variables_doctor.rb
0 → 100644
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/capistrano-3.17.1/spec/lib/capistrano/configuration/filter_spec.rb
0 → 100644
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/capistrano-3.17.1/spec/lib/capistrano/configuration/question_spec.rb
0 → 100644
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/capistrano-3.17.1/spec/lib/capistrano/configuration/server_spec.rb
0 → 100644
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/capistrano-3.17.1/spec/lib/capistrano/configuration/servers_spec.rb
0 → 100644
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/capistrano-3.17.1/spec/lib/capistrano/configuration_spec.rb
0 → 100644
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/capistrano-3.17.1/spec/lib/capistrano/doctor/gems_doctor_spec.rb
0 → 100644
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/capistrano-3.17.1/spec/lib/capistrano/doctor/output_helpers_spec.rb
0 → 100644
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/capistrano-3.17.1/spec/lib/capistrano/doctor/servers_doctor_spec.rb
0 → 100644
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/capistrano-3.17.1/spec/lib/capistrano/doctor/variables_doctor_spec.rb
0 → 100644
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/capistrano-3.17.1/spec/lib/capistrano/dsl/task_enhancements_spec.rb
0 → 100644
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/capistrano-3.17.1/spec/lib/capistrano/immutable_task_spec.rb
0 → 100644
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/capistrano-3.17.1/spec/lib/capistrano/version_validator_spec.rb
0 → 100644
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/capistrano-3.4.0/features/support/remote_command_helpers.rb
0 → 100644
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/capistrano-3.4.0/spec/lib/capistrano/configuration/filter_spec.rb
0 → 100644
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/capistrano-3.4.0/spec/lib/capistrano/configuration/question_spec.rb
0 → 100644
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/capistrano-3.4.0/spec/lib/capistrano/configuration/server_spec.rb
0 → 100644
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/capistrano-3.4.0/spec/lib/capistrano/configuration/servers_spec.rb
0 → 100644
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/capistrano-3.4.0/spec/lib/capistrano/dsl/task_enhancements_spec.rb
0 → 100644
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/capistrano-3.4.0/spec/lib/capistrano/version_validator_spec.rb
0 → 100644
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/capistrano-composer-0.0.6/lib/capistrano/tasks/composer.rake
0 → 100644
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/concurrent-ruby-1.1.10/ext/concurrent-ruby/ConcurrentRubyService.java
0 → 100644
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff could not be displayed because it is too large.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff could not be displayed because it is too large.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/concurrent-ruby-1.1.10/lib/concurrent-ruby/concurrent-ruby.rb
0 → 100644
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/concurrent-ruby-1.1.10/lib/concurrent-ruby/concurrent/agent.rb
0 → 100644
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/concurrent-ruby-1.1.10/lib/concurrent-ruby/concurrent/array.rb
0 → 100644
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/concurrent-ruby-1.1.10/lib/concurrent-ruby/concurrent/async.rb
0 → 100644
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/concurrent-ruby-1.1.10/lib/concurrent-ruby/concurrent/atom.rb
0 → 100644
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/concurrent-ruby-1.1.10/lib/concurrent-ruby/concurrent/atomic/event.rb
0 → 100644
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/concurrent-ruby-1.1.10/lib/concurrent-ruby/concurrent/atomics.rb
0 → 100644
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
No preview for this file type
vendor/bundle/ruby/3.2.0/gems/concurrent-ruby-1.1.10/lib/concurrent-ruby/concurrent/configuration.rb
0 → 100644
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/concurrent-ruby-1.1.10/lib/concurrent-ruby/concurrent/constants.rb
0 → 100644
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/concurrent-ruby-1.1.10/lib/concurrent-ruby/concurrent/dataflow.rb
0 → 100644
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/concurrent-ruby-1.1.10/lib/concurrent-ruby/concurrent/delay.rb
0 → 100644
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/concurrent-ruby-1.1.10/lib/concurrent-ruby/concurrent/errors.rb
0 → 100644
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/concurrent-ruby-1.1.10/lib/concurrent-ruby/concurrent/exchanger.rb
0 → 100644
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/concurrent-ruby-1.1.10/lib/concurrent-ruby/concurrent/executors.rb
0 → 100644
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/concurrent-ruby-1.1.10/lib/concurrent-ruby/concurrent/future.rb
0 → 100644
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/concurrent-ruby-1.1.10/lib/concurrent-ruby/concurrent/hash.rb
0 → 100644
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/concurrent-ruby-1.1.10/lib/concurrent-ruby/concurrent/ivar.rb
0 → 100644
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/concurrent-ruby-1.1.10/lib/concurrent-ruby/concurrent/map.rb
0 → 100644
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/concurrent-ruby-1.1.10/lib/concurrent-ruby/concurrent/maybe.rb
0 → 100644
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/concurrent-ruby-1.1.10/lib/concurrent-ruby/concurrent/mvar.rb
0 → 100644
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/concurrent-ruby-1.1.10/lib/concurrent-ruby/concurrent/options.rb
0 → 100644
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/concurrent-ruby-1.1.10/lib/concurrent-ruby/concurrent/promise.rb
0 → 100644
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/concurrent-ruby-1.1.10/lib/concurrent-ruby/concurrent/promises.rb
0 → 100644
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/concurrent-ruby-1.1.10/lib/concurrent-ruby/concurrent/re_include.rb
0 → 100644
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/concurrent-ruby-1.1.10/lib/concurrent-ruby/concurrent/set.rb
0 → 100644
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/concurrent-ruby-1.1.10/lib/concurrent-ruby/concurrent/timer_task.rb
0 → 100644
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/concurrent-ruby-1.1.10/lib/concurrent-ruby/concurrent/tuple.rb
0 → 100644
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/concurrent-ruby-1.1.10/lib/concurrent-ruby/concurrent/tvar.rb
0 → 100644
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/concurrent-ruby-1.1.10/lib/concurrent-ruby/concurrent/version.rb
0 → 100644
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/net-ssh-3.0.2/lib/net/ssh/authentication/agent/java_pageant.rb
0 → 100644
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/net-ssh-3.0.2/lib/net/ssh/authentication/methods/abstract.rb
0 → 100644
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/net-ssh-3.0.2/lib/net/ssh/authentication/methods/hostbased.rb
0 → 100644
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/net-ssh-3.0.2/lib/net/ssh/authentication/methods/password.rb
0 → 100644
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/net-ssh-3.0.2/lib/net/ssh/authentication/methods/publickey.rb
0 → 100644
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/net-ssh-3.0.2/lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb
0 → 100644
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/net-ssh-3.0.2/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb
0 → 100644
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/net-ssh-3.0.2/lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb
0 → 100644
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/net-ssh-3.0.2/lib/net/ssh/transport/kex/ecdh_sha2_nistp384.rb
0 → 100644
This diff is collapsed.
Click to expand it.
vendor/bundle/ruby/3.2.0/gems/net-ssh-3.0.2/lib/net/ssh/transport/kex/ecdh_sha2_nistp521.rb
0 → 100644
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
-
Please register or sign in to post a comment