diff --git a/Library/Homebrew/bundle/brewfile.rb b/Library/Homebrew/bundle/brewfile.rb index 60e1a1fba4a61..77354a682835e 100644 --- a/Library/Homebrew/bundle/brewfile.rb +++ b/Library/Homebrew/bundle/brewfile.rb @@ -24,7 +24,21 @@ def self.path(dash_writes_to_stdout: false, global: false, file: nil) else raise "'HOMEBREW_BUNDLE_FILE' cannot be specified with '--global'" if env_bundle_file.present? - if user_config_home && File.exist?("#{user_config_home}/Brewfile") + # Determine if we're in XDG mode by checking if user_config_home is XDG-based + # In bin/brew: XDG_CONFIG_HOME set -> HOMEBREW_USER_CONFIG_HOME="${XDG_CONFIG_HOME}/homebrew" + # XDG_CONFIG_HOME not set -> HOMEBREW_USER_CONFIG_HOME="${HOME}/.homebrew" + using_xdg = user_config_home&.end_with?("/homebrew") + + if using_xdg && user_config_home + # XDG mode: check both XDG and legacy locations, preferring existing files + xdg_brewfile = "#{user_config_home}/Brewfile" + if File.exist?(xdg_brewfile) + xdg_brewfile + else + legacy_brewfile = Bundle.exchange_uid_if_needed! { "#{Dir.home}/.Brewfile" } + File.exist?(legacy_brewfile) ? legacy_brewfile : xdg_brewfile + end + elsif user_config_home && File.exist?("#{user_config_home}/Brewfile") "#{user_config_home}/Brewfile" else Bundle.exchange_uid_if_needed! do diff --git a/Library/Homebrew/bundle/dumper.rb b/Library/Homebrew/bundle/dumper.rb index 218b297890ef6..c48687583a1a7 100644 --- a/Library/Homebrew/bundle/dumper.rb +++ b/Library/Homebrew/bundle/dumper.rb @@ -81,6 +81,7 @@ def self.brewfile_path(global: false, file: nil) sig { params(file: Pathname, content: String).void } def self.write_file(file, content) Bundle.exchange_uid_if_needed! do + file.parent.mkpath file.open("w") { |io| io.write content } end end diff --git a/Library/Homebrew/test/bundle/brewfile_spec.rb b/Library/Homebrew/test/bundle/brewfile_spec.rb index 9be511c2a5628..a8bcf75c58a2b 100644 --- a/Library/Homebrew/test/bundle/brewfile_spec.rb +++ b/Library/Homebrew/test/bundle/brewfile_spec.rb @@ -26,8 +26,12 @@ allow(ENV).to receive(:fetch).with("HOMEBREW_USER_CONFIG_HOME", any_args) .and_return(env_user_config_home_value) + allow(ENV).to receive(:[]).with("XDG_CONFIG_HOME").and_return(nil) allow(File).to receive(:exist?).with("/Users/username/.homebrew/Brewfile") .and_return(config_dir_brewfile_exist) + # Allow any other File.exist? calls and Dir.home calls for flexibility + allow(File).to receive(:exist?).and_return(false) + allow(Dir).to receive(:home).and_return("/Users/username") end context "when `file` is specified with a relative path" do @@ -171,6 +175,33 @@ expect(path).to eq(expected_pathname) end end + + context "when HOMEBREW_USER_CONFIG_HOME is set but neither Brewfile exists" do + let(:config_dir_brewfile_exist) { false } + + context "when XDG_CONFIG_HOME is set" do + before do + allow(ENV).to receive(:[]).with("XDG_CONFIG_HOME").and_return("/custom/xdg") + # Mock that both XDG and legacy Brewfiles don't exist + allow(File).to receive(:exist?).with("/Users/username/.homebrew/Brewfile").and_return(false) + allow(File).to receive(:exist?).with("#{Dir.home}/.Brewfile").and_return(false) + end + + it "returns the XDG path for initial Brewfile creation" do + expect(path).to eq(Pathname.new("#{env_user_config_home_value}/Brewfile")) + end + end + + context "when XDG_CONFIG_HOME is not set" do + before do + allow(ENV).to receive(:[]).with("XDG_CONFIG_HOME").and_return(nil) + end + + it "returns the legacy path" do + expect(path).to eq(Pathname.new("#{Dir.home}/.Brewfile")) + end + end + end end context "when HOMEBREW_BUNDLE_FILE has a value" do