Module: Pray::GitSources

Defined in:
lib/pray/git_sources.rb

Class Method Summary collapse

Class Method Details

.apply_sparse_checkout(repository, subdir) ⇒ Object



180
181
182
183
# File 'lib/pray/git_sources.rb', line 180

def apply_sparse_checkout(repository, subdir)
  run_git_in_repo(repository, "sparse-checkout", "init", "--cone")
  run_git_in_repo(repository, "sparse-checkout", "set", subdir)
end

.cache_key(text) ⇒ Object



121
122
123
# File 'lib/pray/git_sources.rb', line 121

def cache_key(text)
  Hashing.sha256_prefixed(text)[7, 16]
end

.checkout_git_revision(repository, _clone_url, revision, refresh) ⇒ Object



185
186
187
188
# File 'lib/pray/git_sources.rb', line 185

def checkout_git_revision(repository, _clone_url, revision, refresh)
  run_git_in_repo(repository, "fetch", "--depth", "1", "origin", revision) if refresh
  run_git_in_repo(repository, "checkout", "--force", revision)
end

.command_error(program, output) ⇒ Object



223
224
225
226
# File 'lib/pray/git_sources.rb', line 223

def command_error(program, output)
  message = output.strip
  message.empty? ? "#{program} failed" : "#{program} failed: #{message}"
end

.discover_distribution_root(path) ⇒ Object



66
67
68
69
70
71
72
73
# File 'lib/pray/git_sources.rb', line 66

def discover_distribution_root(path)
  return path if local_distribution_root?(path)

  prayers_root = File.join(path, "prayers")
  return prayers_root if local_distribution_root?(prayers_root)

  nil
end

.ensure_git_repository(project_root, clone_url, refresh:, pinned_revision:, sparse_subdir:) ⇒ Object



90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/pray/git_sources.rb', line 90

def ensure_git_repository(project_root, clone_url, refresh:, pinned_revision:, sparse_subdir:)
  cache_directory = git_source_cache_directory(project_root, clone_url)
  if File.directory?(File.join(cache_directory, ".git"))
    refresh_global_git_cache(clone_url) if refresh
    if pinned_revision
      checkout_git_revision(cache_directory, clone_url, pinned_revision, refresh)
    elsif refresh
      refresh_git_worktree(cache_directory, clone_url)
    end
    apply_sparse_checkout(cache_directory, sparse_subdir) if sparse_subdir
    revision = git_head_revision(cache_directory)
    return [cache_directory, revision]
  end

  FileUtils.rm_rf(cache_directory) if File.exist?(cache_directory)
  FileUtils.mkdir_p(File.dirname(cache_directory))
  if seed_git_cache_from_global(clone_url, cache_directory, project_root)
    run_git_in_repo(cache_directory, "remote", "set-url", "origin", clone_url)
  else
    run_git(project_root, "clone", "--depth", "1", clone_url, cache_directory)
    mirror_git_cache_to_global(clone_url, cache_directory)
  end
  checkout_git_revision(cache_directory, clone_url, pinned_revision, true) if pinned_revision
  apply_sparse_checkout(cache_directory, sparse_subdir) if sparse_subdir
  [cache_directory, git_head_revision(cache_directory)]
end

.git_head_revision(repository) ⇒ Object



202
203
204
205
206
207
208
209
210
# File 'lib/pray/git_sources.rb', line 202

def git_head_revision(repository)
  output, status = Open3.capture2e("git", "-C", repository, "rev-parse", "HEAD")
  raise Error.resolution(command_error("git rev-parse HEAD", output)) unless status.success?

  revision = output.strip
  raise Error.resolution("git repository has no HEAD revision") if revision.empty?

  revision
end

.git_source_cache_directory(project_root, clone_url) ⇒ Object



117
118
119
# File 'lib/pray/git_sources.rb', line 117

def git_source_cache_directory(project_root, clone_url)
  File.join(project_root, ".pray", "cache", "git", cache_key(clone_url))
end

.global_cache_rootObject



145
146
147
148
149
150
151
# File 'lib/pray/git_sources.rb', line 145

def global_cache_root
  return ENV["PRAY_CACHE"] if ENV["PRAY_CACHE"]
  return File.join(ENV["PRAY_HOME"], "cache") if ENV["PRAY_HOME"]

  home = ENV["HOME"]
  home ? File.join(home, ".cache", "pray") : nil
end

.global_git_cache_directory(clone_url) ⇒ Object



153
154
155
156
# File 'lib/pray/git_sources.rb', line 153

def global_git_cache_directory(clone_url)
  root = global_cache_root
  root ? File.join(root, "git", cache_key(clone_url)) : nil
end

.global_git_cache_ready?(global_cache) ⇒ Boolean

Returns:

  • (Boolean)


158
159
160
# File 'lib/pray/git_sources.rb', line 158

def global_git_cache_ready?(global_cache)
  File.directory?(File.join(global_cache, ".git")) || File.file?(File.join(global_cache, "HEAD"))
end

.local_distribution_root?(path) ⇒ Boolean

Returns:

  • (Boolean)


75
76
77
# File 'lib/pray/git_sources.rb', line 75

def local_distribution_root?(path)
  File.directory?(File.join(path, "v1", "packages"))
end

.local_filesystem_source?(clone_url) ⇒ Boolean

Returns:

  • (Boolean)


135
136
137
# File 'lib/pray/git_sources.rb', line 135

def local_filesystem_source?(clone_url)
  clone_url.start_with?("file://") || Pathname.new(clone_url).absolute?
end

.local_git_repo_path(clone_url) ⇒ Object



139
140
141
142
143
# File 'lib/pray/git_sources.rb', line 139

def local_git_repo_path(clone_url)
  path = clone_url.delete_prefix("file://")
  git_directory = File.join(path, ".git")
  File.directory?(git_directory) ? path : nil
end

.local_git_source_root(clone_url) ⇒ Object



79
80
81
82
83
84
85
86
87
88
# File 'lib/pray/git_sources.rb', line 79

def local_git_source_root(clone_url)
  path = if clone_url.start_with?("file://")
    clone_url.delete_prefix("file://")
  else
    clone_url
  end
  return nil unless File.exist?(path)

  discover_distribution_root(path)
end

.mirror_git_cache_to_global(clone_url, project_cache) ⇒ Object



170
171
172
173
174
175
176
177
178
# File 'lib/pray/git_sources.rb', line 170

def mirror_git_cache_to_global(clone_url, project_cache)
  global_cache = global_git_cache_directory(clone_url)
  return unless global_cache
  return if global_git_cache_ready?(global_cache)

  FileUtils.mkdir_p(File.dirname(global_cache))
  FileUtils.rm_rf(global_cache) if File.exist?(global_cache)
  run_git(File.dirname(project_cache), "clone", "--bare", "--quiet", File.basename(project_cache), global_cache)
end

.pinned_revision_for_source(lockfile, source) ⇒ Object



125
126
127
128
129
130
131
132
133
# File 'lib/pray/git_sources.rb', line 125

def pinned_revision_for_source(lockfile, source)
  if lockfile
    entry = lockfile.source.find { |item| item.name == source.name && item.kind == "git" }
    return entry.revision if entry&.revision
  end
  return source.rev if source.kind == "git" && source.rev

  source.tag if source.kind == "git"
end

.prepare_git_sources(project_root, sources, lockfile, refresh: false) ⇒ Object



13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/pray/git_sources.rb', line 13

def prepare_git_sources(project_root, sources, lockfile, refresh: false)
  checkouts = {}
  sources.each do |source|
    next unless source.kind == "git"

    clone_url = source.url.delete_prefix("git+")
    if local_filesystem_source?(clone_url) && !local_git_repo_path(clone_url)
      source_root = local_git_source_root(clone_url)
      if source_root
        checkouts[source.name] = GitSourceCheckout.new(
          cache_directory: source_root,
          revision: "",
          subdir: source.subdir
        )
      end
      next
    end

    pinned_revision = refresh ? nil : pinned_revision_for_source(lockfile, source)
    cache_directory, revision = ensure_git_repository(
      project_root,
      clone_url,
      refresh: refresh,
      pinned_revision: pinned_revision,
      sparse_subdir: source.subdir
    )
    checkouts[source.name] = GitSourceCheckout.new(
      cache_directory: cache_directory,
      revision: revision,
      subdir: source.subdir
    )
  end
  checkouts
end

.refresh_git_worktree(repository, _clone_url) ⇒ Object



190
191
192
193
# File 'lib/pray/git_sources.rb', line 190

def refresh_git_worktree(repository, _clone_url)
  run_git_in_repo(repository, "fetch", "--depth", "1", "origin")
  run_git_in_repo(repository, "reset", "--hard", "origin/HEAD")
end

.refresh_global_git_cache(clone_url) ⇒ Object



195
196
197
198
199
200
# File 'lib/pray/git_sources.rb', line 195

def refresh_global_git_cache(clone_url)
  global_cache = global_git_cache_directory(clone_url)
  return unless global_cache && global_git_cache_ready?(global_cache)

  run_git_in_repo(global_cache, "fetch", "--depth", "1", "origin")
end

.resolve_distribution_root(repo_root, subdir) ⇒ Object



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/pray/git_sources.rb', line 48

def resolve_distribution_root(repo_root, subdir)
  if subdir
    path = File.join(repo_root, subdir)
    return path if local_distribution_root?(path)

    raise Error.resolution(
      "no pray distribution root at subdir #{path.inspect} in git source #{repo_root.inspect}"
    )
  end

  discover_distribution_root(repo_root) ||
    raise(Error.resolution(
            "no pray distribution root in git source #{repo_root.inspect}. " \
            "Expected v1/packages at the repository root or under prayers/. " \
            "Publish with `pray publish --root ./prayers` or point the source at a distribution repository."
          ))
end

.run_git(cwd, *arguments) ⇒ Object



212
213
214
215
216
217
# File 'lib/pray/git_sources.rb', line 212

def run_git(cwd, *arguments)
  output, status = Open3.capture2e("git", "-C", cwd, *arguments)
  return if status.success?

  raise Error.resolution(command_error("git #{arguments.join(" ")}", output))
end

.run_git_in_repo(repository, *arguments) ⇒ Object



219
220
221
# File 'lib/pray/git_sources.rb', line 219

def run_git_in_repo(repository, *arguments)
  run_git(repository, *arguments)
end

.seed_git_cache_from_global(clone_url, destination, working_directory) ⇒ Object



162
163
164
165
166
167
168
# File 'lib/pray/git_sources.rb', line 162

def seed_git_cache_from_global(clone_url, destination, working_directory)
  global_cache = global_git_cache_directory(clone_url)
  return false unless global_cache && global_git_cache_ready?(global_cache)

  run_git(working_directory, "clone", "--depth", "1", "--quiet", global_cache, destination)
  true
end