Class: Inspec::Fetcher::Git

Inherits:
Object
  • Object
show all
Defined in:
lib/inspec/fetcher/git.rb

Overview

The git fetcher uses the git binary to fetch remote git sources. Git-based sources should be specified with the ‘git:` key in the source hash. Additionally, we accept `:branch`, `:ref`, and `:tag` keys to allow users to pin to a particular revision.

Parts of this class are derived from:

https://github.com/chef/omnibus/blob/master/lib/omnibus/fetchers/git_fetcher.rb

which is Copyright 2012-2014 Chef Software, Inc. and offered under the same Apache 2 software license as inspec.

Many thanks to the omnibus authors!

Note that we haven’t replicated all of omnibus’ features here. If you got to this file during debugging, you may want to look at the omnibus source for hints.

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(remote_url, opts = {}) ⇒ Git

Returns a new instance of Git.



38
39
40
41
42
43
44
45
46
# File 'lib/inspec/fetcher/git.rb', line 38

def initialize(remote_url, opts = {})
  @branch = opts[:branch]
  @tag = opts[:tag]
  @ref = opts[:ref]
  @remote_url = expand_local_path(remote_url)
  @repo_directory = nil
  @resolved_ref = nil
  @relative_path = opts[:relative_path] if opts[:relative_path] && !opts[:relative_path].empty?
end

Class Method Details

.resolve(target, opts = {}) ⇒ Object



30
31
32
33
34
35
36
# File 'lib/inspec/fetcher/git.rb', line 30

def self.resolve(target, opts = {})
  if target.is_a?(String)
    new(target, opts) if target.start_with?("git@") || target.end_with?(".git")
  elsif target.respond_to?(:has_key?) && target.key?(:git)
    new(target[:git], opts.merge(target))
  end
end

Instance Method Details

#archive_pathObject



112
113
114
# File 'lib/inspec/fetcher/git.rb', line 112

def archive_path
  @repo_directory
end

#cache_keyObject



99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/inspec/fetcher/git.rb', line 99

def cache_key
  cache_key = if @relative_path && !resolved_ref.nil?
                OpenSSL::Digest.hexdigest("SHA256", resolved_ref + @relative_path)
              elsif @relative_path && resolved_ref.nil?
                OpenSSL::Digest.hexdigest("SHA256", @remote_url + @relative_path)
              elsif resolved_ref.nil?
                OpenSSL::Digest.hexdigest("SHA256", @remote_url)
              else
                resolved_ref
              end
  cache_key
end

#expand_local_path(url_or_file_path) ⇒ Object



48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/inspec/fetcher/git.rb', line 48

def expand_local_path(url_or_file_path)
  # This paths to local on-disk repos, not relative paths within repos.
  # This is especially needed with testing.

  # We could try to do something clever with URI
  # processing, but then again, if you passed a relative path
  # to an on-disk repo, you probably expect it to exist.
  return url_or_file_path unless File.exist?(url_or_file_path)

  # It's important to expand this path, because it may be specified
  # locally in the metadata files, and when we clone, we will be
  # in a temp dir.
  File.expand_path(url_or_file_path)
end

#fetch(destination_path) ⇒ Object



63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/inspec/fetcher/git.rb', line 63

def fetch(destination_path)
  @repo_directory = destination_path # Might be the cache, or vendoring, or something else
  FileUtils.mkdir_p(destination_path) unless Dir.exist?(destination_path)
  if cloned?
    checkout
  else
    Dir.mktmpdir do |working_dir|
      checkout(working_dir)
      if @relative_path
        perform_relative_path_fetch(destination_path, working_dir)
      else
        Inspec::Log.debug("Checkout of #{resolved_ref.nil? ? @remote_url : resolved_ref} successful. " \
                          "Moving checkout to #{destination_path}")
        FileUtils.cp_r(working_dir + "/.", destination_path)
      end
    end
  end
  @repo_directory
end

#perform_relative_path_fetch(destination_path, working_dir) ⇒ Object



83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/inspec/fetcher/git.rb', line 83

def perform_relative_path_fetch(destination_path, working_dir)
  Inspec::Log.debug("Checkout of #{resolved_ref.nil? ? @remote_url : resolved_ref} successful. " \
                    "Moving #{@relative_path} to #{destination_path}")
  unless File.exist?("#{working_dir}/#{@relative_path}")
    # Cleanup the destination path - otherwise we'll have an empty dir
    # in the cache, which is enough to confuse the cache reader
    # This is a courtesy, assuming we're writing to the cache; if we're
    # vendoring to something more complex, don't bother.
    FileUtils.rm_r(destination_path) if Dir.exist?(destination_path)

    raise Inspec::FetcherFailure, "Cannot find relative path '#{@relative_path}' " \
                                  "within profile in git repo specified by '#{@remote_url}'"
  end
  FileUtils.cp_r("#{working_dir}/#{@relative_path}", destination_path)
end

#requires_locking?Boolean

Git fetcher is sensitive to cache contention so it needs cache locking mechanism.

Returns:

  • (Boolean)


131
132
133
# File 'lib/inspec/fetcher/git.rb', line 131

def requires_locking?
  true
end

#resolved_sourceObject



116
117
118
119
120
121
122
123
124
# File 'lib/inspec/fetcher/git.rb', line 116

def resolved_source
  if resolved_ref.nil?
    source = { git: @remote_url }
  else
    source = { git: @remote_url, ref: resolved_ref }
  end
  source[:relative_path] = @relative_path if @relative_path
  source
end

#update_from_opts(opts) ⇒ Object



126
127
128
# File 'lib/inspec/fetcher/git.rb', line 126

def update_from_opts(opts)
  %i{branch tag ref}.map { |opt_name| update_ivar_from_opt(opt_name, opts) }.any?
end