lib/generators/templates/application/common/merb.thor in merb-gen-0.9.13 vs lib/generators/templates/application/common/merb.thor in merb-gen-1.0
- old
+ new
@@ -3,11 +3,11 @@
require 'thor'
require 'fileutils'
require 'yaml'
# Important - don't change this line or its position
-MERB_THOR_VERSION = '0.1.0'
+MERB_THOR_VERSION = '0.2.1'
##############################################################################
module ColorfulMessages
@@ -333,11 +333,11 @@
require '#{then_req}'
end
# use gems dir if ../gems exists - eg. only for ./bin/#{bin_file_name}
if File.directory?(gems_dir = File.join(File.dirname(__FILE__), '..', 'gems'))
- $BUNDLE = true; Gem.clear_paths; Gem.path.replace([gems_dir])
+ $BUNDLE = true; Gem.clear_paths; Gem.path.replace([File.expand_path(gems_dir)])
ENV["PATH"] = "\#{File.dirname(__FILE__)}:\#{gems_dir}/bin:\#{ENV["PATH"]}"
if (local_gem = Dir[File.join(gems_dir, "specifications", "#{spec.name}-*.gemspec")].last)
version = File.basename(local_gem)[/-([\\.\\d]+)\\.gemspec$/, 1]
end
end
@@ -444,10 +444,14 @@
def self.included(base)
base.send(:include, ColorfulMessages)
base.extend ColorfulMessages
end
+ def use_edge_gem_server
+ ::Gem.sources << 'http://edge.merbivore.com'
+ end
+
def source_manager
@_source_manager ||= SourceManager.new(source_dir)
end
def extract_repositories(names)
@@ -641,27 +645,542 @@
##############################################################################
$SILENT = true # don't output all the mess some rake package tasks spit out
module Merb
+
+ class Gem < Thor
+ include MerbThorHelper
+ extend GemManagement
+
+ attr_accessor :system, :local, :missing
+
+ global_method_options = {
+ "--merb-root" => :optional, # the directory to operate on
+ "--version" => :optional, # gather specific version of gem
+ "--ignore-dependencies" => :boolean # don't install sub-dependencies
+ }
+
+ method_options global_method_options
+ def initialize(*args); super; end
+
+ # List gems that match the specified criteria.
+ #
+ # By default all local gems are listed. When the first argument is 'all' the
+ # list is partitioned into system an local gems; specify 'system' to show
+ # only system gems. A second argument can be used to filter on a set of known
+ # components, like all merb-more gems for example.
+ #
+ # Examples:
+ #
+ # merb:gem:list # list all local gems - the default
+ # merb:gem:list all # list system and local gems
+ # merb:gem:list system # list only system gems
+ # merb:gem:list all merb-more # list only merb-more related gems
+ # merb:gem:list --version 0.9.8 # list gems that match the version
+
+ desc 'list [all|local|system] [comp]', 'Show installed gems'
+ def list(filter = 'local', comp = nil)
+ deps = comp ? Merb::Stack.select_component_dependencies(dependencies, comp) : dependencies
+ self.system, self.local, self.missing = Merb::Gem.partition_dependencies(deps, gem_dir)
+ case filter
+ when 'all'
+ message 'Installed system gems:'
+ display_gemspecs(system)
+ message 'Installed local gems:'
+ display_gemspecs(local)
+ when 'system'
+ message 'Installed system gems:'
+ display_gemspecs(system)
+ when 'local'
+ message 'Installed local gems:'
+ display_gemspecs(local)
+ else
+ warning "Invalid listing filter '#{filter}'"
+ end
+ end
+
+ # Install the specified gems.
+ #
+ # All arguments should be names of gems to install.
+ #
+ # When :force => true then any existing versions of the gems to be installed
+ # will be uninstalled first. It's important to note that so-called meta-gems
+ # or gems that exactly match a set of Merb::Stack.components will have their
+ # sub-gems uninstalled too. For example, uninstalling merb-more will install
+ # all contained gems: merb-action-args, merb-assets, merb-gen, ...
+ #
+ # Examples:
+ #
+ # merb:gem:install merb-core merb-slices # install all specified gems
+ # merb:gem:install merb-core --version 0.9.8 # install a specific version of a gem
+ # merb:gem:install merb-core --force # uninstall then subsequently install the gem
+ # merb:gem:install merb-core --cache # try to install locally from system gems
+ # merb:gem:install merb --merb-edge # install from edge.merbivore.com
+
+ desc 'install GEM_NAME [GEM_NAME, ...]', 'Install a gem from rubygems'
+ method_options "--cache" => :boolean,
+ "--dry-run" => :boolean,
+ "--force" => :boolean,
+ "--merb-edge" => :boolean
+ def install(*names)
+ opts = { :version => options[:version], :cache => options[:cache] }
+ use_edge_gem_server if options[:"merb-edge"]
+ current_gem = nil
+
+ # uninstall existing gems of the ones we're going to install
+ uninstall(*names) if options[:force]
+
+ message "Installing #{names.length} #{names.length == 1 ? 'gem' : 'gems'}..."
+ puts "This may take a while..."
+
+ names.each do |gem_name|
+ current_gem = gem_name
+ if dry_run?
+ note "Installing #{current_gem}..."
+ else
+ message "Installing #{current_gem}..."
+ self.class.install(gem_name, default_install_options.merge(opts))
+ end
+ end
+ rescue => e
+ error "Failed to install #{current_gem ? current_gem : 'gem'} (#{e.message})"
+ end
+
+ # Uninstall the specified gems.
+ #
+ # By default all specified gems are uninstalled. It's important to note that
+ # so-called meta-gems or gems that match a set of Merb::Stack.components will
+ # have their sub-gems uninstalled too. For example, uninstalling merb-more
+ # will install all contained gems: merb-action-args, merb-assets, ...
+ #
+ # Existing dependencies will be clobbered; when :force => true then all gems
+ # will be cleared, otherwise only existing local dependencies of the
+ # matching component set will be removed.
+ #
+ # Examples:
+ #
+ # merb:gem:uninstall merb-core merb-slices # uninstall all specified gems
+ # merb:gem:uninstall merb-core --version 0.9.8 # uninstall a specific version of a gem
+
+ desc 'uninstall GEM_NAME [GEM_NAME, ...]', 'Unstall a gem'
+ method_options "--dry-run" => :boolean
+ def uninstall(*names)
+ opts = { :version => options[:version] }
+ current_gem = nil
+ if dry_run?
+ note "Uninstalling any existing gems of: #{names.join(', ')}"
+ else
+ message "Uninstalling any existing gems of: #{names.join(', ')}"
+ names.each do |gem_name|
+ current_gem = gem_name
+ Merb::Gem.uninstall(gem_name, default_uninstall_options) rescue nil
+ # if this gem is a meta-gem or a component set name, remove sub-gems
+ (Merb::Stack.components(gem_name) || []).each do |comp|
+ Merb::Gem.uninstall(comp, default_uninstall_options) rescue nil
+ end
+ end
+ end
+ rescue => e
+ error "Failed to uninstall #{current_gem ? current_gem : 'gem'} (#{e.message})"
+ end
+
+ # Recreate all gems from gems/cache on the current platform.
+ #
+ # This task should be executed as part of a deployment setup, where the
+ # deployment system runs this after the app has been installed.
+ # Usually triggered by Capistrano, God...
+ #
+ # It will regenerate gems from the bundled gems cache for any gem that has
+ # C extensions - which need to be recompiled for the target deployment platform.
+ #
+ # Note: at least gems/cache and gems/specifications should be in your SCM.
+
+ desc 'redeploy', 'Recreate all gems on the current platform'
+ method_options "--dry-run" => :boolean, "--force" => :boolean
+ def redeploy
+ require 'tempfile' # for Dir::tmpdir access
+ if gem_dir && File.directory?(cache_dir = File.join(gem_dir, 'cache'))
+ specs = local_gemspecs
+ message "Recreating #{specs.length} gems from cache..."
+ puts "This may take a while..."
+ specs.each do |gemspec|
+ if File.exists?(gem_file = File.join(cache_dir, "#{gemspec.full_name}.gem"))
+ gem_file_copy = File.join(Dir::tmpdir, File.basename(gem_file))
+ if dry_run?
+ note "Recreating #{gemspec.full_name}"
+ else
+ message "Recreating #{gemspec.full_name}"
+ if options[:force] && File.directory?(gem = File.join(gem_dir, 'gems', gemspec.full_name))
+ puts "Removing existing #{gemspec.full_name}"
+ FileUtils.rm_rf(gem)
+ end
+ # Copy the gem to a temporary file, because otherwise RubyGems/FileUtils
+ # will complain about copying identical files (same source/destination).
+ FileUtils.cp(gem_file, gem_file_copy)
+ Merb::Gem.install(gem_file_copy, :install_dir => gem_dir, :ignore_dependencies => true)
+ File.delete(gem_file_copy)
+ end
+ end
+ end
+ else
+ error "No application local gems directory found"
+ end
+ end
+
+ private
+
+ # Return dependencies for all installed gems; both system-wide and locally;
+ # optionally filters on :version requirement.
+ def dependencies
+ version_req = if options[:version]
+ ::Gem::Requirement.create(options[:version])
+ else
+ ::Gem::Requirement.default
+ end
+ if gem_dir
+ ::Gem.clear_paths; ::Gem.path.unshift(gem_dir)
+ ::Gem.source_index.refresh!
+ end
+ deps = []
+ ::Gem.source_index.each do |fullname, gemspec|
+ if version_req.satisfied_by?(gemspec.version)
+ deps << ::Gem::Dependency.new(gemspec.name, "= #{gemspec.version}")
+ end
+ end
+ ::Gem.clear_paths if gem_dir
+ deps.sort
+ end
+
+ public
+
+ # Install gem with some default options.
+ def self.install(name, options = {})
+ defaults = {}
+ defaults[:cache] = false unless opts[:install_dir]
+ install_gem(name, defaults.merge(options))
+ end
+
+ # Uninstall gem with some default options.
+ def self.uninstall(name, options = {})
+ defaults = { :ignore => true, :executables => true }
+ uninstall_gem(name, defaults.merge(options))
+ end
+
+ end
+
+ class Tasks < Thor
+
+ include MerbThorHelper
+
+ # Show merb.thor version information
+ #
+ # merb:tasks:version # show the current version info
+ # merb:tasks:version --info # show extended version info
+
+ desc 'version', 'Show verion info'
+ method_options "--info" => :boolean
+ def version
+ message "Currently installed merb.thor version: #{MERB_THOR_VERSION}"
+ if options[:version]
+ self.options = { :"dry-run" => true }
+ self.update # run update task with dry-run enabled
+ end
+ end
+
+ # Update merb.thor tasks from remotely available version
+ #
+ # merb:tasks:update # update merb.thor
+ # merb:tasks:update --force # force-update merb.thor
+ # merb:tasks:update --dry-run # show version info only
+
+ desc 'update [URL]', 'Fetch the latest merb.thor and install it locally'
+ method_options "--dry-run" => :boolean, "--force" => :boolean
+ def update(url = 'http://merbivore.com/merb.thor')
+ require 'open-uri'
+ require 'rubygems/version'
+ remote_file = open(url)
+ code = remote_file.read
+
+ # Extract version information from the source code
+ if version = code[/^MERB_THOR_VERSION\s?=\s?('|")([\.\d]+)('|")/,2]
+ # borrow version comparison from rubygems' Version class
+ current_version = ::Gem::Version.new(MERB_THOR_VERSION)
+ remote_version = ::Gem::Version.new(version)
+
+ if current_version >= remote_version
+ puts "currently installed: #{current_version}"
+ if current_version != remote_version
+ puts "available version: #{remote_version}"
+ end
+ info "No update of merb.thor necessary#{options[:force] ? ' (forced)' : ''}"
+ proceed = options[:force]
+ elsif current_version < remote_version
+ puts "currently installed: #{current_version}"
+ puts "available version: #{remote_version}"
+ proceed = true
+ end
+
+ if proceed && !dry_run?
+ File.open(File.join(__FILE__), 'w') do |f|
+ f.write(code)
+ end
+ success "Installed the latest merb.thor (v#{version})"
+ end
+ else
+ raise "invalid source-code data"
+ end
+ rescue OpenURI::HTTPError
+ error "Error opening #{url}"
+ rescue => e
+ error "An error occurred (#{e.message})"
+ end
+
+ end
+
+ #### MORE LOW-LEVEL TASKS ####
+
+ class Source < Thor
+
+ group 'core'
+
+ include MerbThorHelper
+ extend GemManagement
+
+ attr_accessor :system, :local, :missing
+
+ global_method_options = {
+ "--merb-root" => :optional, # the directory to operate on
+ "--ignore-dependencies" => :boolean, # don't install sub-dependencies
+ "--sources" => :optional # a yml config to grab sources from
+ }
+
+ method_options global_method_options
+ def initialize(*args); super; end
+
+ # List source repositories, of either local or known sources.
+ #
+ # Examples:
+ #
+ # merb:source:list # list all local sources
+ # merb:source:list available # list all known sources
+
+ desc 'list [local|available]', 'Show git source repositories'
+ def list(mode = 'local')
+ if mode == 'available'
+ message 'Available source repositories:'
+ repos = self.class.repos(options[:sources])
+ repos.keys.sort.each { |name| puts "- #{name}: #{repos[name]}" }
+ elsif mode == 'local'
+ message 'Current source repositories:'
+ Dir[File.join(source_dir, '*')].each do |src|
+ next unless File.directory?(src)
+ src_name = File.basename(src)
+ unless (repos = source_manager.existing_repos(src_name)).empty?
+ puts "#{src_name}"
+ repos.keys.sort.each { |b| puts "- #{b}: #{repos[b]}" }
+ end
+ end
+ else
+ error "Unknown listing: #{mode}"
+ end
+ end
+
+ # Install the specified gems.
+ #
+ # All arguments should be names of gems to install.
+ #
+ # When :force => true then any existing versions of the gems to be installed
+ # will be uninstalled first. It's important to note that so-called meta-gems
+ # or gems that exactly match a set of Merb::Stack.components will have their
+ # sub-gems uninstalled too. For example, uninstalling merb-more will install
+ # all contained gems: merb-action-args, merb-assets, merb-gen, ...
+ #
+ # Examples:
+ #
+ # merb:source:install merb-core merb-slices # install all specified gems
+ # merb:source:install merb-core --force # uninstall then subsequently install the gem
+ # merb:source:install merb-core --wipe # clear repo then install the gem
+
+ desc 'install GEM_NAME [GEM_NAME, ...]', 'Install a gem from git source/edge'
+ method_options "--dry-run" => :boolean,
+ "--force" => :boolean,
+ "--wipe" => :boolean
+ def install(*names)
+ use_edge_gem_server
+ # uninstall existing gems of the ones we're going to install
+ uninstall(*names) if options[:force] || options[:wipe]
+
+ # We want dependencies instead of just names
+ deps = names.map { |n| ::Gem::Dependency.new(n, ::Gem::Requirement.default) }
+
+ # Selectively update repositories for the matching dependencies
+ update_dependency_repositories(deps) unless dry_run?
+
+ current_gem = nil
+ deps.each do |dependency|
+ current_gem = dependency.name
+ if dry_run?
+ note "Installing #{current_gem} from source..."
+ else
+ message "Installing #{current_gem} from source..."
+ puts "This may take a while..."
+ unless install_dependency_from_source(dependency)
+ raise "gem source not found"
+ end
+ end
+ end
+ rescue => e
+ error "Failed to install #{current_gem ? current_gem : 'gem'} (#{e.message})"
+ end
+
+ # Uninstall the specified gems.
+ #
+ # By default all specified gems are uninstalled. It's important to note that
+ # so-called meta-gems or gems that match a set of Merb::Stack.components will
+ # have their sub-gems uninstalled too. For example, uninstalling merb-more
+ # will install all contained gems: merb-action-args, merb-assets, ...
+ #
+ # Existing dependencies will be clobbered; when :force => true then all gems
+ # will be cleared, otherwise only existing local dependencies of the
+ # matching component set will be removed. Additionally when :wipe => true,
+ # the matching git repositories will be removed from the source directory.
+ #
+ # Examples:
+ #
+ # merb:source:uninstall merb-core merb-slices # uninstall all specified gems
+ # merb:source:uninstall merb-core --wipe # force-uninstall a gem and clear repo
+
+ desc 'uninstall GEM_NAME [GEM_NAME, ...]', 'Unstall a gem (specify --force to remove the repo)'
+ method_options "--version" => :optional, "--dry-run" => :boolean, "--wipe" => :boolean
+ def uninstall(*names)
+ # Remove the repos that contain the gem
+ if options[:wipe]
+ extract_repositories(names).each do |(name, url)|
+ if File.directory?(src = File.join(source_dir, name))
+ if dry_run?
+ note "Removing #{src}..."
+ else
+ info "Removing #{src}..."
+ FileUtils.rm_rf(src)
+ end
+ end
+ end
+ end
+
+ # Use the Merb::Gem#uninstall task to handle this
+ gem_tasks = Merb::Gem.new
+ gem_tasks.options = options
+ gem_tasks.uninstall(*names)
+ end
+
+ # Update the specified source repositories.
+ #
+ # The arguments can be actual repository names (from Merb::Source.repos)
+ # or names of known merb stack gems. If the repo doesn't exist already,
+ # it will be created and cloned.
+ #
+ # merb:source:pull merb-core # update source of specified gem
+ # merb:source:pull merb-slices # implicitly updates merb-more
+
+ desc 'pull REPO_NAME [GEM_NAME, ...]', 'Update git source repository from edge'
+ def pull(*names)
+ repos = extract_repositories(names)
+ update_repositories(repos)
+ unless repos.empty?
+ message "Updated the following repositories:"
+ repos.each { |name, url| puts "- #{name}: #{url}" }
+ else
+ warning "No repositories found to update!"
+ end
+ end
+
+ # Clone a git repository into ./src.
+
+ # The repository can be a direct git url or a known -named- repository.
+ #
+ # Examples:
+ #
+ # merb:source:clone merb-core
+ # merb:source:clone dm-core awesome-repo
+ # merb:source:clone dm-core --sources ./path/to/sources.yml
+ # merb:source:clone git://github.com/sam/dm-core.git
+
+ desc 'clone (REPO_NAME|URL) [DIR_NAME]', 'Clone git source repository by name or url'
+ def clone(repository, name = nil)
+ if repository =~ /^git:\/\//
+ repository_url = repository
+ repository_name = File.basename(repository_url, '.git')
+ elsif url = Merb::Source.repo(repository, options[:sources])
+ repository_url = url
+ repository_name = repository
+ end
+ source_manager.clone(name || repository_name, repository_url)
+ end
+
+ # Git repository sources - pass source_config option to load a yaml
+ # configuration file - defaults to ./config/git-sources.yml and
+ # ~/.merb/git-sources.yml - which you need to create yourself.
+ #
+ # Example of contents:
+ #
+ # merb-core: git://github.com/myfork/merb-core.git
+ # merb-more: git://github.com/myfork/merb-more.git
+
+ def self.repos(source_config = nil)
+ source_config ||= begin
+ local_config = File.join(Dir.pwd, 'config', 'git-sources.yml')
+ user_config = File.join(ENV["HOME"] || ENV["APPDATA"], '.merb', 'git-sources.yml')
+ File.exists?(local_config) ? local_config : user_config
+ end
+ if source_config && File.exists?(source_config)
+ default_repos.merge(YAML.load(File.read(source_config)))
+ else
+ default_repos
+ end
+ end
+
+ def self.repo(name, source_config = nil)
+ self.repos(source_config)[name]
+ end
+
+ # Default Git repositories
+ def self.default_repos
+ @_default_repos ||= {
+ 'merb' => "git://github.com/wycats/merb.git",
+ 'merb-plugins' => "git://github.com/wycats/merb-plugins.git",
+ 'extlib' => "git://github.com/sam/extlib.git",
+ 'dm-core' => "git://github.com/sam/dm-core.git",
+ 'dm-more' => "git://github.com/sam/dm-more.git",
+ 'sequel' => "git://github.com/wayneeseguin/sequel.git",
+ 'do' => "git://github.com/sam/do.git",
+ 'thor' => "git://github.com/wycats/thor.git",
+ 'rake' => "git://github.com/jimweirich/rake.git"
+ }
+ end
+
+ end
+
class Dependencies < Thor
+
+ group 'core'
# The Dependencies tasks will install dependencies based on actual application
# dependencies. For this, the application is queried for any dependencies.
# All operations will be performed within this context.
- attr_accessor :system, :local, :missing
+ attr_accessor :system, :local, :missing, :extract_dependencies
include MerbThorHelper
global_method_options = {
"--merb-root" => :optional, # the directory to operate on
- "--include-dependencies" => :boolean, # gather sub-dependencies
+ "--ignore-dependencies" => :boolean, # ignore sub-dependencies
"--stack" => :boolean, # gather only stack dependencies
"--no-stack" => :boolean, # gather only non-stack dependencies
- "--config" => :boolean, # gather dependencies from yaml config
+ "--extract" => :boolean, # gather dependencies from the app itself
"--config-file" => :optional, # gather from the specified yaml config
"--version" => :optional # gather specific version of framework
}
method_options global_method_options
@@ -679,11 +1198,11 @@
# merb:dependencies:list # list all dependencies - the default
# merb:dependencies:list local # list only local gems
# merb:dependencies:list all merb-more # list only merb-more related dependencies
# merb:dependencies:list --stack # list framework dependencies
# merb:dependencies:list --no-stack # list 3rd party dependencies
- # merb:dependencies:list --config # list dependencies from the default config
+ # merb:dependencies:list --extract # list dependencies by extracting them
# merb:dependencies:list --config-file file.yml # list from the specified config file
desc 'list [all|local|system|missing] [comp]', 'Show application dependencies'
def list(filter = 'all', comp = nil)
deps = comp ? Merb::Stack.select_component_dependencies(dependencies, comp) : dependencies
@@ -739,11 +1258,11 @@
# merb:dependencies:install stable --version 0.9.8 # install a specific version of the framework
# merb:dependencies:install stable missing # install currently missing gems locally
# merb:dependencies:install stable merb-more # install only merb-more related dependencies
# merb:dependencies:install stable --stack # install framework dependencies
# merb:dependencies:install stable --no-stack # install 3rd party dependencies
- # merb:dependencies:install stable --config # read dependencies from the default config
+ # merb:dependencies:install stable --extract # extract dependencies from the actual app
# merb:dependencies:install stable --config-file file.yml # read from the specified config file
#
# In addition to the options above, edge install uses the following:
#
# merb:dependencies:install edge # install all dependencies using edge strategy
@@ -782,10 +1301,11 @@
if deps.empty?
warning "No dependencies to install..."
else
puts "#{deps.length} dependencies to install..."
+ puts "This may take a while..."
install_dependencies(strategy, deps, clobber)
end
# Show current dependency info now that we're done
puts # Seperate output
@@ -810,11 +1330,10 @@
#
# Examples:
#
# merb:dependencies:uninstall # uninstall all dependencies - the default
# merb:dependencies:uninstall merb-more # uninstall merb-more related gems locally
- # merb:dependencies:uninstall --config # read dependencies from the default config
desc 'uninstall [comp]', 'Uninstall application dependencies'
method_options "--dry-run" => :boolean, "--force" => :boolean
def uninstall(comp = nil)
# If comp given, filter on known stack components
@@ -822,46 +1341,21 @@
self.system, self.local, self.missing = Merb::Gem.partition_dependencies(deps, gem_dir)
# Clobber existing local dependencies - based on self.local
clobber_dependencies!
end
- # Recreate binary gems on the current platform.
+ # Recreate all gems from gems/cache on the current platform.
#
- # This task should be executed as part of a deployment setup, where the
- # deployment system runs this after the app has been installed.
- # Usually triggered by Capistrano, God...
- #
- # It will regenerate gems from the bundled gems cache for any gem that has
- # C extensions - which need to be recompiled for the target deployment platform.
- #
- # Note: gems/cache should be in your SCM for this to work correctly.
+ # Note: use merb:gem:redeploy instead
- desc 'redeploy', 'Recreate any binary gems on the target platform'
- method_options "--dry-run" => :boolean
+ desc 'redeploy', 'Recreate all gems on the current platform'
+ method_options "--dry-run" => :boolean, "--force" => :boolean
def redeploy
- require 'tempfile' # for Dir::tmpdir access
- if gem_dir && File.directory?(cache_dir = File.join(gem_dir, 'cache'))
- local_gemspecs.each do |gemspec|
- unless gemspec.extensions.empty?
- if File.exists?(gem_file = File.join(cache_dir, "#{gemspec.full_name}.gem"))
- gem_file_copy = File.join(Dir::tmpdir, File.basename(gem_file))
- if dry_run?
- note "Recreating #{gemspec.full_name}"
- else
- message "Recreating #{gemspec.full_name}"
- # Copy the gem to a temporary file, because otherwise RubyGems/FileUtils
- # will complain about copying identical files (same source/destination).
- FileUtils.cp(gem_file, gem_file_copy)
- Merb::Gem.install(gem_file_copy, :install_dir => gem_dir)
- File.delete(gem_file_copy)
- end
- end
- end
- end
- else
- error "No application local gems directory found"
- end
+ warning 'Warning: merb:dependencies:redeploy has been deprecated - use merb:gem:redeploy instead'
+ gem = Merb::Gem.new
+ gem.options = options
+ gem.redeploy
end
# Create a dependencies configuration file.
#
# A configuration yaml file will be created from the extracted application
@@ -880,10 +1374,11 @@
# merb:dependencies:configure --config-file file.yml # write to the specified config file
desc 'configure [comp]', 'Create a dependencies config file'
method_options "--dry-run" => :boolean, "--force" => :boolean, "--versions" => :boolean
def configure(comp = nil)
+ self.extract_dependencies = true # of course we need to consult the app itself
# If comp given, filter on known stack components
deps = comp ? Merb::Stack.select_component_dependencies(dependencies, comp) : dependencies
# If --versions is set, update the version_requirements with the actual version available
if options[:versions]
@@ -946,17 +1441,17 @@
end
false
end
def dependencies
- if use_config?
- # Use preconfigured dependencies from yaml file
- deps = config_dependencies
- else
+ if extract_dependencies?
# Extract dependencies from the current application
deps = Merb::Stack.core_dependencies(gem_dir, ignore_dependencies?)
- deps += Merb::Dependencies.extract_dependencies(working_dir)
+ deps += Merb::Dependencies.extract_dependencies(working_dir)
+ else
+ # Use preconfigured dependencies from yaml file
+ deps = config_dependencies
end
stack_components = Merb::Stack.components
if options[:stack]
@@ -988,16 +1483,17 @@
def config_dependencies
if File.exists?(config_file)
self.class.parse_dependencies_yaml(File.read(config_file))
else
+ warning "No dependencies.yml file found at: #{config_file}"
[]
end
end
- def use_config?
- options[:config] || options[:"config-file"]
+ def extract_dependencies?
+ options[:extract] || extract_dependencies
end
def config_file
@config_file ||= begin
options[:"config-file"] || File.join(working_dir, 'config', 'dependencies.yml')
@@ -1045,10 +1541,11 @@
end
installed_from_rubygems
end
def edge_strategy(deps)
+ use_edge_gem_server
installed_from_rubygems = []
# Selectively update repositories for the matching dependencies
update_dependency_repositories(deps) unless dry_run?
@@ -1105,12 +1602,11 @@
end
Merb::BootLoader::Dependencies.dependencies
rescue StandardError => e
error "Couldn't extract dependencies from application!"
error e.message
- puts "Make sure you're executing the task from your app (--merb-root), or"
- puts "specify a config option (--config or --config-file=YAML_FILE)"
+ puts "Make sure you're executing the task from your app (--merb-root)"
return []
rescue SystemExit
error "Couldn't extract dependencies from application!"
error "application failed to run"
puts "Please check if your application runs using 'merb'; for example,"
@@ -1132,14 +1628,16 @@
end
end
dependencies
end
- end
+ end
class Stack < Thor
+ group 'core'
+
# The Stack tasks will install dependencies based on known sets of gems,
# regardless of actual application dependency settings.
DM_STACK = %w[
extlib
@@ -1306,10 +1804,11 @@
"--sources" => :optional,
"--force" => :boolean,
"--dry-run" => :boolean,
"--strategy" => :optional
def install(*comps)
+ use_edge_gem_server if options[:edge]
mngr = self.dependency_manager
deps = gather_dependencies(comps)
mngr.system, mngr.local, mngr.missing = Merb::Gem.partition_dependencies(deps, gem_dir)
mngr.install_dependencies(strategy, deps)
end
@@ -1514,472 +2013,8 @@
items.include?(item) ? (set_name = set) : nil
end
set_name
end
- end
-
- class Tasks < Thor
-
- include MerbThorHelper
-
- # Show merb.thor version information
- #
- # merb:tasks:version # show the current version info
- # merb:tasks:version --info # show extended version info
-
- desc 'version', 'Show verion info'
- method_options "--info" => :boolean
- def version
- message "Currently installed merb.thor version: #{MERB_THOR_VERSION}"
- if options[:version]
- self.options = { :"dry-run" => true }
- self.update # run update task with dry-run enabled
- end
- end
-
- # Update merb.thor tasks from remotely available version
- #
- # merb:tasks:update # update merb.thor
- # merb:tasks:update --force # force-update merb.thor
- # merb:tasks:update --dry-run # show version info only
-
- desc 'update [URL]', 'Fetch the latest merb.thor and install it locally'
- method_options "--dry-run" => :boolean, "--force" => :boolean
- def update(url = 'http://merbivore.com/merb.thor')
- require 'open-uri'
- require 'rubygems/version'
- remote_file = open(url)
- code = remote_file.read
-
- # Extract version information from the source code
- if version = code[/^MERB_THOR_VERSION\s?=\s?('|")([\.\d]+)('|")/,2]
- # borrow version comparison from rubygems' Version class
- current_version = ::Gem::Version.new(MERB_THOR_VERSION)
- remote_version = ::Gem::Version.new(version)
-
- if current_version >= remote_version
- puts "currently installed: #{current_version}"
- if current_version != remote_version
- puts "available version: #{remote_version}"
- end
- info "No update of merb.thor necessary#{options[:force] ? ' (forced)' : ''}"
- proceed = options[:force]
- elsif current_version < remote_version
- puts "currently installed: #{current_version}"
- puts "available version: #{remote_version}"
- proceed = true
- end
-
- if proceed && !dry_run?
- File.open(File.join(__FILE__), 'w') do |f|
- f.write(code)
- end
- success "Installed the latest merb.thor (v#{version})"
- end
- else
- raise "invalid source-code data"
- end
- rescue OpenURI::HTTPError
- error "Error opening #{url}"
- rescue => e
- error "An error occurred (#{e.message})"
- end
-
- end
-
- #### MORE LOW-LEVEL TASKS ####
-
- class Gem < Thor
-
- group 'core'
-
- include MerbThorHelper
- extend GemManagement
-
- attr_accessor :system, :local, :missing
-
- global_method_options = {
- "--merb-root" => :optional, # the directory to operate on
- "--version" => :optional, # gather specific version of gem
- "--ignore-dependencies" => :boolean # don't install sub-dependencies
- }
-
- method_options global_method_options
- def initialize(*args); super; end
-
- # List gems that match the specified criteria.
- #
- # By default all local gems are listed. When the first argument is 'all' the
- # list is partitioned into system an local gems; specify 'system' to show
- # only system gems. A second argument can be used to filter on a set of known
- # components, like all merb-more gems for example.
- #
- # Examples:
- #
- # merb:gem:list # list all local gems - the default
- # merb:gem:list all # list system and local gems
- # merb:gem:list system # list only system gems
- # merb:gem:list all merb-more # list only merb-more related gems
- # merb:gem:list --version 0.9.8 # list gems that match the version
-
- desc 'list [all|local|system] [comp]', 'Show installed gems'
- def list(filter = 'local', comp = nil)
- deps = comp ? Merb::Stack.select_component_dependencies(dependencies, comp) : dependencies
- self.system, self.local, self.missing = Merb::Gem.partition_dependencies(deps, gem_dir)
- case filter
- when 'all'
- message 'Installed system gems:'
- display_gemspecs(system)
- message 'Installed local gems:'
- display_gemspecs(local)
- when 'system'
- message 'Installed system gems:'
- display_gemspecs(system)
- when 'local'
- message 'Installed local gems:'
- display_gemspecs(local)
- else
- warning "Invalid listing filter '#{filter}'"
- end
- end
-
- # Install the specified gems.
- #
- # All arguments should be names of gems to install.
- #
- # When :force => true then any existing versions of the gems to be installed
- # will be uninstalled first. It's important to note that so-called meta-gems
- # or gems that exactly match a set of Merb::Stack.components will have their
- # sub-gems uninstalled too. For example, uninstalling merb-more will install
- # all contained gems: merb-action-args, merb-assets, merb-gen, ...
- #
- # Examples:
- #
- # merb:gem:install merb-core merb-slices # install all specified gems
- # merb:gem:install merb-core --version 0.9.8 # install a specific version of a gem
- # merb:gem:install merb-core --force # uninstall then subsequently install the gem
- # merb:gem:install merb-core --cache # try to install locally from system gems
-
- desc 'install GEM_NAME [GEM_NAME, ...]', 'Install a gem from rubygems'
- method_options "--cache" => :boolean,
- "--dry-run" => :boolean,
- "--force" => :boolean
- def install(*names)
- opts = { :version => options[:version], :cache => options[:cache] }
- current_gem = nil
-
- # uninstall existing gems of the ones we're going to install
- uninstall(*names) if options[:force]
-
- names.each do |gem_name|
- current_gem = gem_name
- if dry_run?
- note "Installing #{current_gem}..."
- else
- message "Installing #{current_gem}..."
- self.class.install(gem_name, default_install_options.merge(opts))
- end
- end
- rescue => e
- error "Failed to install #{current_gem ? current_gem : 'gem'} (#{e.message})"
- end
-
- # Uninstall the specified gems.
- #
- # By default all specified gems are uninstalled. It's important to note that
- # so-called meta-gems or gems that match a set of Merb::Stack.components will
- # have their sub-gems uninstalled too. For example, uninstalling merb-more
- # will install all contained gems: merb-action-args, merb-assets, ...
- #
- # Existing dependencies will be clobbered; when :force => true then all gems
- # will be cleared, otherwise only existing local dependencies of the
- # matching component set will be removed.
- #
- # Examples:
- #
- # merb:gem:uninstall merb-core merb-slices # uninstall all specified gems
- # merb:gem:uninstall merb-core --version 0.9.8 # uninstall a specific version of a gem
-
- desc 'uninstall GEM_NAME [GEM_NAME, ...]', 'Unstall a gem'
- method_options "--dry-run" => :boolean
- def uninstall(*names)
- opts = { :version => options[:version] }
- current_gem = nil
- if dry_run?
- note "Uninstalling any existing gems of: #{names.join(', ')}"
- else
- message "Uninstalling any existing gems of: #{names.join(', ')}"
- names.each do |gem_name|
- current_gem = gem_name
- Merb::Gem.uninstall(gem_name, default_uninstall_options) rescue nil
- # if this gem is a meta-gem or a component set name, remove sub-gems
- (Merb::Stack.components(gem_name) || []).each do |comp|
- Merb::Gem.uninstall(comp, default_uninstall_options) rescue nil
- end
- end
- end
- rescue => e
- error "Failed to uninstall #{current_gem ? current_gem : 'gem'} (#{e.message})"
- end
-
- private
-
- # Return dependencies for all installed gems; both system-wide and locally;
- # optionally filters on :version requirement.
- def dependencies
- version_req = if options[:version]
- ::Gem::Requirement.create(options[:version])
- else
- ::Gem::Requirement.default
- end
- if gem_dir
- ::Gem.clear_paths; ::Gem.path.unshift(gem_dir)
- ::Gem.source_index.refresh!
- end
- deps = []
- ::Gem.source_index.each do |fullname, gemspec|
- if version_req.satisfied_by?(gemspec.version)
- deps << ::Gem::Dependency.new(gemspec.name, "= #{gemspec.version}")
- end
- end
- ::Gem.clear_paths if gem_dir
- deps.sort
- end
-
- public
-
- # Install gem with some default options.
- def self.install(name, options = {})
- defaults = {}
- defaults[:cache] = false unless opts[:install_dir]
- install_gem(name, defaults.merge(options))
- end
-
- # Uninstall gem with some default options.
- def self.uninstall(name, options = {})
- defaults = { :ignore => true, :executables => true }
- uninstall_gem(name, defaults.merge(options))
- end
-
- end
-
- class Source < Thor
-
- group 'core'
-
- include MerbThorHelper
- extend GemManagement
-
- attr_accessor :system, :local, :missing
-
- global_method_options = {
- "--merb-root" => :optional, # the directory to operate on
- "--ignore-dependencies" => :boolean, # don't install sub-dependencies
- "--sources" => :optional # a yml config to grab sources from
- }
-
- method_options global_method_options
- def initialize(*args); super; end
-
- # List source repositories, of either local or known sources.
- #
- # Examples:
- #
- # merb:source:list # list all local sources
- # merb:source:list available # list all known sources
-
- desc 'list [local|available]', 'Show git source repositories'
- def list(mode = 'local')
- if mode == 'available'
- message 'Available source repositories:'
- repos = self.class.repos(options[:sources])
- repos.keys.sort.each { |name| puts "- #{name}: #{repos[name]}" }
- elsif mode == 'local'
- message 'Current source repositories:'
- Dir[File.join(source_dir, '*')].each do |src|
- next unless File.directory?(src)
- src_name = File.basename(src)
- unless (repos = source_manager.existing_repos(src_name)).empty?
- puts "#{src_name}"
- repos.keys.sort.each { |b| puts "- #{b}: #{repos[b]}" }
- end
- end
- else
- error "Unknown listing: #{mode}"
- end
- end
-
- # Install the specified gems.
- #
- # All arguments should be names of gems to install.
- #
- # When :force => true then any existing versions of the gems to be installed
- # will be uninstalled first. It's important to note that so-called meta-gems
- # or gems that exactly match a set of Merb::Stack.components will have their
- # sub-gems uninstalled too. For example, uninstalling merb-more will install
- # all contained gems: merb-action-args, merb-assets, merb-gen, ...
- #
- # Examples:
- #
- # merb:source:install merb-core merb-slices # install all specified gems
- # merb:source:install merb-core --force # uninstall then subsequently install the gem
- # merb:source:install merb-core --wipe # clear repo then install the gem
-
- desc 'install GEM_NAME [GEM_NAME, ...]', 'Install a gem from git source/edge'
- method_options "--dry-run" => :boolean,
- "--force" => :boolean,
- "--wipe" => :boolean
- def install(*names)
- # uninstall existing gems of the ones we're going to install
- uninstall(*names) if options[:force] || options[:wipe]
-
- # We want dependencies instead of just names
- deps = names.map { |n| ::Gem::Dependency.new(n, ::Gem::Requirement.default) }
-
- # Selectively update repositories for the matching dependencies
- update_dependency_repositories(deps) unless dry_run?
-
- current_gem = nil
- deps.each do |dependency|
- current_gem = dependency.name
- if dry_run?
- note "Installing #{current_gem} from source..."
- else
- message "Installing #{current_gem} from source..."
- unless install_dependency_from_source(dependency)
- raise "gem source not found"
- end
- end
- end
- rescue => e
- error "Failed to install #{current_gem ? current_gem : 'gem'} (#{e.message})"
- end
-
- # Uninstall the specified gems.
- #
- # By default all specified gems are uninstalled. It's important to note that
- # so-called meta-gems or gems that match a set of Merb::Stack.components will
- # have their sub-gems uninstalled too. For example, uninstalling merb-more
- # will install all contained gems: merb-action-args, merb-assets, ...
- #
- # Existing dependencies will be clobbered; when :force => true then all gems
- # will be cleared, otherwise only existing local dependencies of the
- # matching component set will be removed. Additionally when :wipe => true,
- # the matching git repositories will be removed from the source directory.
- #
- # Examples:
- #
- # merb:source:uninstall merb-core merb-slices # uninstall all specified gems
- # merb:source:uninstall merb-core --wipe # force-uninstall a gem and clear repo
-
- desc 'uninstall GEM_NAME [GEM_NAME, ...]', 'Unstall a gem (specify --force to remove the repo)'
- method_options "--version" => :optional, "--dry-run" => :boolean, "--wipe" => :boolean
- def uninstall(*names)
- # Remove the repos that contain the gem
- if options[:wipe]
- extract_repositories(names).each do |(name, url)|
- if File.directory?(src = File.join(source_dir, name))
- if dry_run?
- note "Removing #{src}..."
- else
- info "Removing #{src}..."
- FileUtils.rm_rf(src)
- end
- end
- end
- end
-
- # Use the Merb::Gem#uninstall task to handle this
- gem_tasks = Merb::Gem.new
- gem_tasks.options = options
- gem_tasks.uninstall(*names)
- end
-
- # Update the specified source repositories.
- #
- # The arguments can be actual repository names (from Merb::Source.repos)
- # or names of known merb stack gems. If the repo doesn't exist already,
- # it will be created and cloned.
- #
- # merb:source:pull merb-core # update source of specified gem
- # merb:source:pull merb-slices # implicitly updates merb-more
-
- desc 'pull REPO_NAME [GEM_NAME, ...]', 'Update git source repository from edge'
- def pull(*names)
- repos = extract_repositories(names)
- update_repositories(repos)
- unless repos.empty?
- message "Updated the following repositories:"
- repos.each { |name, url| puts "- #{name}: #{url}" }
- else
- warning "No repositories found to update!"
- end
- end
-
- # Clone a git repository into ./src.
-
- # The repository can be a direct git url or a known -named- repository.
- #
- # Examples:
- #
- # merb:source:clone merb-core
- # merb:source:clone dm-core awesome-repo
- # merb:source:clone dm-core --sources ./path/to/sources.yml
- # merb:source:clone git://github.com/sam/dm-core.git
-
- desc 'clone (REPO_NAME|URL) [DIR_NAME]', 'Clone git source repository by name or url'
- def clone(repository, name = nil)
- if repository =~ /^git:\/\//
- repository_url = repository
- repository_name = File.basename(repository_url, '.git')
- elsif url = Merb::Source.repo(repository, options[:sources])
- repository_url = url
- repository_name = repository
- end
- source_manager.clone(name || repository_name, repository_url)
- end
-
- # Git repository sources - pass source_config option to load a yaml
- # configuration file - defaults to ./config/git-sources.yml and
- # ~/.merb/git-sources.yml - which you need to create yourself.
- #
- # Example of contents:
- #
- # merb-core: git://github.com/myfork/merb-core.git
- # merb-more: git://github.com/myfork/merb-more.git
-
- def self.repos(source_config = nil)
- source_config ||= begin
- local_config = File.join(Dir.pwd, 'config', 'git-sources.yml')
- user_config = File.join(ENV["HOME"] || ENV["APPDATA"], '.merb', 'git-sources.yml')
- File.exists?(local_config) ? local_config : user_config
- end
- if source_config && File.exists?(source_config)
- default_repos.merge(YAML.load(File.read(source_config)))
- else
- default_repos
- end
- end
-
- def self.repo(name, source_config = nil)
- self.repos(source_config)[name]
- end
-
- # Default Git repositories
- def self.default_repos
- @_default_repos ||= {
- 'merb' => "git://github.com/wycats/merb.git",
- 'merb-plugins' => "git://github.com/wycats/merb-plugins.git",
- 'extlib' => "git://github.com/sam/extlib.git",
- 'dm-core' => "git://github.com/sam/dm-core.git",
- 'dm-more' => "git://github.com/sam/dm-more.git",
- 'sequel' => "git://github.com/wayneeseguin/sequel.git",
- 'do' => "git://github.com/sam/do.git",
- 'thor' => "git://github.com/wycats/thor.git",
- 'rake' => "git://github.com/jimweirich/rake.git"
- }
- end
-
end
end
\ No newline at end of file