Skip to content

Commit

Permalink
Refactor directory initialization (#544)
Browse files Browse the repository at this point in the history
Signed-off-by: James Couball <jcouball@yahoo.com>
  • Loading branch information
jcouball committed Dec 20, 2021
1 parent 3884314 commit 8feb4ff
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 38 deletions.
135 changes: 100 additions & 35 deletions lib/git/base.rb
Expand Up @@ -12,43 +12,35 @@ class Base

# (see Git.bare)
def self.bare(git_dir, options = {})
self.new({:repository => git_dir}.merge(options))
normalize_paths(options, default_repository: git_dir, bare: true)
self.new(options)
end

# (see Git.clone)
def self.clone(repository, name, options = {})
self.new(Git::Lib.new(nil, options[:log]).clone(repository, name, options))
new_options = Git::Lib.new(nil, options[:log]).clone(repository, name, options)
normalize_paths(new_options, bare: options[:bare] || options[:mirror])
self.new(new_options)
end

# Returns (and initialize if needed) a Git::Config instance
#
# @return [Git::Config] the current config instance.
def self.config
return @@config ||= Config.new
@@config ||= Config.new
end

# (see Git.init)
def self.init(directory, options = {})
options[:working_directory] ||= directory
options[:repository] ||= File.join(options[:working_directory], '.git')

FileUtils.mkdir_p(options[:working_directory]) if options[:working_directory] && !File.directory?(options[:working_directory])
def self.init(directory = '.', options = {})
normalize_paths(options, default_working_directory: directory, default_repository: directory, bare: options[:bare])

init_options = {
:bare => options[:bare],
:initial_branch => options[:initial_branch],
}

options.delete(:working_directory) if options[:bare]

# Submodules have a .git *file* not a .git folder.
# This file's contents point to the location of
# where the git refs are held (In the parent repo)
if options[:working_directory] && File.file?(File.join(options[:working_directory], '.git'))
git_file = File.open('.git').read[8..-1].strip
options[:repository] = git_file
options[:index] = git_file + '/index'
end
directory = options[:bare] ? options[:repository] : options[:working_directory]
FileUtils.mkdir_p(directory) unless File.exist?(directory)

# TODO: this dance seems awkward: this creates a Git::Lib so we can call
# init so we can create a new Git::Base which in turn (ultimately)
Expand All @@ -66,21 +58,8 @@ def self.init(directory, options = {})
end

# (see Git.open)
def self.open(working_dir, options={})
# TODO: move this to Git.open?

options[:working_directory] ||= working_dir
options[:repository] ||= File.join(options[:working_directory], '.git')

# Submodules have a .git *file* not a .git folder.
# This file's contents point to the location of
# where the git refs are held (In the parent repo)
if options[:working_directory] && File.file?(File.join(options[:working_directory], '.git'))
git_file = File.open('.git').read[8..-1].strip
options[:repository] = git_file
options[:index] = git_file + '/index'
end

def self.open(working_dir, options = {})
normalize_paths(options, default_working_directory: working_dir)
self.new(options)
end

Expand Down Expand Up @@ -571,7 +550,6 @@ def with_temp_working &blk
with_working(temp_dir, &blk)
end


# runs git rev-parse to convert the objectish to a full sha
#
# @example
Expand All @@ -596,6 +574,93 @@ def current_branch
self.lib.branch_current
end

end
private

# Normalize options before they are sent to Git::Base.new
#
# Updates the options parameter by setting appropriate values for the following keys:
# * options[:working_directory]
# * options[:repository]
# * options[:index]
#
# All three values will be set to absolute paths. An exception is that
# :working_directory will be set to nil if bare is true.
#
private_class_method def self.normalize_paths(
options, default_working_directory: nil, default_repository: nil, bare: false
)
normalize_working_directory(options, default: default_working_directory, bare: bare)
normalize_repository(options, default: default_repository, bare: bare)
normalize_index(options)
end

# Normalize options[:working_directory]
#
# If working with a bare repository, set to `nil`.
# Otherwise, set to the first non-nil value of:
# 1. `options[:working_directory]`,
# 2. the `default` parameter, or
# 3. the current working directory
#
# Finally, if options[:working_directory] is a relative path, convert it to an absoluite
# path relative to the current directory.
#
private_class_method def self.normalize_working_directory(options, default:, bare: false)
working_directory =
if bare
nil
else
File.expand_path(options[:working_directory] || default || Dir.pwd)
end

options[:working_directory] = working_directory
end

# Normalize options[:repository]
#
# If working with a bare repository, set to the first non-nil value out of:
# 1. `options[:repository]`
# 2. the `default` parameter
# 3. the current working directory
#
# Otherwise, set to the first non-nil value of:
# 1. `options[:repository]`
# 2. `.git`
#
# Next, if options[:repository] refers to a *file* and not a *directory*, set
# options[:repository] to the contents of that file. This is the case when
# working with a submodule or a secondary working tree (created with git worktree
# add). In these cases the repository is actually contained/nested within the
# parent's repository directory.
#
# Finally, if options[:repository] is a relative path, convert it to an absolute
# path relative to:
# 1. the current directory if working with a bare repository or
# 2. the working directory if NOT working with a bare repository
#
private_class_method def self.normalize_repository(options, default:, bare: false)
repository =
if bare
File.expand_path(options[:repository] || default || Dir.pwd)
else
File.expand_path(options[:repository] || '.git', options[:working_directory])
end

if File.file?(repository)
repository = File.expand_path(File.open(repository).read[8..-1].strip, options[:working_directory])
end

options[:repository] = repository
end

# Normalize options[:index]
#
# If options[:index] is a relative directory, convert it to an absolute
# directory relative to the repository directory
#
private_class_method def self.normalize_index(options)
index = File.expand_path(options[:index] || 'index', options[:repository])
options[:index] = index
end
end
end
3 changes: 1 addition & 2 deletions tests/units/test_init.rb
Expand Up @@ -45,8 +45,7 @@ def test_git_init
def test_git_init_bare
in_temp_dir do |path|
repo = Git.init(path, :bare => true)
assert(File.directory?(File.join(path, '.git')))
assert(File.exist?(File.join(path, '.git', 'config')))
assert(File.exist?(File.join(path, 'config')))
assert_equal('true', repo.config('core.bare'))
end
end
Expand Down
2 changes: 1 addition & 1 deletion tests/units/test_thread_safety.rb
Expand Up @@ -24,7 +24,7 @@ def test_git_init_bare
threads.each(&:join)

dirs.each do |dir|
Git.bare("#{dir}/.git").ls_files
Git.bare(dir).ls_files
end
end
end

0 comments on commit 8feb4ff

Please sign in to comment.