From: Jan Provaznik <[email protected]>

- added models and migrations for image_descriptor and image_descriptor_target
- added util/repository_manager.rb used for downloading/parsing  repository xml 
files
- added util/image_descriptor_xml.rb used for creating/parsing image xml file
---
 src/app/models/image_descriptor.rb                 |   27 +++
 src/app/models/image_descriptor_target.rb          |   18 ++
 src/app/util/image_descriptor_xml.rb               |  177 ++++++++++++++++++++
 src/app/util/repository_manager.rb                 |  103 ++++++++++++
 .../20100527095400_create_image_descriptors.rb     |   14 ++
 ...100527095428_create_image_descriptor_targets.rb |   15 ++
 6 files changed, 354 insertions(+), 0 deletions(-)
 create mode 100644 src/app/models/image_descriptor.rb
 create mode 100644 src/app/models/image_descriptor_target.rb
 create mode 100644 src/app/util/image_descriptor_xml.rb
 create mode 100644 src/app/util/repository_manager.rb
 create mode 100644 src/db/migrate/20100527095400_create_image_descriptors.rb
 create mode 100644 
src/db/migrate/20100527095428_create_image_descriptor_targets.rb

diff --git a/src/app/models/image_descriptor.rb 
b/src/app/models/image_descriptor.rb
new file mode 100644
index 0000000..29a3c81
--- /dev/null
+++ b/src/app/models/image_descriptor.rb
@@ -0,0 +1,27 @@
+require 'util/repository_manager'
+require 'util/image_descriptor_xml'
+
+class ImageDescriptor < ActiveRecord::Base
+  has_many :image_descriptor_targets,  :dependent => :destroy
+
+  #TODO: validations
+
+  def update_xml_attributes!(opts = {})
+    doc = ImageDescriptorXML.new(self[:xml])
+    doc.name = opts[:name] if opts[:name]
+    doc.platform = opts[:platform] if opts[:platform]
+    doc.description = opts[:description] if opts[:description]
+    doc.services = opts[:services] if opts[:services]
+    doc.packages = opts[:packages] if opts[:packages]
+    self[:xml] = doc.to_xml
+    @xml = doc
+    save!
+  end
+
+  def xml
+    unless @xml
+      @xml = ImageDescriptorXML.new(self[:xml].to_s)
+    end
+    return @xml
+  end
+end
diff --git a/src/app/models/image_descriptor_target.rb 
b/src/app/models/image_descriptor_target.rb
new file mode 100644
index 0000000..7c67c73
--- /dev/null
+++ b/src/app/models/image_descriptor_target.rb
@@ -0,0 +1,18 @@
+require 'yaml'
+
+class ImageDescriptorTarget < ActiveRecord::Base
+  belongs_to :image_descriptor
+
+  #TODO: validations
+  validates_presence_of :name
+
+  def self.new_if_not_exists(data)
+    unless find(:first, :conditions => {:name => data[:name], 
:image_descriptor_id => data[:image_descriptor_id]})
+      ImageDescriptorTarget.new(data).save!
+    end
+  end
+
+  def self.available_targets
+    return YAML.load_file("#{RAILS_ROOT}/config/image_descriptor_targets.yml")
+  end
+end
diff --git a/src/app/util/image_descriptor_xml.rb 
b/src/app/util/image_descriptor_xml.rb
new file mode 100644
index 0000000..c5ed310
--- /dev/null
+++ b/src/app/util/image_descriptor_xml.rb
@@ -0,0 +1,177 @@
+#
+# Copyright (C) 2009 Red Hat, Inc.
+# Written by Jan Provaznik <[email protected]>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.  A copy of the GNU General Public License is
+# also available at http://www.gnu.org/copyleft/gpl.html.
+
+require 'yaml'
+
+class ImageDescriptorXML
+  def initialize(xmlstr = "")
+    @doc = Nokogiri::XML(xmlstr)
+    # create at least root node if it doesn't exist
+    unless @doc.root
+      @doc.root = Nokogiri::XML::Node.new('image', @doc)
+    end
+    @root = @doc.root.at_xpath('/image')
+  end
+
+  def name=(str)
+    node = get_or_create_node('name')
+    node.content = str
+  end
+
+  def name
+    return get_node_text('name')
+  end
+
+  def platform=(str)
+    # FIXME: we remove all repos beacouse we don't know which one is for
+    # platform
+    recreate_repo_nodes(str, services)
+
+    node = get_or_create_node('os')
+    node.content = str
+  end
+
+  def platform
+    return get_node_text('os')
+  end
+
+  def platforms
+    unless @platforms
+      @platforms = 
YAML.load_file("#{RAILS_ROOT}/config/image_descriptor_platform_repositories.yml")
+    end
+    return @platforms
+  end
+
+  def description=(str)
+    node = get_or_create_node('description')
+    node.content = str
+  end
+
+  def description
+    return get_node_text('description')
+  end
+
+  def services=(services)
+    service_node = get_or_create_node('services')
+    service_node.xpath('.//service').remove
+    repositories = repository_manager.repositories
+    services.each do |s|
+      snode = Nokogiri::XML::Node.new('service', @doc)
+      service_node << snode
+      snode.content = s[0]
+      if repo = repositories[s[0]]
+        add_service_packages(s[0], repo)
+      end
+    end
+    recreate_repo_nodes(platform, services)
+    @services = nil
+  end
+
+  def services
+    unless @services
+      @services = []
+      @root.xpath('/image/services/service').each do |s|
+        services << s.text
+      end
+    end
+    return @services
+  end
+
+  def to_xml
+    return @doc.to_xml
+  end
+
+  def packages
+    packages = {}
+    @root.xpath('/image/packages/package').each do |s|
+      group = s.at_xpath('.//group').text
+      packages[group] ||= []
+      packages[group] << {:name => s.at_xpath('.//name').text}
+    end
+    packages
+  end
+
+  def packages=(packages)
+    pkgs_node = get_or_create_node('packages')
+    pkgs_node.xpath('.//package').remove
+    packages.each do |pkg|
+      group, name = pkg.split(/#/, 2)
+      add_package(pkgs_node, name, group)
+    end
+  end
+
+  private
+
+  def recreate_repo_nodes(platform, services)
+    unless repconf = platforms[platform]
+      raise "unknown platform #{platform}"
+    end
+
+    repo_node = get_or_create_node('repos')
+    repo_node.xpath('.//repo').remove
+    rnode = get_or_create_node('repo', repo_node)
+    rnode.content = repconf['baseurl']
+
+    repositories = repository_manager.repositories
+    services.each do |s|
+      if rep = repositories[s[0]]
+        rnode = get_or_create_node('repo', repo_node)
+        rnode.content = rep['baseurl']
+      end
+    end
+  end
+
+  def get_or_create_node(name, parent = @root)
+    unless node = @root.at_xpath(name)
+      node = Nokogiri::XML::Node.new(name, @doc)
+      parent << node
+    end
+    return node
+  end
+
+  def get_node_text(path)
+    node = @root.at_xpath('/image/' + path)
+    return node ? node.text : nil
+  end
+
+  def add_service_packages(repid, repconf)
+    repo = repository_manager.get_repository(repid)
+    packages = repo.get_packages
+    pkgs_node = get_or_create_node('packages')
+    pkgs_node.xpath('.//package').remove
+    packages.each {|p| add_package(pkgs_node, p[:name], p[:group])}
+  end
+
+  def add_package(parent, name, group)
+    pnode = get_or_create_node('package', parent)
+    n = Nokogiri::XML::Node.new('name', @doc)
+    n.content = name
+    pnode << n
+    n = Nokogiri::XML::Node.new('group', @doc)
+    n.content = group
+    pnode << n
+  end
+
+  def repository_manager
+    unless @repository_manager
+      @repository_manager = RepositoryManager.new
+    end
+    return @repository_manager
+  end
+end
diff --git a/src/app/util/repository_manager.rb 
b/src/app/util/repository_manager.rb
new file mode 100644
index 0000000..1835390
--- /dev/null
+++ b/src/app/util/repository_manager.rb
@@ -0,0 +1,103 @@
+#
+# Copyright (C) 2009 Red Hat, Inc.
+# Written by Jan Provaznik <[email protected]>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.  A copy of the GNU General Public License is
+# also available at http://www.gnu.org/copyleft/gpl.html.
+
+require 'open-uri'
+require 'yaml'
+
+class RepositoryManager
+  class CompsRepository
+    def initialize(baseurl)
+      @baseurl = baseurl
+      @repomd_uri = File.join(@baseurl, 'repodata', 'repomd.xml')
+      begin
+        repoio = open(@repomd_uri)
+      rescue
+        raise "failed to download repomd file #...@repomd_uri}"
+      end
+      @repomd = Nokogiri::XML(repoio)
+    end
+
+    def get_packages
+      packages = []
+      # FIXME: currently are selected only mandatory and default packages,
+      # optional packages are ingored
+      get_packages_nodes.each do |node|
+        name = node.at_xpath('./xmlns:name/child::text()')
+        group = node.at_xpath('./xmlns:format/rpm:group/child::text()')
+        description = node.at_xpath('./xmlns:description/child::text()')
+        next unless name and group
+        packages << {
+          :name => name.text,
+          :group => group.text,
+          :description => description ? description.text : '',
+        }
+      end
+      return packages
+    end
+
+    def get_packages_by_group
+      groups = {}
+      get_packages.each do |p|
+        group = (groups[p[:group]] ||= [])
+        group << p
+      end
+      return groups
+    end
+
+    private
+
+    def get_packages_nodes
+      unless @packages_nodes
+        data = get_xml(get_primary_url)
+        xml = Nokogiri::XML(data)
+        @packages_nodes = xml.xpath('/xmlns:metadata/xmlns:package')
+      end
+      return @packages_nodes
+    end
+
+    def get_xml(url)
+      xml_data = open(url)
+      if url =~ /\.gz$/
+        return Zlib::GzipReader.new(xml_data).read
+      else
+        return xml_data
+      end
+    end
+
+    def get_primary_url
+      location = 
@repomd.xpath('/xmlns:repomd/xmlns:da...@type="primary"]/xmlns:location').first
+      raise "location for primary data not found" unless location
+      return File.join(@baseurl, location['href'])
+    end
+  end
+
+  def initialize
+    @config = 
YAML.load_file("#{RAILS_ROOT}/config/image_descriptor_package_repositories.yml")
+  end
+
+  def get_repository(repository_id)
+    repo = @config[repository_id]
+    raise "Repository '#{repository_id}' doesn't exist" unless repo
+    return CompsRepository.new(repo['baseurl'])
+  end
+
+  def repositories
+    return @config
+  end
+end
diff --git a/src/db/migrate/20100527095400_create_image_descriptors.rb 
b/src/db/migrate/20100527095400_create_image_descriptors.rb
new file mode 100644
index 0000000..9f91629
--- /dev/null
+++ b/src/db/migrate/20100527095400_create_image_descriptors.rb
@@ -0,0 +1,14 @@
+class CreateImageDescriptors < ActiveRecord::Migration
+  def self.up
+    create_table :image_descriptors do |t|
+      t.binary :xml, :null => false
+      t.string :uri
+      t.boolean :complete
+      t.timestamps
+    end
+  end
+
+  def self.down
+    drop_table :image_descriptors
+  end
+end
diff --git a/src/db/migrate/20100527095428_create_image_descriptor_targets.rb 
b/src/db/migrate/20100527095428_create_image_descriptor_targets.rb
new file mode 100644
index 0000000..2cb49da
--- /dev/null
+++ b/src/db/migrate/20100527095428_create_image_descriptor_targets.rb
@@ -0,0 +1,15 @@
+class CreateImageDescriptorTargets < ActiveRecord::Migration
+  def self.up
+    create_table :image_descriptor_targets do |t|
+      t.string :name, :null => false
+      t.integer :build_id
+      t.string :status
+      t.integer :image_descriptor_id
+      t.timestamps
+    end
+  end
+
+  def self.down
+    drop_table :image_descriptor_targets
+  end
+end
-- 
1.7.0.1

_______________________________________________
deltacloud-devel mailing list
[email protected]
https://fedorahosted.org/mailman/listinfo/deltacloud-devel

Reply via email to