#! /usr/bin/ruby
# Usage: rip-package-git URL VERSION

require 'rip/script'

source, path, version = Rip::Package.parse_args(ARGV)

# Only handle root packages
exit 3 if path != '/'

unless source =~ %r{^file://|^git://|\.git$} ||
    (source && File.directory?(source) && File.exists?("#{source}/HEAD"))
  exit 3 # Can't handle source
end


def lookup_git_rev(path, rev)
  ref = git "--git-dir=#{path} rev-list -n1 #{rev} 2> /dev/null"
  $?.success? ? ref : nil
end

def tag?(path, name)
  if tags = git("--git-dir=#{path} show-ref --tags")
    tags.grep(/^#{name}|tags\/#{name}/).any?
  end
end

def deref_version(path, version, floating = true)
  ref = lookup_git_rev(path, version)

  # If floating versions are allowed or SHA matches
  # Allow partial SHAs to match
  if floating || ref =~ /^#{version}/ || tag?(path, version)
    ref
  end
end

def describe_ref(path, ref)
  if git("--git-dir=#{path} describe --tags --exact-match #{ref} 2> /dev/null") =~ /^(.+)$/
    $1
  else
    ref
  end
end


if source =~ /([^\/]+?)-.{32}/
  name = $1
else
  name = source.split(%r{:|/}).last.chomp('.git')
end

version ||= "master"

ref = nil
cache_path = "#{Rip.cache}/#{name}-#{Rip.md5(source)}"


synchronize(cache_path) do
  # Cache exists and we have a tag or SHA - grab the full thing
  if File.directory?(cache_path)
    ref = deref_version(cache_path, version, false)
  end

  # Update cache and deference
  if !ref
    if File.directory?(cache_path)
      info "updating #{source}"
      git "--git-dir=#{cache_path} fetch -q 2> /dev/null"
    else
      info "fetching #{source}"
      git("clone --bare --mirror #{source} #{cache_path} 2> /dev/null") ||
        abort("#{source} not found")
    end

    ref = deref_version(cache_path, version)
  end

  if !ref
    abort "#{source} #{version} could not be found"
  end
end


package_path = "#{Rip.packages}/#{name}-#{Rip.md5("#{source}#{ref}")}"

synchronize(package_path) do
  if File.directory?(package_path)
    puts package_path
    exit 0
  end

  $-e = true

  at_exit do
    if !exited_successfully?
      debug "cleaning up #{package_path}"
      rm_rf package_path
    end
  end

  git("clone --no-checkout #{cache_path} #{package_path} 2> /dev/null")
  cd package_path
  git "checkout --quiet #{ref}"
  git "remote rm origin"
  Dir["#{package_path}/.git/refs/heads/*"].each do |branch|
    git "branch -D #{basename(branch)}"
  end

  $-e = false
  write("#{package_path}/metadata.rip") do
    "#{source} #{describe_ref(cache_path, ref)}"
  end

  puts package_path
end
