class ReaPack::Index

Constants

Error
FS_ROOT
NAME_INVALID
NAME_REGEX
PKG_TYPES
Provides
VERSION

Attributes

amend[RW]
auto_bump_commit[RW]
cdetector[R]
commit[RW]
files[RW]
path[R]
strict[RW]
time[RW]
url_template[R]

Public Class Methods

expand(filepath, basedir) click to toggle source
# File lib/reapack/index.rb, line 295
def self.expand(filepath, basedir)
  expanded = File.expand_path filepath, FS_ROOT + basedir
  expanded[0...FS_ROOT.size] = ''
  expanded
end
is_package?(path)
Alias for: type_of
is_type?(input) click to toggle source
# File lib/reapack/index.rb, line 60
def is_type?(input)
  PKG_TYPES.has_key? input&.to_sym
end
new(path) click to toggle source
# File lib/reapack/index.rb, line 92
def initialize(path)
  @amend = false
  @changes = {}
  @changed_nodes = []
  @files = []
  @path = path
  @auto_bump_commit = true

  @cdetector = ConflictDetector.new

  if File.exist? path
    begin
      # noblanks: don't preserve the original white spaces
      # so we always output a neat document
      @doc = File.open(path) {|file| Nokogiri::XML file, &:noblanks }
    rescue Nokogiri::XML::SyntaxError
    end

    unless @doc&.root&.name == 'index'
      raise Error, "'#{path}' is not a ReaPack index file"
    end

    @cdetector.load_xml @doc.root
  else
    @dirty = true
    @is_new = true

    @doc = Nokogiri::XML::Document.new
    @doc.root = Nokogiri::XML::Node.new 'index', @doc
  end

  @doc.root[:version] = 1
  @doc.encoding = 'utf-8'

  @metadata = Metadata.new @doc.root
end
parse(contents) click to toggle source
# File lib/reapack/index.rb, line 82
def parse(contents)
  mh = MetaHeader.parse contents
  unless mh.has? :changelog
    wp = WordpressChangelog.new mh
    wp.parse contents
  end
  mh
end
resolve_type(input) click to toggle source
# File lib/reapack/index.rb, line 76
def resolve_type(input)
  PKG_TYPES
    .find {|name, exts| input.to_sym == name || exts.include?(input.to_s) }
    &.first
end
type_of(path) click to toggle source
# File lib/reapack/index.rb, line 64
def type_of(path)
  # don't treat files in the root directory as packages
  # because they don't have a category

  if File.dirname(path) != '.' && (ext = File.extname(path)[1..-1])
    ext.downcase!
    PKG_TYPES.find {|_, v| v.include? ext }&.first
  end
end
Also aliased as: is_package?

Public Instance Methods

about() click to toggle source
# File lib/reapack/index.rb, line 207
def about
  @metadata.about
end
about=(content) click to toggle source
# File lib/reapack/index.rb, line 211
def about=(content)
  old = @metadata.about
  @metadata.about = content

  log_change 'modified metadata' if old != @metadata.about
end
changelog() click to toggle source
# File lib/reapack/index.rb, line 277
def changelog
  list = []

  @changes.each_pair {|type, data|
    count, plural = data
    list << "#{count} #{count != 1 ? plural : type}"
  }

  list << 'empty index' if @is_new && Category.find_all(@doc.root).empty?

  list.join ', '
end
clear() click to toggle source
# File lib/reapack/index.rb, line 290
def clear
  Category.find_all(@doc.root).each {|cat| cat.remove }
  @cdetector.clear
end
last_commit() click to toggle source
# File lib/reapack/index.rb, line 255
def last_commit
  @doc.root[:commit]
end
modified?() click to toggle source
# File lib/reapack/index.rb, line 273
def modified?
  !!@dirty
end
name() click to toggle source
# File lib/reapack/index.rb, line 241
def name
  @doc.root[:name].to_s
end
name=(newName) click to toggle source
# File lib/reapack/index.rb, line 245
def name=(newName)
  if !NAME_REGEX.match(newName) || NAME_INVALID.match(newName)
    raise Error, "invalid name '#{newName}'"
  end

  oldName = name
  @doc.root['name'] = newName
  log_change 'modified metadata' if oldName != newName
end
remove(path) click to toggle source
# File lib/reapack/index.rb, line 174
def remove(path)
  cat, pkg = package_for path, false
  return unless pkg

  @cdetector[path].clear

  pkg.remove
  cat.remove if cat.empty?

  bump_commit if @auto_bump_commit
  log_change 'removed package'
end
scan(path, contents) click to toggle source
# File lib/reapack/index.rb, line 129
def scan(path, contents)
  type = self.class.type_of path
  return unless type

  mh = contents.is_a?(MetaHeader) ? contents : self.class.parse(contents)

  if mh[:noindex]
    remove path
    return
  end

  # variables to restore if an error occur
  backups = Hash[[:@doc, :@cdetector].map {|var|
    [var, instance_variable_get(var).clone]
  }]

  cat, pkg = package_for path
  pkg.type = type

  scanner = Scanner.new cat, pkg, mh, self

  begin
    scanner.run @strict
  rescue Error
    backups.each {|var, value| instance_variable_set var, value }
    raise
  end

  log_change 'new category', 'new categories' if cat.is_new?

  if pkg.modified? && !@changed_nodes.include?(pkg.node)
    log_change "#{pkg.is_new? ? 'new' : 'modified'} package"
    @changed_nodes << pkg.node
  end

  pkg.versions.each {|ver|
    if ver.modified? && !@changed_nodes.include?(ver.node)
      log_change "#{ver.is_new? ? 'new' : 'modified'} version"
      @changed_nodes << ver.node
    end
  }

  bump_commit if @auto_bump_commit
end
url_template=(tpl) click to toggle source
# File lib/reapack/index.rb, line 218
def url_template=(tpl)
  return @url_template = nil if tpl.nil?

  uri = Addressable::URI.parse tpl
  uri.normalize!

  unless (uri.request_uri || uri.path).include? '$path'
    raise Error, "missing $path placeholder in '#{tpl}'"
  end

  unless %w{http https file}.include? uri.scheme
    raise Addressable::URI::InvalidURIError
  end

  @url_template = tpl
rescue Addressable::URI::InvalidURIError
  raise Error, "invalid template '#{tpl}'"
end
version() click to toggle source
# File lib/reapack/index.rb, line 237
def version
  @doc.root[:version].to_i
end
write(path) click to toggle source
# File lib/reapack/index.rb, line 259
def write(path)
  sort @doc.root

  FileUtils.mkdir_p File.dirname(path)
  File.binwrite path, @doc.to_xml
end
write!() click to toggle source
# File lib/reapack/index.rb, line 266
def write!
  write @path

  @is_new = @dirty = false
  @changes.clear
end

Private Instance Methods

bump_commit() click to toggle source
# File lib/reapack/index.rb, line 335
def bump_commit
  sha1 = @commit || last_commit

  if sha1.nil?
    @doc.root.remove_attribute 'commit'
  else
    @doc.root['commit'] = sha1
  end
end
log_change(desc, plural = nil) click to toggle source
# File lib/reapack/index.rb, line 302
def log_change(desc, plural = nil)
  @dirty = true

  @changes[desc] ||= [0, plural || desc + 's']
  @changes[desc][0] += 1
end
package_for(path, create = true) click to toggle source
# File lib/reapack/index.rb, line 309
def package_for(path, create = true)
  cat_name = File.dirname path
  pkg_name = File.basename path

  cat = Category.fetch cat_name, @doc.root, create
  pkg = Package.fetch pkg_name, cat&.node, create

  [cat, pkg]
end
sort(node) click to toggle source
# File lib/reapack/index.rb, line 319
def sort(node)
  node.element_children.map {|n| sort n }

  sorted = node.element_children
    .stable_sort_by {|n|
      if n.name == Version.tag
        '' # don't sort version tags by name attribute value
      else
        n[:name].to_s.downcase
      end
    }
    .stable_sort_by {|n| n.name.downcase }

  sorted.each {|n| node << n }
end