lib/ronin/database/database.rb in ronin-0.3.0 vs lib/ronin/database/database.rb in ronin-1.0.0.pre1
- old
+ new
@@ -1,9 +1,9 @@
#
# Ronin - A Ruby platform for exploit development and security research.
#
-# Copyright (c) 2006-2009 Hal Brodigan (postmodern.mod3 at gmail.com)
+# Copyright (c) 2006-2010 Hal Brodigan (postmodern.mod3 at gmail.com)
#
# 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; either version 2 of the License, or
# (at your option) any later version.
@@ -17,77 +17,116 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
require 'ronin/database/exceptions/invalid_config'
+require 'ronin/database/exceptions/unknown_repository'
+require 'ronin/database/migrations/migrations'
require 'ronin/model'
-require 'ronin/arch'
-require 'ronin/os'
-require 'ronin/author'
-require 'ronin/license'
-require 'ronin/product'
require 'ronin/config'
+require 'ronin/installation'
+require 'addressable/uri'
require 'yaml'
require 'dm-core'
module Ronin
+ #
+ # Manages the {Database} configuration and the defined repositories.
+ # Also provides a simple wrapper around DataMapper, for initializing,
+ # auto-upgrading and querying {Database} repositories.
+ #
module Database
# Database configuration file
CONFIG_FILE = File.join(Config::PATH,'database.yml')
# Database log file
DEFAULT_LOG_PATH = File.join(Config::PATH,'database.log')
# Database log level
DEFAULT_LOG_LEVEL = :info
- # Default configuration of the database
- DEFAULT_CONFIG = "sqlite3://" + File.join(Config::PATH,'database.sqlite3')
+ # Default database repository
+ DEFAULT_REPOSITORY = Addressable::URI.new(
+ :scheme => 'sqlite3',
+ :path => File.join(Config::PATH,'database.sqlite3')
+ )
+ @repositories = {}
+ @log = nil
+
#
- # Returns the Database configuration that is stored in the
- # +CONFIG_FILE+. Defaults to +DEFAULT_CONFIG+ if +CONFIG_FILE+ does not
- # exist.
+ # Returns the Database repositories to use.
#
+ # @return [Hash{Symbol => Addressable::URI}]
+ # The database repository names and URIs.
+ #
# @raise [InvalidConfig]
- # The config file did not contain a YAML Hash or String.
+ # The config file did not contain a YAML Hash.
#
- def Database.config
- unless (class_variable_defined?('@@ronin_database_config'))
- @@ronin_database_config = DEFAULT_CONFIG
+ # @since 1.0.0
+ #
+ def Database.repositories
+ if @repositories.empty?
+ @repositories[:default] = DEFAULT_REPOSITORY
if File.file?(CONFIG_FILE)
- conf = YAML.load(CONFIG_FILE)
+ conf = YAML.load_file(CONFIG_FILE)
- unless (conf.kind_of?(Hash) || conf.kind_of?(String))
- raise(InvalidConfig,"#{CONFIG_FILE} must contain either a Hash or a String",caller)
+ unless conf.kind_of?(Hash)
+ raise(InvalidConfig,"#{CONFIG_FILE} must contain a YAML Hash of repositories")
end
- @@ronin_database_config = conf
+ conf.each do |name,uri|
+ @repositories[name.to_sym] = Addressable::URI.parse(uri)
+ end
end
end
- return @@ronin_database_config ||= DEFAULT_CONFIG
+ return @repositories
end
#
- # Sets the Database configuration.
+ # Determines if the Database provides a specific repository.
#
- # @param [String, Hash] configuration
- # The DataMapper configuration to set the Ronin::Database with.
+ # @param [String, Symbol] name
+ # Name of the repository.
#
- def Database.config=(configuration)
- @@ronin_database_config = configuration
+ # @return [Boolean]
+ # Specifies if the Database provides the repository.
+ #
+ # @since 1.0.0
+ #
+ def Database.repository?(name)
+ Database.repositories.has_key?(name.to_sym)
end
#
- # @return [DataMapper::Logger, nil]
- # The current Database log.
+ # Saves the Database configuration to `CONFIG_FILE`.
#
- def Database.log
- @@ronin_database_log ||= nil
+ # @yield []
+ # If a block is given, it will be called before the database
+ # configuration is saved.
+ #
+ # @return [true]
+ #
+ # @since 1.0.0
+ #
+ def Database.save
+ yield if block_given?
+
+ File.open(CONFIG_FILE,'w') do |file|
+ hash = {}
+
+ Database.repositories.each do |name,value|
+ hash[name.to_s] = value.to_s
+ end
+
+ YAML.dump(hash,file)
+ end
+
+ return true
end
#
# Setup the Database log.
#
@@ -100,64 +139,153 @@
# @option options [IO] :stream
# The stream to use for the log.
#
# @option options [Symbol] :level
# The level of messages to log.
- # May be either +:fatal+, +:error+, +:warn+, +:info+ or +:debug+.
+ # May be either `:fatal`, `:error`, `:warn`, `:info` or `:debug`.
#
- # @return [DataMapper::Logger]
- # The new Database log.
+ # @return [true]
+ # Specifies that the log has been setup.
#
def Database.setup_log(options={})
path = (options[:path] || DEFAULT_LOG_PATH)
stream = (options[:stream] || File.new(path,'w+'))
level = (options[:level] || DEFAULT_LOG_LEVEL)
- return @@ronin_database_log = DataMapper::Logger.new(stream,level)
+ @log = DataMapper::Logger.new(stream,level)
+ return true
end
#
+ # Determines if a specific database repository is setup.
+ #
+ # @param [Symbol] name
+ # The database repository name.
+ #
# @return [Boolean]
# Specifies wether or not the Database is setup.
#
- def Database.setup?
- repository = DataMapper.repository(Model::REPOSITORY_NAME)
+ def Database.setup?(name=:default)
+ repository = DataMapper.repository(name)
return repository.class.adapters.has_key?(repository.name)
end
#
- # Updates the Database, by running auto-upgrades, but only if the
- # Database is already setup.
+ # Upgrades the Database, by running migrations for a given
+ # ronin library, but only if the Database has been setup.
#
- # @yield []
- # The block to call before the Database is updated.
+ # @return [Boolean]
+ # Specifies whether the Database was migrated or is currently
+ # not setup.
#
- def Database.update!(&block)
- block.call if block
-
- DataMapper.auto_upgrade!(Model::REPOSITORY_NAME) if Database.setup?
- return nil
+ def Database.upgrade!
+ if Database.setup?
+ Migrations.migrate_up!
+ else
+ false
+ end
end
#
# Sets up the Database.
#
- # @param [String, Hash] configuration
- # The DataMapper configuration to use to setup the Database.
- #
# @yield []
# The block to call after the Database has been setup, but before
# it is updated.
#
- def Database.setup(configuration=Database.config,&block)
+ # @see Database.upgrade!
+ #
+ def Database.setup(&block)
# setup the database log
- Database.setup_log unless Database.log
+ Database.setup_log unless @log
- # setup the database repository
- DataMapper.setup(Model::REPOSITORY_NAME, configuration)
+ # setup the database repositories
+ Database.repositories.each do |name,uri|
+ DataMapper.setup(name,uri)
+ end
- Database.update!(&block)
+ # auto-upgrade the database repository
+ Database.upgrade!(&block)
+ end
+
+ #
+ # Performs Database transactions within a given repository.
+ #
+ # @param [String, Symbol] name
+ # The name of the repository to access.
+ #
+ # @return [DataMapper::Repository]
+ # The Database repository.
+ #
+ # @raise [UnknownRepository]
+ # The specified Database repository is unknown.
+ #
+ # @since 1.0.0
+ #
+ def Database.repository(name,&block)
+ name = name.to_sym
+
+ unless Database.repository?(name)
+ raise(UnknownRepository,"unknown database repository #{name}")
+ end
+
+ return DataMapper.repository(name,&block)
+ end
+
+ #
+ # Clears the Database, by running destructive auto-migrations.
+ #
+ # @param [String, Symbol] name
+ # The name of the Database repository to clear.
+ #
+ # @yield []
+ # If a block is given, it will be called after the Database
+ # repository has been cleared.
+ #
+ # @return [nil]
+ #
+ # @raise [UnknownRepository]
+ # The specified Database repository is unknown.
+ #
+ # @since 1.0.0
+ #
+ def Database.clear(name)
+ name = name.to_sym
+
+ unless Database.repository?(name)
+ raise(UnknownRepository,"unknown database repository #{name}")
+ end
+
+ DataMapper.auto_migrate!(name)
+
+ yield if block_given?
return nil
+ end
+
+ #
+ # Performs Database transactions in each of the Database
+ # repositories.
+ #
+ # @yield []
+ # The given block will be ran within the context of each Database
+ # repository.
+ #
+ # @return [Array]
+ # The results from each database transaction.
+ #
+ # @since 1.0.0
+ #
+ def Database.map(&block)
+ results = []
+
+ Database.repositories.each_key do |name|
+ DataMapper.repository(name) do
+ result = block.call()
+ results << result unless result.nil?
+ end
+ end
+
+ return results
end
end
end