From 4a969a04cc4d0333b6f0ac3eafcbcb9a4857ee16 Mon Sep 17 00:00:00 2001 From: James Couball Date: Tue, 26 Dec 2023 16:51:25 -0800 Subject: [PATCH 1/3] Do not change ENV variables of a current process Instead pass relevant environment to the actual shell command being run Signed-off-by: James Couball --- lib/git/base.rb | 6 +++-- lib/git/lib.rb | 67 ++++++++----------------------------------------- 2 files changed, 15 insertions(+), 58 deletions(-) diff --git a/lib/git/base.rb b/lib/git/base.rb index 93dcf16e..99a7b719 100644 --- a/lib/git/base.rb +++ b/lib/git/base.rb @@ -69,8 +69,10 @@ def self.root_of_worktree(working_dir) status = nil git_cmd = "#{Git::Base.config.binary_path} -c core.quotePath=true -c color.ui=false rev-parse --show-toplevel 2>&1" - result, status = Open3.capture2(git_cmd, chdir: File.expand_path(working_dir)) - result = result.chomp + IO.popen(git_cmd, :chdir => working_dir) do |io| + status = Process.wait2(io.pid).last + result = io.read.chomp + end raise ArgumentError, "'#{working_dir}' is not in a git working tree" unless status.success? result diff --git a/lib/git/lib.rb b/lib/git/lib.rb index 86c34a85..36494fc3 100644 --- a/lib/git/lib.rb +++ b/lib/git/lib.rb @@ -7,8 +7,6 @@ module Git class Lib - @@semaphore = Mutex.new - # The path to the Git working copy. The default is '"./.git"'. # # @return [Pathname] the path to the Git working copy. @@ -442,10 +440,7 @@ def worktree_prune def list_files(ref_dir) dir = File.join(@git_dir, 'refs', ref_dir) files = [] - begin - files = Dir.glob('**/*', base: dir).select { |f| File.file?(File.join(dir, f)) } - rescue - end + files = Dir.glob(File.join(dir, '**/*')).select { |f| File.file?(f) } rescue nil files end @@ -1146,41 +1141,14 @@ def command_lines(cmd, *opts, chdir: nil) op.split("\n") end - # Takes the current git's system ENV variables and store them. - def store_git_system_env_variables - @git_system_env_variables = {} - ENV_VARIABLE_NAMES.each do |env_variable_name| - @git_system_env_variables[env_variable_name] = ENV[env_variable_name] - end - end - - # Takes the previously stored git's ENV variables and set them again on ENV. - def restore_git_system_env_variables - ENV_VARIABLE_NAMES.each do |env_variable_name| - ENV[env_variable_name] = @git_system_env_variables[env_variable_name] - end - end - - # Sets git's ENV variables to the custom values for the current instance. - def set_custom_git_env_variables - ENV['GIT_DIR'] = @git_dir - ENV['GIT_WORK_TREE'] = @git_work_dir - ENV['GIT_INDEX_FILE'] = @git_index_file - ENV['GIT_SSH'] = Git::Base.config.git_ssh - end - - # Runs a block inside an environment with customized ENV variables. - # It restores the ENV after execution. - # - # @param [Proc] block block to be executed within the customized environment - def with_custom_env_variables(&block) - @@semaphore.synchronize do - store_git_system_env_variables() - set_custom_git_env_variables() - return block.call() - end - ensure - restore_git_system_env_variables() + # git's ENV variables for the current instance. + def custom_git_env_variables + { + 'GIT_DIR' => @git_dir, + 'GIT_WORK_TREE' => @git_work_dir, + 'GIT_INDEX_FILE' => @git_index_file, + 'GIT_SSH' => Git::Base.config.git_ssh, + } end def command(*cmd, redirect: '', chomp: true, chdir: nil, &block) @@ -1200,18 +1168,7 @@ def command(*cmd, redirect: '', chomp: true, chdir: nil, &block) git_cmd = "#{Git::Base.config.binary_path} #{global_opts} #{escaped_cmd} #{redirect} 2>&1" - output = nil - - command_thread = nil; - - status = nil - - with_custom_env_variables do - command_thread = Thread.new do - output, status = run_command(git_cmd, chdir, &block) - end - command_thread.join - end + output, status = run_command(git_cmd, chdir, &block) @logger.info(git_cmd) @logger.debug(output) @@ -1298,9 +1255,7 @@ def run_command(git_cmd, chdir=nil, &block) opts = {} opts[:chdir] = File.expand_path(chdir) if chdir - Open3.popen2(git_cmd, opts) do |stdin, stdout, wait_thr| - [block.call(stdout), wait_thr.value] - end + [IO.popen(custom_git_env_variables, git_cmd, opts, &block), $?] end def escape(s) From 4231e94cf8a382c0769c63d937079d753905d561 Mon Sep 17 00:00:00 2001 From: James Couball Date: Tue, 26 Dec 2023 18:10:22 -0800 Subject: [PATCH 2/3] Test using Open3.popen2 instead of IO.popen Signed-off-by: James Couball --- lib/git/base.rb | 21 ++++++++++++++++++--- lib/git/lib.rb | 15 ++++++++++++++- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/lib/git/base.rb b/lib/git/base.rb index 99a7b719..3f7d3c9e 100644 --- a/lib/git/base.rb +++ b/lib/git/base.rb @@ -69,11 +69,26 @@ def self.root_of_worktree(working_dir) status = nil git_cmd = "#{Git::Base.config.binary_path} -c core.quotePath=true -c color.ui=false rev-parse --show-toplevel 2>&1" - IO.popen(git_cmd, :chdir => working_dir) do |io| - status = Process.wait2(io.pid).last - result = io.read.chomp + + # Option 1 using IO.popen + # + # IO.popen(git_cmd, :chdir => working_dir) do |io| + # status = Process.wait2(io.pid).last + # result = io.read.chomp + # end + + # Option 2 using Open3.popen2 + # + Open3.popen2(git_cmd, chdir: working_dir) do |stdin, stdout, wait_thr| + status = wait_thr.value + result = stdout.chomp end + # Option 3 using Open3.capture3 + # + # stdout_s, stderr_s, status = Open3.capture3(custom_git_env_variables, git_cmd, opts) + # result = status_s + raise ArgumentError, "'#{working_dir}' is not in a git working tree" unless status.success? result end diff --git a/lib/git/lib.rb b/lib/git/lib.rb index 36494fc3..2a1f1ded 100644 --- a/lib/git/lib.rb +++ b/lib/git/lib.rb @@ -1255,7 +1255,20 @@ def run_command(git_cmd, chdir=nil, &block) opts = {} opts[:chdir] = File.expand_path(chdir) if chdir - [IO.popen(custom_git_env_variables, git_cmd, opts, &block), $?] + # Option 1 using IO.popen + # + # [IO.popen(custom_git_env_variables, git_cmd, opts, &block), $?] + + # Option 2 using Open3.popen2 + # + Open3.popen2(custom_git_env_variables, git_cmd, opts) do |stdin, stdout, wait_thr| + [block.call(stdout), wait_thr.value] + end + + # Option 3 using Open3.capture3 + # + # stdout_s, stderr_s, status = Open3.capture3(custom_git_env_variables, git_cmd, opts) + # [block.call(StringIO.new(stdout_s)), status] end def escape(s) From d684854e6e1c7be2c078881cb8e6708099ac1ced Mon Sep 17 00:00:00 2001 From: James Couball Date: Tue, 26 Dec 2023 18:25:50 -0800 Subject: [PATCH 3/3] Use Open3.capture3 instead of IO.popen Signed-off-by: James Couball --- lib/git/base.rb | 15 ++++++++------- lib/git/lib.rb | 11 ++++++----- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/lib/git/base.rb b/lib/git/base.rb index 3f7d3c9e..1b826ccb 100644 --- a/lib/git/base.rb +++ b/lib/git/base.rb @@ -72,24 +72,25 @@ def self.root_of_worktree(working_dir) # Option 1 using IO.popen # - # IO.popen(git_cmd, :chdir => working_dir) do |io| + # IO.popen(git_cmd, chdir: working_dir) do |io| # status = Process.wait2(io.pid).last # result = io.read.chomp # end # Option 2 using Open3.popen2 # - Open3.popen2(git_cmd, chdir: working_dir) do |stdin, stdout, wait_thr| - status = wait_thr.value - result = stdout.chomp - end + # Open3.popen2(git_cmd, chdir: working_dir) do |stdin, stdout, wait_thr| + # status = wait_thr.value + # result = stdout.read.chomp + # end # Option 3 using Open3.capture3 # - # stdout_s, stderr_s, status = Open3.capture3(custom_git_env_variables, git_cmd, opts) - # result = status_s + stdout_s, stderr_s, status = Open3.capture3(git_cmd, chdir: working_dir) + result = stdout_s.chomp raise ArgumentError, "'#{working_dir}' is not in a git working tree" unless status.success? + result end diff --git a/lib/git/lib.rb b/lib/git/lib.rb index 2a1f1ded..453776c6 100644 --- a/lib/git/lib.rb +++ b/lib/git/lib.rb @@ -3,6 +3,7 @@ require 'tempfile' require 'zlib' require 'open3' +require 'stringio' module Git class Lib @@ -1261,14 +1262,14 @@ def run_command(git_cmd, chdir=nil, &block) # Option 2 using Open3.popen2 # - Open3.popen2(custom_git_env_variables, git_cmd, opts) do |stdin, stdout, wait_thr| - [block.call(stdout), wait_thr.value] - end + # Open3.popen2(custom_git_env_variables, git_cmd, opts) do |stdin, stdout, wait_thr| + # [block.call(stdout), wait_thr.value] + # end # Option 3 using Open3.capture3 # - # stdout_s, stderr_s, status = Open3.capture3(custom_git_env_variables, git_cmd, opts) - # [block.call(StringIO.new(stdout_s)), status] + stdout_s, stderr_s, status = Open3.capture3(custom_git_env_variables, git_cmd, opts) + [block.call(StringIO.new(stdout_s)), status] end def escape(s)