Skip to content

Commit

Permalink
Merge pull request #15954 from Bo98/vendor-cleanup
Browse files Browse the repository at this point in the history
vendor/bundle/ruby: cleanup unneeded files
  • Loading branch information
MikeMcQuaid authored Sep 27, 2023
2 parents 39f76d6 + 5820494 commit e501853
Show file tree
Hide file tree
Showing 530 changed files with 557 additions and 49,151 deletions.
54 changes: 54 additions & 0 deletions .github/workflows/vendor-gems.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,60 @@ permissions:
pull-requests: read

jobs:
check-vendor-version:
if: github.event_name == 'pull_request'
runs-on: ubuntu-22.04
steps:
- name: Set up Homebrew
id: set-up-homebrew
uses: Homebrew/actions/setup-homebrew@master
with:
core: false
cask: false
test-bot: false

- name: Install Bundler RubyGems
run: brew install-bundler-gems --groups=all

- name: Get Ruby ABI version
id: ruby-abi
run: echo "version=$(brew ruby -e "puts Gem.ruby_api_version")" >> "${GITHUB_OUTPUT}"

- name: Get gem info
id: gem-info
working-directory: ${{ steps.set-up-homebrew.outputs.gems-path }}/${{ steps.ruby-abi.outputs.version }}/gems
run: |
{
echo "vendor-version=$(cat ../.homebrew_vendor_version)"
echo "ignored<<EOS"
git check-ignore -- *
echo "EOS"
} >> "${GITHUB_OUTPUT}"
- name: Compare to base ref
working-directory: ${{ steps.set-up-homebrew.outputs.gems-path }}/${{ steps.ruby-abi.outputs.version }}
run: |
git checkout "origin/${GITHUB_BASE_REF}"
rm .homebrew_vendor_version
brew install-bundler-gems --groups=all
if [[ "$(cat .homebrew_vendor_version)" == "${{ steps.gem-info.outputs.vendor-version }}" ]]; then
ignored_gems="${{ steps.gem-info.outputs.ignored }}"
while IFS= read -r gem; do
gem_dir="./gems/${gem}"
[[ -d "${gem_dir}" ]] || continue
exit_code=0
git check-ignore --quiet "${gem_dir}" || exit_code=$?
if (( exit_code != 0 )); then
if (( exit_code == 1 )); then
echo "::error::VENDOR_VERSION needs bumping in utils/gems.rb" >&2
else
echo "::error::git check-ignore failed" >&2
fi
exit "${exit_code}"
fi
done <<< "${ignored_gems}"
fi
vendor-gems:
if: >
github.repository_owner == 'Homebrew' && (
Expand Down
221 changes: 35 additions & 186 deletions .gitignore

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Library/Homebrew/livecheck/livecheck.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
require "livecheck/skip_conditions"
require "livecheck/strategy"
require "addressable"
require "ruby-progressbar"
require "uri"

module Homebrew
Expand Down Expand Up @@ -208,6 +207,7 @@ def run_checks(
stderr.puts Formatter.headline("Running checks", color: :blue)
end

require "ruby-progressbar"
progress = ProgressBar.create(
total: formulae_and_casks_total,
progress_mark: "#",
Expand Down
2 changes: 2 additions & 0 deletions Library/Homebrew/sorbet/rbi/upstream.rbi
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,5 @@ module Kernel
sig { params(arg0: NilClass).returns(NilClass) }
def set_trace_func(arg0); end
end

class Gem::Security::Exception < Gem::Exception; end
78 changes: 74 additions & 4 deletions Library/Homebrew/utils/gems.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,44 @@ module Homebrew
# After updating this, run `brew vendor-gems --update=--bundler`.
HOMEBREW_BUNDLER_VERSION = "2.4.18"

GEM_GROUPS_FILE = (HOMEBREW_LIBRARY_PATH/"vendor/bundle/ruby/.homebrew_gem_groups").freeze
# Bump this whenever a committed vendored gem is later added to gitignore.
# This will trigger it to reinstall properly if `brew install-bundler-gems` needs it.
VENDOR_VERSION = 1
private_constant :VENDOR_VERSION

RUBY_BUNDLE_VENDOR_DIRECTORY = (HOMEBREW_LIBRARY_PATH/"vendor/bundle/ruby").freeze
private_constant :RUBY_BUNDLE_VENDOR_DIRECTORY

# This is tracked across Ruby versions.
GEM_GROUPS_FILE = (RUBY_BUNDLE_VENDOR_DIRECTORY/".homebrew_gem_groups").freeze
private_constant :GEM_GROUPS_FILE

# This is tracked per Ruby version.
VENDOR_VERSION_FILE = (
RUBY_BUNDLE_VENDOR_DIRECTORY/"#{RbConfig::CONFIG["ruby_version"]}/.homebrew_vendor_version"
).freeze
private_constant :VENDOR_VERSION_FILE

module_function

# @api private
def gemfile
File.join(ENV.fetch("HOMEBREW_LIBRARY"), "Homebrew", "Gemfile")
end

# @api private
def bundler_definition
@bundler_definition ||= Bundler::Definition.build(Bundler.default_gemfile, Bundler.default_lockfile, false)
end

# @api private
def valid_gem_groups
install_bundler!
require "bundler"

Bundler.with_unbundled_env do
ENV["BUNDLE_GEMFILE"] = gemfile
groups = Bundler::Definition.build(Bundler.default_gemfile, Bundler.default_lockfile, false).groups
groups = bundler_definition.groups
groups.delete(:default)
groups.map(&:to_s)
end
Expand Down Expand Up @@ -71,7 +91,7 @@ def setup_gem_environment!(setup_path: true)
ENV["BUNDLER_NO_OLD_RUBYGEMS_WARNING"] = "1"

# Match where our bundler gems are.
gem_home = "#{HOMEBREW_LIBRARY_PATH}/vendor/bundle/ruby/#{RbConfig::CONFIG["ruby_version"]}"
gem_home = "#{RUBY_BUNDLE_VENDOR_DIRECTORY}/#{RbConfig::CONFIG["ruby_version"]}"
Gem.paths = {
"GEM_HOME" => gem_home,
"GEM_PATH" => gem_home,
Expand Down Expand Up @@ -181,6 +201,14 @@ def forget_user_gem_groups!
end
end

def user_vendor_version
@user_vendor_version ||= if VENDOR_VERSION_FILE.exist?
VENDOR_VERSION_FILE.read.to_i
else
0
end
end

def install_bundler_gems!(only_warn_on_failure: false, setup_path: true, groups: [])
old_path = ENV.fetch("PATH", nil)
old_gem_path = ENV.fetch("GEM_PATH", nil)
Expand Down Expand Up @@ -229,7 +257,49 @@ def install_bundler_gems!(only_warn_on_failure: false, setup_path: true, groups:
bundle_check_failed = !$CHILD_STATUS.success?

# for some reason sometimes the exit code lies so check the output too.
bundle_installed = if bundle_check_failed || bundle_check_output.include?("Install missing gems")
bundle_install_required = bundle_check_failed || bundle_check_output.include?("Install missing gems")

if user_vendor_version != VENDOR_VERSION
# Check if the install is intact. This is useful if any gems are added to gitignore.
# We intentionally map over everything and then call `any?` so that we remove the spec of each bad gem.
specs = bundler_definition.resolve.materialize(bundler_definition.locked_dependencies)
vendor_reinstall_required = specs.map do |spec|
spec_file = "#{Gem.dir}/specifications/#{spec.full_name}.gemspec"
next false unless File.exist?(spec_file)

cache_file = "#{Gem.dir}/cache/#{spec.full_name}.gem"
if File.exist?(cache_file)
require "rubygems/package"
package = Gem::Package.new(cache_file)

package_install_intact = begin
contents = package.contents

# If the gem has contents, ensure we have every file installed it contains.
contents&.all? do |gem_file|
File.exist?("#{Gem.dir}/gems/#{spec.full_name}/#{gem_file}")
end
rescue Gem::Package::Error, Gem::Security::Exception
# Malformed, assume broken
File.unlink(cache_file)
false
end

next false if package_install_intact
end

# Mark gem for reinstallation
File.unlink(spec_file)
true
end.any?

VENDOR_VERSION_FILE.dirname.mkpath
VENDOR_VERSION_FILE.write(VENDOR_VERSION.to_s)

bundle_install_required ||= vendor_reinstall_required
end

bundle_installed = if bundle_install_required
if system bundle, "install"
true
else
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
Copyright (c) 2005-2022 David Heinemeier Hansson

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

This file was deleted.

This file was deleted.

This file was deleted.

Loading

0 comments on commit e501853

Please sign in to comment.