class Omnibus::GitCache

Constants

REQUIRED_GIT_FILES
SERIAL_NUMBER

The serial number represents compatibility of a cache entry with the current version of the omnibus code base. Any time a change is made to omnibus that makes the code incompatible with any cache entries created before the code change, the serial number should be incremented.

For example, if a code change generates content in the ‘install_dir` before cache snapshots are taken, any snapshots created before upgrade will not have the generated content, so these snapshots would be incompatible with the current omnibus codebase. Incrementing the serial number ensures these old shapshots will not be used in subsequent builds.

Attributes

software[R]

@return [Software]

Public Class Methods

new(software) click to toggle source

@param [Software] software

the software this git cache is for
# File lib/omnibus/git_cache.rb, line 54
def initialize(software)
  @software = software
end

Public Instance Methods

cache_path() click to toggle source

The path to the full install_dir cache for the project.

@return [String]

# File lib/omnibus/git_cache.rb, line 63
def cache_path
  @cache_path ||= File.join(Config.git_cache_dir, install_dir)
end
create_cache_path() click to toggle source

Creates the full path if it does not exist already.

@return [true, false]

true if the path was created, false otherwise
# File lib/omnibus/git_cache.rb, line 73
def create_cache_path
  if File.directory?(cache_path)
    false
  else
    create_directory(File.dirname(cache_path))
    git_cmd("init -q")
    # On windows, git is very picky about single vs double quotes
    git_cmd("config --local user.name \"Omnibus Git Cache\"")
    git_cmd("config --local user.email \"omnibus@localhost\"")
    true
  end
end
incremental() click to toggle source

Create an incremental install path cache for the software step

# File lib/omnibus/git_cache.rb, line 124
def incremental
  log.internal(log_key) { "Performing incremental cache" }

  create_cache_path
  remove_git_dirs

  git_cmd("add -A -f")

  begin
    git_cmd(%Q{commit -q -m "Backup of #{tag}"})
  rescue CommandFailed => e
    raise unless e.message.include?("nothing to commit")
  end

  git_cmd(%Q{tag -f "#{tag}"})
end
remove_git_dirs() click to toggle source

Git caching will attempt to version embedded git directories, partially versioning them. This causes failures on subsequent runs. This method will find git directories and remove them to prevent those errors.

@return [true]

# File lib/omnibus/git_cache.rb, line 172
def remove_git_dirs
  log.internal(log_key) { "Removing git directories" }

  Dir.glob("#{install_dir}/**/{,.*}/config").reject do |path|
    REQUIRED_GIT_FILES.any? do |required_file|
      !File.exist?(File.join(File.dirname(path), required_file))
    end
  end.each do |path|
    log.internal(log_key) { "Removing git dir `#{path}'" }
    FileUtils.rm_rf(File.dirname(path))
  end

  true
end
restore() click to toggle source
# File lib/omnibus/git_cache.rb, line 141
def restore
  log.internal(log_key) { "Performing cache restoration" }

  create_cache_path

  if has_tag(tag)
    log.internal(log_key) { "Detected tag `#{tag}' can be restored, marking it for restoration" }
    git_cmd(%Q{tag -f restore_here "#{tag}"})
    true
  elsif has_tag("restore_here")
    log.internal(log_key) { "Could not find tag `#{tag}', restoring previous tag" }
    restore_from_cache
    false
  else
    log.internal(log_key) { "Could not find marker tag `restore_here', nothing to restore" }
    false
  end
end
restore_from_cache() click to toggle source
# File lib/omnibus/git_cache.rb, line 160
def restore_from_cache
  git_cmd("checkout -f restore_here")
ensure
  git_cmd("tag -d restore_here")
end
tag() click to toggle source

Computes the tag for this cache entry.

@return [String]

# File lib/omnibus/git_cache.rb, line 91
def tag
  return @tag if @tag

  log.internal(log_key) { "Calculating tag" }

  # Accumulate an array of all the software projects that come before
  # the name and version we are tagging. So if you have
  #
  # build_order = [ 1, 2, 3, 4, 5 ]
  #
  # And we are tagging 3, you would get dep_list = [ 1, 2 ]
  dep_list = software.project.library.build_order.take_while do |dep|
    if dep.name == software.name && dep.version == software.version
      false
    else
      true
    end
  end

  log.internal(log_key) { "dep_list: #{dep_list.map(&:name).inspect}" }

  # This is the list of all the unqiue shasums of all the software build
  # dependencies, including the on currently being acted upon.
  shasums = [dep_list.map(&:shasum), software.shasum].flatten
  suffix  = Digest::SHA256.hexdigest(shasums.join("|"))
  @tag    = "#{software.name}-#{suffix}-#{SERIAL_NUMBER}"

  log.internal(log_key) { "tag: #{@tag}" }

  @tag
end

Private Instance Methods

git_cmd(command) click to toggle source

Shell out and invoke a git command in the context of the git cache.

We explicitly disable autocrlf because we want bit-for-bit storage and recovery of build output. Hashes calculated on output files will be invalid if we muck around with files after they have been produced.

@return [Mixlib::Shellout] the underlying command object.

# File lib/omnibus/git_cache.rb, line 198
def git_cmd(command)
  shellout!([
    "git",
    "-c core.autocrlf=false",
    "-c core.ignorecase=false",
    "--git-dir=\"#{cache_path}\"",
    "--work-tree=\"#{install_dir}\"",
    command,
  ].join(" "))
end
has_tag(tag) click to toggle source
# File lib/omnibus/git_cache.rb, line 227
def has_tag(tag)
  cmd = git_cmd(%Q{tag -l "#{tag}"})
  cmd.stdout.lines.any? { |line| tag == line.chomp }
end
install_dir() click to toggle source

The installation directory for this software’s project. Drive letters are stripped for Windows.

@return [String]

# File lib/omnibus/git_cache.rb, line 216
def install_dir
  @install_dir ||= software.project.install_dir.sub(/^([A-Za-z]:)/, "")
end
log_key() click to toggle source

Override the log_key for this class to include the software name

@return [String]

# File lib/omnibus/git_cache.rb, line 223
def log_key
  @log_key ||= "#{super}: #{software.name}"
end