Class: Omnibus::GitFetcher

Inherits:
Fetcher
  • Object
show all
Defined in:
lib/omnibus/fetchers/git_fetcher.rb

Constant Summary

Constants included from Util

Util::SHELLOUT_OPTIONS

Instance Attribute Summary

Attributes inherited from Fetcher

#build_dir, #described_version, #name, #project_dir, #resolved_version, #source

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Fetcher

#fetcher, #initialize, #version

Methods included from Util

#copy_file, #create_directory, #create_file, #create_link, included, #remove_directory, #remove_file, #shellout, #shellout!, #windows_safe_path

Methods included from Logging

included

Methods included from Digestable

#digest, #digest_directory, included

Constructor Details

This class inherits a constructor from Omnibus::Fetcher

Class Method Details

.dereference_annotated_tag(remote_list, ref) ⇒ String

Dereference annotated tags.

The remote_list parameter is assumed to look like this:

a2ed66c01f42514bcab77fd628149eccb4ecee28        refs/tags/rel-0.11.0
f915286abdbc1907878376cce9222ac0b08b12b8        refs/tags/rel-0.11.0^{}

The SHA with ^{} is the commit pointed to by an annotated tag. If ref isn't an annotated tag, there will not be a line with trailing ^{}.



267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
# File 'lib/omnibus/fetchers/git_fetcher.rb', line 267

def self.dereference_annotated_tag(remote_list, ref)
  # We'll return the SHA corresponding to the ^{} which is the
  # commit pointed to by an annotated tag. If no such commit
  # exists (not an annotated tag) then we return the SHA of the
  # ref.  If nothing matches, return "".
  lines = remote_list.split("\n")
  matches = lines.map { |line| line.split("\t") }
  # First try for ^{} indicating the commit pointed to by an
  # annotated tag.
  tagged_commit = matches.find { |m| m[1].end_with?("#{ref}^{}") }
  if tagged_commit
    tagged_commit.first
  else
    found = matches.find { |m| m[1].end_with?("#{ref}") }
    if found
      found.first
    else
      nil
    end
  end
end

.resolve_version(ref, source) ⇒ String

Return the SHA1 corresponding to a ref as determined by the remote source.



199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
# File 'lib/omnibus/fetchers/git_fetcher.rb', line 199

def self.resolve_version(ref, source)
  if sha_hash?(ref)
    # A git server negotiates in terms of refs during the info-refs phase
    # of a fetch. During upload-pack, the client is not allowed to specify
    # any sha1s in the "wants" unless the server has publicized them during
    # info-refs. Hence, the server is allowed to drop requests to fetch
    # particular sha1s, even if it is an otherwise reachable commit object.
    # Only when the service is specifically configured with
    # uploadpack.allowReachableSHA1InWant is there any guarantee that it
    # considers "naked" wants.
    log.warn(log_key) { 'git fetch on a sha1 is not guaranteed to work' }
    log.warn(log_key) { "Specify a ref name instead of #{ref} on #{source}" }
    ref
  else
    revision_from_remote_reference(ref, source)
  end
end

.revision_from_remote_reference(ref, source) ⇒ String

Return the SHA corresponding to ref.

If ref is an annotated tag, return the SHA that was tagged not the SHA of the tag itself.



234
235
236
237
238
239
240
241
242
243
244
245
246
# File 'lib/omnibus/fetchers/git_fetcher.rb', line 234

def self.revision_from_remote_reference(ref, source)
  # execute `git ls-remote` the trailing '*' does globbing. This
  # allows us to return the SHA of the tagged commit for annotated
  # tags. We take care to only return exact matches in
  # process_remote_list.
  remote_list = shellout!("git ls-remote \"#{source[:git]}\" #{ref}*").stdout
  commit_ref = dereference_annotated_tag(remote_list, ref)

  unless commit_ref
    raise UnresolvableGitReference.new(ref)
  end
  commit_ref
end

.sha_hash?(rev) ⇒ true, false

Determine if the given revision is a SHA



222
223
224
# File 'lib/omnibus/fetchers/git_fetcher.rb', line 222

def self.sha_hash?(rev)
  rev =~ /^[0-9a-f]{4,40}$/i
end

Instance Method Details

#cleantrue, false

Clean the project directory by removing the contents from disk.



45
46
47
48
49
50
51
52
53
# File 'lib/omnibus/fetchers/git_fetcher.rb', line 45

def clean
  if cloned?
    log.info(log_key) { 'Cleaning existing clone' }
    git('clean -fdx')
    true
  else
    false
  end
end

#fetchvoid

This method returns an undefined value.

Fetch (clone) or update (fetch) the remote git repository.



60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/omnibus/fetchers/git_fetcher.rb', line 60

def fetch
  log.info(log_key) { "Fetching from `#{source_url}'" }
  create_required_directories

  if cloned?
    git_fetch unless same_revision?(resolved_version)
  else
    force_recreate_project_dir! unless dir_empty?(project_dir)
    git_clone
    git_checkout
  end
end

#fetch_required?true, false

A fetch is required if the git repository is not cloned or if the local revision does not match the desired revision.



25
26
27
# File 'lib/omnibus/fetchers/git_fetcher.rb', line 25

def fetch_required?
  !(cloned? && same_revision?(resolved_version))
end

#version_for_cacheString

The version for this item in the cache. The is the parsed revision of the item on disk.



79
80
81
# File 'lib/omnibus/fetchers/git_fetcher.rb', line 79

def version_for_cache
  "revision:#{current_revision}"
end

#version_guidString

The version identifier for this git location. This is computed using the current revision on disk.



35
36
37
# File 'lib/omnibus/fetchers/git_fetcher.rb', line 35

def version_guid
  "git:#{current_revision}"
end