Skip to content

Commit 8feb4ff

Browse files
authored
Refactor directory initialization (#544)
Signed-off-by: James Couball <jcouball@yahoo.com>
1 parent 3884314 commit 8feb4ff

File tree

3 files changed

+102
-38
lines changed

3 files changed

+102
-38
lines changed

lib/git/base.rb

Lines changed: 100 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -12,43 +12,35 @@ class Base
1212

1313
# (see Git.bare)
1414
def self.bare(git_dir, options = {})
15-
self.new({:repository => git_dir}.merge(options))
15+
normalize_paths(options, default_repository: git_dir, bare: true)
16+
self.new(options)
1617
end
1718

1819
# (see Git.clone)
1920
def self.clone(repository, name, options = {})
20-
self.new(Git::Lib.new(nil, options[:log]).clone(repository, name, options))
21+
new_options = Git::Lib.new(nil, options[:log]).clone(repository, name, options)
22+
normalize_paths(new_options, bare: options[:bare] || options[:mirror])
23+
self.new(new_options)
2124
end
2225

2326
# Returns (and initialize if needed) a Git::Config instance
2427
#
2528
# @return [Git::Config] the current config instance.
2629
def self.config
27-
return @@config ||= Config.new
30+
@@config ||= Config.new
2831
end
2932

3033
# (see Git.init)
31-
def self.init(directory, options = {})
32-
options[:working_directory] ||= directory
33-
options[:repository] ||= File.join(options[:working_directory], '.git')
34-
35-
FileUtils.mkdir_p(options[:working_directory]) if options[:working_directory] && !File.directory?(options[:working_directory])
34+
def self.init(directory = '.', options = {})
35+
normalize_paths(options, default_working_directory: directory, default_repository: directory, bare: options[:bare])
3636

3737
init_options = {
3838
:bare => options[:bare],
3939
:initial_branch => options[:initial_branch],
4040
}
4141

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

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

6860
# (see Git.open)
69-
def self.open(working_dir, options={})
70-
# TODO: move this to Git.open?
71-
72-
options[:working_directory] ||= working_dir
73-
options[:repository] ||= File.join(options[:working_directory], '.git')
74-
75-
# Submodules have a .git *file* not a .git folder.
76-
# This file's contents point to the location of
77-
# where the git refs are held (In the parent repo)
78-
if options[:working_directory] && File.file?(File.join(options[:working_directory], '.git'))
79-
git_file = File.open('.git').read[8..-1].strip
80-
options[:repository] = git_file
81-
options[:index] = git_file + '/index'
82-
end
83-
61+
def self.open(working_dir, options = {})
62+
normalize_paths(options, default_working_directory: working_dir)
8463
self.new(options)
8564
end
8665

@@ -571,7 +550,6 @@ def with_temp_working &blk
571550
with_working(temp_dir, &blk)
572551
end
573552

574-
575553
# runs git rev-parse to convert the objectish to a full sha
576554
#
577555
# @example
@@ -596,6 +574,93 @@ def current_branch
596574
self.lib.branch_current
597575
end
598576

599-
end
577+
private
578+
579+
# Normalize options before they are sent to Git::Base.new
580+
#
581+
# Updates the options parameter by setting appropriate values for the following keys:
582+
# * options[:working_directory]
583+
# * options[:repository]
584+
# * options[:index]
585+
#
586+
# All three values will be set to absolute paths. An exception is that
587+
# :working_directory will be set to nil if bare is true.
588+
#
589+
private_class_method def self.normalize_paths(
590+
options, default_working_directory: nil, default_repository: nil, bare: false
591+
)
592+
normalize_working_directory(options, default: default_working_directory, bare: bare)
593+
normalize_repository(options, default: default_repository, bare: bare)
594+
normalize_index(options)
595+
end
596+
597+
# Normalize options[:working_directory]
598+
#
599+
# If working with a bare repository, set to `nil`.
600+
# Otherwise, set to the first non-nil value of:
601+
# 1. `options[:working_directory]`,
602+
# 2. the `default` parameter, or
603+
# 3. the current working directory
604+
#
605+
# Finally, if options[:working_directory] is a relative path, convert it to an absoluite
606+
# path relative to the current directory.
607+
#
608+
private_class_method def self.normalize_working_directory(options, default:, bare: false)
609+
working_directory =
610+
if bare
611+
nil
612+
else
613+
File.expand_path(options[:working_directory] || default || Dir.pwd)
614+
end
600615

616+
options[:working_directory] = working_directory
617+
end
618+
619+
# Normalize options[:repository]
620+
#
621+
# If working with a bare repository, set to the first non-nil value out of:
622+
# 1. `options[:repository]`
623+
# 2. the `default` parameter
624+
# 3. the current working directory
625+
#
626+
# Otherwise, set to the first non-nil value of:
627+
# 1. `options[:repository]`
628+
# 2. `.git`
629+
#
630+
# Next, if options[:repository] refers to a *file* and not a *directory*, set
631+
# options[:repository] to the contents of that file. This is the case when
632+
# working with a submodule or a secondary working tree (created with git worktree
633+
# add). In these cases the repository is actually contained/nested within the
634+
# parent's repository directory.
635+
#
636+
# Finally, if options[:repository] is a relative path, convert it to an absolute
637+
# path relative to:
638+
# 1. the current directory if working with a bare repository or
639+
# 2. the working directory if NOT working with a bare repository
640+
#
641+
private_class_method def self.normalize_repository(options, default:, bare: false)
642+
repository =
643+
if bare
644+
File.expand_path(options[:repository] || default || Dir.pwd)
645+
else
646+
File.expand_path(options[:repository] || '.git', options[:working_directory])
647+
end
648+
649+
if File.file?(repository)
650+
repository = File.expand_path(File.open(repository).read[8..-1].strip, options[:working_directory])
651+
end
652+
653+
options[:repository] = repository
654+
end
655+
656+
# Normalize options[:index]
657+
#
658+
# If options[:index] is a relative directory, convert it to an absolute
659+
# directory relative to the repository directory
660+
#
661+
private_class_method def self.normalize_index(options)
662+
index = File.expand_path(options[:index] || 'index', options[:repository])
663+
options[:index] = index
664+
end
665+
end
601666
end

tests/units/test_init.rb

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,7 @@ def test_git_init
4545
def test_git_init_bare
4646
in_temp_dir do |path|
4747
repo = Git.init(path, :bare => true)
48-
assert(File.directory?(File.join(path, '.git')))
49-
assert(File.exist?(File.join(path, '.git', 'config')))
48+
assert(File.exist?(File.join(path, 'config')))
5049
assert_equal('true', repo.config('core.bare'))
5150
end
5251
end

tests/units/test_thread_safety.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ def test_git_init_bare
2424
threads.each(&:join)
2525

2626
dirs.each do |dir|
27-
Git.bare("#{dir}/.git").ls_files
27+
Git.bare(dir).ls_files
2828
end
2929
end
3030
end

0 commit comments

Comments
 (0)