Class: RubyLens::GitRepository

Inherits:
Object
  • Object
show all
Defined in:
lib/rubylens/git_repository.rb

Constant Summary collapse

INDEXABLE_EXTENSIONS =
%w[.rb .rake .rbs .ru].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(target_root) ⇒ GitRepository

Returns a new instance of GitRepository.

Raises:



13
14
15
16
17
18
19
20
21
22
23
24
# File 'lib/rubylens/git_repository.rb', line 13

def initialize(target_root)
  @target_root = Pathname(target_root).expand_path.realpath
  raise ExtractionError, "target is not a directory" unless @target_root.directory?

  top, status = capture("rev-parse", "--show-toplevel")
  raise ExtractionError, "target must be inside a Git repository" unless status.success?

  @git_root = Pathname(top.strip).realpath
  unless Paths.inside?(@target_root, @git_root)
    raise ExtractionError, "target is outside its reported Git repository"
  end
end

Instance Attribute Details

#git_rootObject (readonly)

Returns the value of attribute git_root.



11
12
13
# File 'lib/rubylens/git_repository.rb', line 11

def git_root
  @git_root
end

#target_rootObject (readonly)

Returns the value of attribute target_root.



11
12
13
# File 'lib/rubylens/git_repository.rb', line 11

def target_root
  @target_root
end

Instance Method Details

#exclude_local(path, description: "report") ⇒ Object

Raises:



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/rubylens/git_repository.rb', line 58

def exclude_local(path, description: "report")
  path = Pathname(path).expand_path
  path = path.dirname.realpath.join(path.basename)
  raise ExtractionError, "local exclude path is outside the Git repository" unless Paths.inside?(path, @git_root)

  exclude_output, status = capture("rev-parse", "--git-path", "info/exclude")
  raise ExtractionError, "failed to locate Git's local exclude file" unless status.success?

  exclude_path = Pathname(exclude_output.strip)
  exclude_path = @git_root.join(exclude_path) unless exclude_path.absolute?
  FileUtils.mkdir_p(exclude_path.dirname)
  relative = path.relative_path_from(@git_root).to_s
  _tracked_output, tracked_status = capture("ls-files", "--error-unmatch", "--", relative)
  raise ExtractionError, "default #{description} path is already tracked by Git" if tracked_status.success?

  directory = File.dirname(relative)
  basename = File.basename(relative)
  escaped_report = escape_ignore_path(relative)
  escaped_temporary = ".#{escape_ignore_path(basename)}.*.tmp"
  escaped_temporary = "#{escape_ignore_path(directory)}/#{escaped_temporary}" unless directory == "."
  entries = ["/#{escaped_report}", "/#{escaped_temporary}"]
  File.open(exclude_path, File::RDWR | File::CREAT, 0o600) do |file|
    file.flock(File::LOCK_EX)
    file.rewind
    contents = file.read
    existing = contents.each_line.map(&:chomp)
    missing = entries - existing
    return false if missing.empty?

    file.seek(0, IO::SEEK_END)
    file.write("\n") if !contents.empty? && !contents.end_with?("\n")
    file.write("#{missing.join("\n")}\n")
  end
  true
end

#metadataObject

Raises:



26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/rubylens/git_repository.rb', line 26

def 
  head, head_status = capture("rev-parse", "--verify", "HEAD")
  branch, branch_status = capture("symbolic-ref", "--quiet", "--short", "HEAD")
  status_output, status_status = capture("status", "--porcelain=v1", "--untracked-files=normal")
  raise ExtractionError, "failed to read Git status" unless status_status.success?

  {
    "head" => head_status.success? ? head.strip : nil,
    "branch" => branch_status.success? ? branch.strip : nil,
    "dirty" => !status_output.empty?,
  }
end

#selected_filesObject

Raises:



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/rubylens/git_repository.rb', line 39

def selected_files
  output, status = capture("ls-files", "-z", "--cached", "--others", "--exclude-standard")
  raise ExtractionError, "failed to enumerate tracked and unignored files" unless status.success?

  output.split("\0").filter_map do |relative_to_git|
    next unless INDEXABLE_EXTENSIONS.include?(File.extname(relative_to_git))

    absolute = @git_root.join(relative_to_git).cleanpath
    next unless Paths.inside?(absolute, @target_root)
    next unless absolute.file?
    resolved = absolute.realpath
    next unless Paths.inside?(resolved, @target_root.realpath)

    resolved.to_s
  rescue Errno::ENOENT, Errno::EACCES, Errno::ELOOP
    nil
  end.sort
end