class Plugin < ActiveRecord::Base acts_as_ferret validates_presence_of :root # TODO: syntax check this against URLs that script/plugin can understand validates_uniqueness_of :root validates_format_of :name, :with => /\A[\w\-_]+\Z/, :if => Proc.new { |p| !p.name.blank? }, :message => 'must only contain letters, digits, hyphens and underscores' validates_uniqueness_of :name has_many :releases has_many :test_results before_validation :guess_name_if_not_given before_validation :normalise_root_url def validate begin @root_links = repository_root true rescue RemoteResources::URLNotFoundException errors.add('root', 'URL cannot be loaded. Is the URL correct?') false end end # only scan for releases automatically on initial plugin creation after_create :scan_root_for_releases def after_initialize self.auto_updatable = false if self.auto_updatable.nil? end # Retrieve the latest release of a plugin. # This assumes that releases are ordered in reverse alphabetically, so 'Beta' > 'Alpha', # '1.1.2' > '1.1.1', and so on. However, if some stranger releaseing system is used, # we might need to be more sophisticated about it. def latest_release return self.releases.first if self.releases.size == 1 self.sorted_releases.reject { |v| v.name == Release::TRUNK_RELEASE_NAME }.last end def older_releases self.sorted_releases.reject { |v| [bleeding_edge, latest_release].include?(v) } end def bleeding_edge self.releases.select { |v| v.name == Release::TRUNK_RELEASE_NAME }.first end # sort based on: http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/82087 def sorted_releases releases.sort_by do |v| v.name.gsub(/\s+/, '').split(/(\d+)/).map do |str| Integer(str) rescue str end end end def scan_root_for_releases # @root_links was loaded in the validation unless @root_links.select { |r| r =~ /^trunk[\/]?/ }.empty? create_trunk_release unless has_release?(Release::TRUNK_RELEASE_NAME) create_tag_releases unless @root_links.select { |r| r =~ /^tags[\/]?/ }.empty? else # we couldn't automatically detect the structure of any releases in this # root, so we must assume that this is the actual plugin itself create_release(self.root, Release::TRUNK_RELEASE_NAME) unless has_release?(Release::TRUNK_RELEASE_NAME) end save end def author self.latest_release.author end def email self.latest_release.email end def homepage self.latest_release.homepage end def summary self.latest_release.summary end def description self.latest_release.description end def updated_at self.latest_release.created_at end protected def normalise_root_url root = read_attribute('root') write_attribute('root', StringUtilities.normalise_url(root)) unless root.blank? end def guess_name_if_not_given if read_attribute('name').blank? && !read_attribute('root').blank? write_attribute('name', self.root.split('/').last.gsub(/\/\Z/, '').gsub(/[^\w\-]/, '_')) end end def read_repository_url(url) RemoteResources.repository_list(url) end def repository_root read_repository_url(self.root) end def repository_tags read_repository_url(tag_url) end def tag_url "#{self.root}tags" end def create_trunk_release create_release("#{self.root}trunk", Release::TRUNK_RELEASE_NAME) end def create_tag_releases repository_tags.each do |release_name| create_release(tag_url + '/' + release_name, release_name) unless has_release?(release_name) end end # this works even if the releases haven't been saved yet def has_release?(v) self.releases.map(&:name).include?(v) end def create_release(source_url, release_name) self.releases.create(:source_url => source_url, :name => release_name) end end