class RightPublish::Repo

Constants

LOCK_FILE_NAME
LOCK_PERIOD
LOCK_RETRY_INTERVAL

Public Class Methods

new(option_key) click to toggle source
# File lib/right_publish/repo.rb, line 41
def initialize(option_key)
  @repository_type ||= option_key
end

Public Instance Methods

add(file_or_dir, targe) click to toggle source

Add a new package to local storage and reindex if necessary

# File lib/right_publish/repo.rb, line 107
def add(file_or_dir, targe)
  raise NotImplementedError, "Subclass responsibility"
end
annotate(options={}) click to toggle source

Create an index.html file to enable browsing of this repo’s subdir. @option options [String] :subdir a subdirectory (common prefix); only files matching this prefix will be included @option options [Array] :filter a whitelist of String glob patterns to filter files, i.e. [“*.rpm”, “*.deb”]

# File lib/right_publish/repo.rb, line 72
def annotate(options={})
  Profile.log("Creating HTML directory listing for #{repo_human_name} files...")

  options[:subdir] ||= repo_config[:subdir]

  files = []
  RightPublish::Storage.ls(local_storage, :subdir => options[:subdir]) do |file|
    files << file
  end

  # Build merged options hash for annotation, based on profile config plus some options
  # passed into our class.
  html_options     = Profile.config[:annotation] ? Profile.config[:annotation].dup : {}
  html_options[:filter] = options[:filter] if options.key?(:filter)

  strip            = options[:subdir].split('/').size
  html             = RightPublish::Annotation.generate_html(files, strip, html_options)

  output    = File.join(repo_config[:subdir], 'index.html')
  local_dir = local_storage.get_directories
  local_dir.files.create(:key => output, :body => html)
end
publish(file_or_dir, target) click to toggle source

Perform one-shot publish of one or more packages. “One-shot” means: pull, add, annotate and push.

# File lib/right_publish/repo.rb, line 97
def publish(file_or_dir, target)
  lock do
    pull
    add(file_or_dir, target)
    annotate
    push
  end
end
pull() click to toggle source

Sync files from remote to local storage

# File lib/right_publish/repo.rb, line 46
def pull()
  Profile.log("Fetching #{repo_human_name} files from remote...")

  begin
    sync_dirs(remote_storage, local_storage, repo_config[:subdir])
  rescue Exception => e
    RightPublish::Profile.log("Could not synchronize storage:\n\t#{e}", :error)
    raise RuntimeError, "pull from remote failed."
  end
end
push() click to toggle source

Sync files from local to remote storage

# File lib/right_publish/repo.rb, line 58
def push()
  Profile.log("Committing local #{repo_human_name} files to remote...")

  begin
    sync_dirs(local_storage, remote_storage, repo_config[:subdir])
  rescue Exception => e
    RightPublish::Profile.log("Could not sychronize storage:\n\t#{e}", :error)
    raise RuntimeError, "push to remote failed."
  end
end

Private Instance Methods

build_glob(ext) click to toggle source
# File lib/right_publish/repo.rb, line 147
def build_glob(ext)
  # Transform array into glob compliant pattern
  '{'.concat Array(ext).join(',').concat '}'
end
do_in_subdir(subdir) { || ... } click to toggle source
# File lib/right_publish/repo.rb, line 152
def do_in_subdir(subdir)
  full_path = File.expand_path(File.join(Profile.config[:local_storage][:cache_dir], subdir))
  FileUtils.mkdir_p full_path

  Dir.chdir(full_path) { yield }
end
get_pkg_list(file_or_dir, ext=nil) { |pkg_path| ... } click to toggle source
# File lib/right_publish/repo.rb, line 159
def get_pkg_list(file_or_dir, ext=nil)
  pkg_list    = []
  file_or_dir = Array(file_or_dir)
  file_or_dir.each do |path|
    path = path.gsub("\\", "/")
    pkg_list << if File.directory?(path)
                  glob_filter = (ext && "*.#{build_glob(ext)}") || "*"
                  Dir.glob(File.join(path, glob_filter))
                else
                  path.split(',')
                end
  end
  pkg_list.flatten!

  fail("No packages found") if pkg_list.empty?
  pkg_list.each do |pkg_path|
    fail("\"#{pkg_path}\" does not appear to be a valid package for the repository.") \
      unless File.file?(pkg_path) && Array(ext).any? { |e| pkg_path.end_with?(e) }
    yield pkg_path if block_given?
  end if ext

  pkg_list
end
get_storage(provider) click to toggle source
# File lib/right_publish/repo.rb, line 208
def get_storage(provider)
  type = RightPublish::StorageManager.storage_types[provider]
  RightPublish::StorageManager.get_storage(type)
end
install_file(file, dest) click to toggle source
# File lib/right_publish/repo.rb, line 213
def install_file(file, dest)
  Profile.log("#{file} => #{dest}")
  local_dir = local_storage.get_directories
  File.open(file, "rb") { |chunk| local_dir.files.create(:key => File.join(dest, File.basename(file)), :body => chunk) }
end
local_storage() click to toggle source

proxy method

# File lib/right_publish/repo.rb, line 204
def local_storage
  get_storage(Profile.config[:local_storage][:provider])
end
lock() { || ... } click to toggle source
# File lib/right_publish/repo.rb, line 113
def lock(&block)
  while( (_lock_time = lock_time) != nil && Time.now.utc <= _lock_time ) do
    Profile.log "Lock is set to expire at #{_lock_time}, waiting for #{LOCK_RETRY_INTERVAL} second(s) ..."
    sleep LOCK_RETRY_INTERVAL
  end
  file = update_lock_time(LOCK_PERIOD)
  Profile.log "#{repo_human_name} has been locked for #{LOCK_PERIOD/60} minute(s)."
  yield
  file.destroy
  Profile.log "#{repo_human_name} has been unlocked."
end
lock_file() click to toggle source
# File lib/right_publish/repo.rb, line 137
def lock_file
  remote_storage.get_directories.files.get(lock_file_path)
rescue Excon::Errors::NotFound
  nil
end
lock_file_path() click to toggle source
# File lib/right_publish/repo.rb, line 143
def lock_file_path
  File.join(repo_config[:subdir], LOCK_FILE_NAME)
end
lock_time() click to toggle source
# File lib/right_publish/repo.rb, line 125
def lock_time
  if lock_file
    return Time.parse(lock_file.body)
  else
    nil
  end
end
prune_all(glob_pattern) click to toggle source
# File lib/right_publish/repo.rb, line 219
def prune_all(glob_pattern)
  Profile.log("Pruning: #{glob_pattern}")
  Dir.glob(glob_pattern) { |f| File.unlink(f) }
end
remote_storage() click to toggle source

proxy method

# File lib/right_publish/repo.rb, line 199
def remote_storage
  get_storage(Profile.config[:remote_storage][:provider])
end
repo_config() click to toggle source
# File lib/right_publish/repo.rb, line 224
def repo_config()
  Profile.config[@repository_type]
end
repo_human_name() click to toggle source
# File lib/right_publish/repo.rb, line 228
def repo_human_name
  @repository_type.to_s.sub(/_/, ' ')
end
shellout_with_password(cmd) click to toggle source

For automation, we want to send the password, however gpg uses getpass c function, which interacts directly with /dev/pty instead of stdin/stdout to hide the password as its typed in. So, we need to allocate a pty. We do this by shelling out to expect script (tcl based). Ruby 1.8 implementation of “expect” is broken and has some race conditions with waiting for a child processes to exist, so don’t use that.

# File lib/right_publish/repo.rb, line 189
def shellout_with_password(cmd)
  password = repo_config[:gpg_password]
  raise Exception, ":gpg_password must be supplied when signing packages" unless password
  ENV['GPG_PASSWORD'] = password
  bin_dir             = File.expand_path("../../../bin", __FILE__)
  autosign            = File.join(bin_dir, "autosign.expect")
  system("#{autosign} #{cmd}")
end
sync_dirs(src, dest, subdir='') click to toggle source
# File lib/right_publish/repo.rb, line 232
def sync_dirs(src, dest, subdir='')
  RightPublish::Storage.sync_dirs(src, dest, :subdir => subdir, :sweep => true)
end
update_lock_time(timeout) click to toggle source
# File lib/right_publish/repo.rb, line 133
def update_lock_time(timeout)
  remote_storage.get_directories.files.create(:key => lock_file_path, :body => (Time.now.utc + timeout).to_s, :acl=>'public-read', :content_type => 'text/plain')
end