lib/core/artifact.rb in buildr-0.15.0 vs lib/core/artifact.rb in buildr-0.16.0
- old
+ new
@@ -1,27 +1,29 @@
module Buildr
# This module gives you a way to access the individual properties of an
- # artifact: id, group, type and version. It can also return the artifact
- # specification.
+ # artifact: id, group, type, classifier and version. It also provides other
+ # methods commonly used on an artifact, specifically #to_hash and #to_spec.
module ActsAsArtifact
+ ARTIFACT_ATTRIBUTES = [:group, :id, :type, :classifier, :version]
+
class << self
def included(mod)
mod.extend self
end
end
- # The artifact id.
+ # The artifact identifier.
attr_reader :id
- # The group id.
+ # The group identifier.
attr_reader :group
# The file type.
attr_reader :type
# The version number.
attr_reader :version
- # Optional classifier.
+ # Optional artifact classifier.
attr_reader :classifier
# Returns the artifact specification as a hash.
def to_spec_hash()
base = { :group=>group, :id=>id, :type=>type, :version=>version }
@@ -29,140 +31,141 @@
end
alias_method :to_hash, :to_spec_hash
# Returns the artifact specification, in the structure:
# <group>:<artifact>:<type>:<version>
+ # or
+ # <group>:<artifact>:<type>:<classifier><:<version>
def to_spec()
classifier.blank? ? "#{group}:#{id}:#{type}:#{version}" : "#{group}:#{id}:#{type}:#{classifier}:#{version}"
end
# Apply specification to this artifact.
def apply_spec(spec)
- case spec
- when String
- @group, @id, @type, @version, *rest = spec.split(":")
- unless rest.empty?
- @classifier, @version = @version, rest.shift
- fail "Expecting project:id:type:version or project:id:type:classifier:version, found #{spec}" unless rest.empty?
- end
- when Hash
- [:group, :id, :type, :version, :classifier].each { |key| instance_variable_set("@#{key}", spec[key]) }
- @type ||= DEFAULT_FILE_TYPE
- else
- raise ArgumentError, "Expecting a string or a hash"
- end
+ spec = Artifact.to_hash(spec)
+ ARTIFACT_ATTRIBUTES.each { |key| instance_variable_set("@#{key}", spec[key]) }
self
end
+ # Convenience method that returns a POM artifact.
def pom()
return self if type.to_s == "pom"
artifact(:group=>group, :id=>id, :version=>version, :type=>"pom", :classifier=>classifier)
end
end
- # Use the artifact and artifacts method to create artifact tasks.
+ # The Artifact task maps to an artifact file in the local repository
+ # and knows how to download the file from a remote repository.
+ #
+ # The task will only download the file if it does not exist. You can
+ # enhance the task to create the artifact yourself.
class Artifact < Rake::FileCreationTask
# The default file type for artifacts, if not specified.
DEFAULT_FILE_TYPE = "jar"
include ActsAsArtifact
class << self
- # Lookup an artifact task based on its specification.
+ # Lookup a previously registered artifact task based on the
+ # artifact specification (string or hash).
def lookup(spec)
@artifacts ||= {}
- @artifacts[hash_to_spec(spec)]
+ @artifacts[to_spec(spec)]
end
- # Register a task as an artifact. Returns the task when calling
- # #artifacts. For example, a project will use this to register the
- # packages it creates.
- def register(task)
+ # Register an artifact task(s) for later lookup (see #lookup).
+ def register(*tasks)
@artifacts ||= {}
- if task.respond_to?(:to_hash)
- @artifacts[hash_to_spec(task.to_hash)] = task
- else
- fail "Can only call with an artifact task"
- end
+ fail "You can only register an artifact task, strings and hashes are just not good enough" unless
+ tasks.all? { |task| task.respond_to?(:to_spec) && task.respond_to?(:invoke) }
+ tasks.each { |task| @artifacts[task.to_spec] = task }
+ tasks
end
# Turn a spec into a hash. This method accepts a string, hash or any object
- # that responds to the method to_spec. There are several reasons you'll want
- # to use this method:
- # * You can pass it anything that could possibly be a spec, and get a hash.
- # * It will check that your spec includes the group identifier, artifact
- # identifier and version number, and set the file type, if not specified.
+ # that responds to the method to_spec. There are several reasons to use this
+ # method:
+ # * You can pass anything that could possibly be a spec, and get a hash.
+ # * It will check that the spec includes the group identifier, artifact
+ # identifier and version number and set the file type, if missing.
# * It will always return a new specs hash.
- # * Calling to_s on the hash will return a spec string.
#
# :nodoc:
- def spec_to_hash(spec)
- return spec_to_hash(spec.to_spec) if spec.respond_to?(:to_spec)
- if String === spec
- group, id, type, version, *rest = spec.split(":")
- unless rest.empty?
- classifier, version = version, rest.shift
- fail "Expecting project:id:type:version or project:id:type:classifier:version, found #{spec}" unless rest.empty?
- end
- fail "Missing file type for #{spec}" if type.blank?
- spec_to_hash :group=>group, :id=>id, :type=>type, :version=>version, :classifier=>classifier
- elsif Hash === spec
- spec = spec.clone
+ def to_hash(spec)
+ if spec.respond_to?(:to_spec)
+ to_hash spec.to_spec
+ elsif Hash === spec
+ # Sanitize the hash and check it's valid.
+ spec = ARTIFACT_ATTRIBUTES.inject({}) { |h, k| h[k] = spec[k] ; h }
fail "Missing group identifier for #{spec.inspect}" if spec[:group].blank?
fail "Missing artifact identifier for #{spec.inspect}" if spec[:id].blank?
fail "Missing version for #{spec.inspect}" if spec[:version].blank?
spec[:type] = DEFAULT_FILE_TYPE if spec[:type].blank?
spec
+ elsif String === spec
+ group, id, type, version, *rest = spec.split(":")
+ unless rest.empty?
+ # Optional classifier comes before version.
+ classifier, version = version, rest.shift
+ fail "Expecting <project:id:type:version> or <project:id:type:classifier:version>, found <#{spec}>" unless rest.empty?
+ end
+ to_hash :group=>group, :id=>id, :type=>type, :version=>version, :classifier=>classifier
else
- fail "Spec must be a string, hash or object that responds to to_spec"
+ fail "Expecting a String, Hash or object that responds to to_spec"
end
end
- # Convert a hash back to a spec string.
- def hash_to_spec(hash)
+ # Convert a hash back to a spec string. This method accepts
+ # a string, hash or any object that responds to to_spec.
+ # :nodoc:
+ def to_spec(hash)
+ hash = to_hash(hash) unless Hash === hash
version = ":#{hash[:version]}" unless hash[:version].blank?
classifier = ":#{hash[:classifier]}" unless hash[:classifier].blank?
"#{hash[:group]}:#{hash[:id]}:#{hash[:type] || DEFAULT_FILE_TYPE}#{classifier}#{version}"
end
# Convert a hash to a file name.
+ # :nodoc:
def hash_to_file_name(hash)
version = "-#{hash[:version]}" unless hash[:version].blank?
classifier = "-#{hash[:classifier]}" unless hash[:classifier].blank?
"#{hash[:id]}#{version}#{classifier}.#{hash[:type] || DEFAULT_FILE_TYPE}"
end
end
- def initialize(*args)
+ def execute()
+ # Default behavior: download the artifact from one of the remote
+ # repositories if the file does not exist. But this default behavior
+ # is counter useful if the artifact knows how to build itself
+ # (e.g. download from a different location), so don't perform it
+ # if the task found a different way to create the artifact.
super
- enhance do |task|
- # Download the artifact form one of the remote repositories if the
- # file does not exist in the local repository, and no other behavior
- # specified. If this task has been enhanced, delegate to the other
- # enhancers. We don't know if this is the first or other enhancement,
- # but we only need to know it's not the only one.
- if @actions.size == 1
- repositories.download(to_spec)
- end
+ unless Rake.application.options.dryrun || File.exist?(name)
+ repositories.download(to_spec)
end
end
end
- # Singleton object for specifying the local, remote and release repositories.
+ # Holds the path to the local repository, URLs for remote repositories, and
+ # settings for the deployment repository.
class Repositories
include Singleton
# Returns the path to the local repository.
#
# The default path is .m2/repository relative to the home directory.
+ # You can change the location of the local repository by using a symbol
+ # link or by setting a different path. If you set a different path, do it
+ # in the buildr.rb file instead of the Rakefile.
def local()
@local ||= ENV["local_repo"] || File.join(ENV["HOME"], ".m2", "repository")
end
# Sets the path to the local repository.
@@ -174,11 +177,11 @@
#
# For example:
# locate :group=>"log4j", :id=>"log4j", :version=>"1.1"
# => ~/.m2/repository/log4j/log4j/1.1/log4j-1.1.jar
def locate(spec)
- spec = Artifact.spec_to_hash(spec) unless Hash === spec
+ spec = Artifact.to_hash(spec)
File.join(local, spec[:group].split("."), spec[:id], spec[:version], Artifact.hash_to_file_name(spec))
end
# Returns a hash of all the remote repositories. The key is the repository
# identifier, and the value is the repository base URL.
@@ -208,14 +211,14 @@
# Attempts to download the artifact from one of the remote repositories
# and store it in the local repository. Returns the path if downloaded,
# otherwise raises an exception.
def download(spec)
- spec = Artifact.spec_to_hash(spec) unless Hash === spec
+ spec = Artifact.to_hash(spec) unless Hash === spec
path = locate(spec)
- puts "Downloading #{Artifact.hash_to_spec(spec)}" if Rake.application.options.trace
+ puts "Downloading #{Artifact.to_spec(spec)}" if Rake.application.options.trace
return path if remote.any? do |repo_id, repo_url|
begin
rel_path = spec[:group].gsub(".", "/") +
"/#{spec[:id]}/#{spec[:version]}/#{Artifact.hash_to_file_name(spec)}"
Transports.perform URI.parse(repo_url.to_s) do |http|
@@ -230,31 +233,42 @@
rescue Exception=>error
warn error if Rake.application.options.trace
false
end
end
- fail "Failed to download #{Artifact.hash_to_spec(spec)}, tried the following repositories:\n#{repositories.remote.values.join("\n")}"
+ fail "Failed to download #{Artifact.to_spec(spec)}, tried the following repositories:\n#{repositories.remote.values.join("\n")}"
end
- # Specifies deployment target for all artifacts generated by this project.
+ # Specifies the deployment repository. Accepts a hash with the different
+ # repository settings (e.g. url, username, password). Anything else is
+ # interepted as the URL.
#
# For example:
- # repositories.deploy_to = "sftp://example.com/var/www/maven/"
+ # repositories.deploy_to = { :url=>"sftp://example.com/var/www/maven/",
+ # :username="john", :password=>"secret" }
# or:
# repositories.deploy_to = "sftp://john:secret@example.com/var/www/maven/"
def deploy_to=(options)
options = { :url=>options } unless Hash === options
@deploy_to = options
end
+ # Returns the current deployment repository configuration. This is a more
+ # convenient way to specify deployment in the Rakefile, and override it
+ # locally. For example:
+ # # Rakefile
+ # repositories.deploy_to[:url] ||= "sftp://example.com"
+ # # buildr.rb
+ # repositories.deploy_to[:url] = "sftp://acme.org"
def deploy_to()
- @deploy_to || {}
+ @deploy_to ||= {}
end
end
- # Returns a global object for setting local and remote repositories.
+
+ # Returns a global object for setting local, remote and deploy repositories.
# See Repositories.
def repositories()
Repositories.instance
end
@@ -274,18 +288,17 @@
#
# To specify an artifact and the means for creating it:
# download(artifact("dojo:dojo-widget:zip:2.0")=>
# "http://download.dojotoolkit.org/release-2.0/dojo-2.0-widget.zip")
def artifact(spec, &block)
- spec = Artifact.spec_to_hash(spec)
+ spec = Artifact.to_hash(spec)
unless task = Artifact.lookup(spec)
task = Artifact.define_task(repositories.locate(spec))
Artifact.register(task)
end
task.apply_spec spec
- task.enhance(&block) if block_given?
- task
+ task.enhance &block
end
# Creates multiple artifacts from a set of specifications and returns
# an array of tasks.
#
@@ -318,21 +331,21 @@
def artifacts(*specs)
specs.inject([]) do |set, spec|
case spec
when Hash
set |= [artifact(spec)]
- when /:.*:.*:/
+ when /:/
set |= [artifact(spec)]
when String
set |= [file(spec)]
when Rake::Task
set |= [spec]
when Project
set |= artifacts(spec.packages)
when Array
set |= artifacts(*spec)
else
- fail "Invalid artifact specification: #{spec || 'nil'}"
+ fail "Invalid artifact specification: #{spec.to_s || 'nil'}"
end
set
end
end