Refactored how repositories are defined and loaded. We can now support probing tons of different types of repositories by loading them just in time.
This commit is contained in:
parent
147f927f84
commit
506be7f192
44
bin/qw
44
bin/qw
@ -1,38 +1,33 @@
|
||||
#!/usr/bin/env ruby
|
||||
# Add qwandry's library to the load path
|
||||
|
||||
# Add Qwandry's library to the load path
|
||||
$:.unshift File.dirname(__FILE__) + '/../lib'
|
||||
# Require it
|
||||
|
||||
# Require Qwandry's library
|
||||
require "qwandry.rb"
|
||||
|
||||
# Create launcher
|
||||
@qwandry = Qwandry::Launcher.new
|
||||
# Load Qwandry's configuration files
|
||||
config = Qwandry::Configuration
|
||||
config.load_configuration_files
|
||||
|
||||
# Create a launcher
|
||||
@launcher = Qwandry::Launcher.new
|
||||
|
||||
opts = OptionParser.new do |opts|
|
||||
opts.banner = "Usage: qwandry [options] name"
|
||||
opts.separator ""
|
||||
|
||||
opts.on("-r", "--repo LABELS", Array, "Search in LABELS, default: #{@qwandry.active.to_a.join(',')}","Available Repositories:", *@qwandry.repositories.keys.map{|k| " #{k}"}) do |labels|
|
||||
@qwandry.active.replace(labels)
|
||||
opts.on("-r", "--repo LABELS", Array, "Search in LABELS, default: #{config.default.join(',')}","Available Repository Types:", *config.configurations.map{|c| " #{c}"}) do |names|
|
||||
config.default *names
|
||||
end
|
||||
|
||||
opts.separator ""
|
||||
opts.on("-e", "--editor EDITOR", "Use EDITOR to open the package") do |editor|
|
||||
@editor = editor
|
||||
@launcher.editor = editor
|
||||
end
|
||||
|
||||
opts.separator "Additional Commands"
|
||||
|
||||
opts.on("--paths", "Prints all repositories and their paths") do
|
||||
@qwandry.repositories.each do |label, entries|
|
||||
puts "#{label} #{"[default]" if @qwandry.active.include? label}"
|
||||
entries.each do |repo|
|
||||
puts "\t#{repo.path} (#{repo.class.to_s.split('::').last})"
|
||||
end
|
||||
puts ""
|
||||
end
|
||||
exit(0)
|
||||
end
|
||||
|
||||
opts.on("--customize", "Create and edit files for customizing Qwandry") do
|
||||
dir = Qwandry.config_dir
|
||||
if !dir
|
||||
@ -43,7 +38,7 @@ opts = OptionParser.new do |opts|
|
||||
Dir[File.dirname(__FILE__) + '/../templates/*'].each do |path|
|
||||
FileUtils.cp(path, dir, :verbose=>true) unless File.exist?(path)
|
||||
end
|
||||
@qwandry.launch dir
|
||||
@launcher.launch dir
|
||||
end
|
||||
exit(0)
|
||||
end
|
||||
@ -60,13 +55,13 @@ if ARGV.length == 0
|
||||
exit 1
|
||||
end
|
||||
|
||||
# Configure default values
|
||||
@qwandry.editor = @editor if @editor
|
||||
|
||||
# Find the packages:
|
||||
name = ARGV.join(' ')
|
||||
packages = @qwandry.find(*ARGV)
|
||||
packages = @launcher.find(*ARGV)
|
||||
ARGV.clear # for the gets below
|
||||
|
||||
# There may be 0, 1, or many matches. If many, then
|
||||
# ask the user which one to launch.
|
||||
package = nil
|
||||
case packages.length
|
||||
when 0
|
||||
@ -84,8 +79,9 @@ else
|
||||
package = packages[index]
|
||||
end
|
||||
|
||||
# If there is a package, then launch it.
|
||||
if package
|
||||
if @qwandry.launch(package)
|
||||
if @launcher.launch(package)
|
||||
# Exit code 0 for success
|
||||
exit 0
|
||||
else
|
||||
|
@ -21,6 +21,7 @@ module Qwandry
|
||||
autoload :FlatRepository, "qwandry/flat_repository"
|
||||
autoload :LibraryRepository, "qwandry/library_repository"
|
||||
autoload :Package, "qwandry/package"
|
||||
autoload :Configuration, "qwandry/configuration"
|
||||
end
|
||||
|
||||
# If defined, Qwandry will use XDG_CONFIG_HOME as the xdg spec. If not it
|
||||
|
135
lib/qwandry/configuration.rb
Normal file
135
lib/qwandry/configuration.rb
Normal file
@ -0,0 +1,135 @@
|
||||
module Qwandry
|
||||
class Configuration
|
||||
class << self
|
||||
# Regsisters a new Qwandry configuration. Use in conjunction with Configuration#add like so:
|
||||
#
|
||||
# register 'projects' do
|
||||
# add '~/Projects/personal'
|
||||
# add '~/Projects/work'
|
||||
# add '~/Experiments'
|
||||
# end
|
||||
#
|
||||
def register name, &block
|
||||
name = name.to_sym
|
||||
builders[name] << block
|
||||
end
|
||||
|
||||
# Sets the default configuration to launch, if no `configurations` are passed
|
||||
# in, it returns their names.
|
||||
def default(*configurations)
|
||||
if configurations.empty?
|
||||
@default ||= []
|
||||
else
|
||||
@default = configurations
|
||||
end
|
||||
end
|
||||
|
||||
# Returns the registered configurations
|
||||
def configurations
|
||||
builders.keys
|
||||
end
|
||||
|
||||
# Loads a configuration file, and executes it in the context of the Qwandry::Configuration
|
||||
# class. See default_configuration.rb for an example, or run:
|
||||
#
|
||||
# qw --customize
|
||||
#
|
||||
# For a sample customization file.
|
||||
def load_configuration(path)
|
||||
if File.exist?(path)
|
||||
begin
|
||||
eval IO.read(path), nil, path, 1
|
||||
rescue Exception=>ex
|
||||
STDERR.puts "Warning: error in configuration file: #{path.inspect}"
|
||||
STDERR.puts "Exception: #{ex.message}"
|
||||
STDERR.puts ex.backtrace
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Loads the Qwandry default configuration and then the user's custom
|
||||
# configuration file if it is present.
|
||||
def load_configuration_files
|
||||
# load default configuration files
|
||||
system_config_dir = File.join(File.dirname(__FILE__), 'configuration')
|
||||
Dir[system_config_dir+"/*.rb"].each do |path|
|
||||
load_configuration path
|
||||
end
|
||||
|
||||
# load user custom init files
|
||||
if config_dir = Qwandry.config_dir
|
||||
custom_path = File.join(config_dir, 'init.rb')
|
||||
load_configuration(custom_path)
|
||||
end
|
||||
end
|
||||
|
||||
# Loads the repositories for `names` if no names are given, it loads the defaults
|
||||
def repositories(*names)
|
||||
names = default if names.empty?
|
||||
repositories = []
|
||||
|
||||
names.each do |name|
|
||||
name = name.to_sym
|
||||
raise ArgumentError, "Unknown Repository type '#{name}'" unless builders.has_key? name
|
||||
|
||||
builder = builders[name]
|
||||
repositories += builder.repositories
|
||||
end
|
||||
|
||||
repositories
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def builders
|
||||
@builders ||= Hash.new{|h,name| h[name] = self.new(name) }
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# Creates a new Configuration for building a set of Repositories, this
|
||||
# should probably only be invoked by Configuration.build, it only exists
|
||||
# to make the customization DSL relatively easy to work with.
|
||||
def initialize(name)
|
||||
@name = name
|
||||
@blocks = []
|
||||
@repositories = []
|
||||
end
|
||||
|
||||
def << (block)
|
||||
@blocks << block
|
||||
end
|
||||
|
||||
def repositories
|
||||
@blocks.each{|block| instance_eval(&block) }
|
||||
@blocks.clear
|
||||
|
||||
@repositories
|
||||
end
|
||||
|
||||
# Adds a new Repository to the current configuration.
|
||||
#
|
||||
# The `options` can be used to customize the repository.
|
||||
#
|
||||
# [:class] Repository class, defaults to Qwandry::FlatRepository
|
||||
# [:accept] Filters paths, only keeping ones matching the accept option
|
||||
# [:reject] Filters paths, rejecting any paths matching the reject option
|
||||
#
|
||||
# `:accept` and `:reject` take patterns such as '*.py[oc]', procs, and regular expressions.
|
||||
#
|
||||
# Examples:
|
||||
# # Add all my little ruby scripts in the scratch directory
|
||||
# add '~/scratch', :accept => '*.rb'
|
||||
# # Add log files in common locations for easy access, but ignore the zipped ones
|
||||
# add ['/var/log/', '/usr/local/var/log/'], :reject => '*.bz2'
|
||||
#
|
||||
def add(paths, options={})
|
||||
paths = [paths] if paths.is_a?(String)
|
||||
paths.each do |path|
|
||||
repository_class = options[:class] || Qwandry::FlatRepository
|
||||
@repositories << repository_class.new(@name, File.expand_path(path), options)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
46
lib/qwandry/configuration/default.rb
Normal file
46
lib/qwandry/configuration/default.rb
Normal file
@ -0,0 +1,46 @@
|
||||
|
||||
# Register the default ruby configuration:
|
||||
register :ruby do
|
||||
# Reject binary paths, and then find only the `/lib/ruby` sources:
|
||||
paths = ($:).reject{|path| path =~ /#{RUBY_PLATFORM}$/}.grep(/lib\/ruby/)
|
||||
|
||||
# Add ruby standard libraries using the LibraryRepository:
|
||||
add paths, :class=>Qwandry::LibraryRepository
|
||||
end
|
||||
|
||||
# Register the default ruby gems configuration:
|
||||
register :gem do
|
||||
# Get the gem paths from the ruby load paths:
|
||||
paths = ($:).grep(/gems/).map{|p| p[/.+\/gems\//]}.uniq
|
||||
|
||||
# Add all the rubygems' paths:
|
||||
add paths
|
||||
end
|
||||
|
||||
# Register a perl configuration:
|
||||
register :perl do
|
||||
# Execute a perl script to find all of the perl load paths:
|
||||
perl_paths = `perl -e 'foreach $k (@INC){print $k,"\n";}'` rescue ''
|
||||
|
||||
# Split on new lines, rejecting blank paths and the current directory:
|
||||
perl_paths = perl_paths.split("\n").reject{|path| path == '' || path == '.'}
|
||||
|
||||
# Add perl paths as a LibraryRepository
|
||||
add perl_paths, :class=>Qwandry::LibraryRepository
|
||||
end
|
||||
|
||||
# Add python repositories:
|
||||
register :python do
|
||||
# Execute a python script to find all of the python load paths:
|
||||
python_paths = `python -c 'import sys;print(\"\\n\".join(sys.path))'` rescue ''
|
||||
|
||||
# Reject all the blank paths and the current directory. Also reject anything that looks like a binary
|
||||
python_paths = python_paths.split("\n").reject{|path| path == '' || path == '.' || path =~ /\.zip$/ || path =~/lib-dynload$/}
|
||||
|
||||
# Add the python paths, instruct Qwandry to skip any compiled files when trying to match a file/library:
|
||||
add python_paths, :class=>Qwandry::LibraryRepository, :reject => /\.(py[oc])|(egg-info)$/
|
||||
end
|
||||
|
||||
# Qwandry is a ruby app after all, so activate ruby and gem by default. Other defaults can be set
|
||||
# with a custom init.rb
|
||||
default :ruby, :gem
|
@ -5,57 +5,19 @@ module Qwandry
|
||||
# The default editor to be used by Qwandry#launch.
|
||||
attr_accessor :editor
|
||||
|
||||
# The set of active repositories
|
||||
attr_reader :active
|
||||
|
||||
# Returns the repositories the Launcher will use.
|
||||
attr_reader :repositories
|
||||
|
||||
def initialize
|
||||
@repositories = Hash.new{|h,k| h[k] = []}
|
||||
@active = Set.new
|
||||
configure_repositories!
|
||||
custom_configuration!
|
||||
end
|
||||
|
||||
# Adds a repository path to Qwandry's Launcher. `label` is used to label packages residing in the folder `path`.
|
||||
#
|
||||
# The `options` can be used to customize the repository.
|
||||
#
|
||||
# [:class] Repository class, defaults to Qwandry::FlatRepository
|
||||
# [:accept] Filters paths, only keeping ones matching the accept option
|
||||
# [:reject] Filters paths, rejecting any paths matching the reject option
|
||||
#
|
||||
# `:accept` and `:reject` take patterns such as '*.py[oc]', procs, and regular expressions.
|
||||
def add(label, path, options={})
|
||||
if path.is_a?(Array)
|
||||
path.each{|p| add label, p, options}
|
||||
else
|
||||
repository_class = options[:class] || Qwandry::FlatRepository
|
||||
label = label.to_s
|
||||
@repositories[label] << repository_class.new(label, File.expand_path(path), options)
|
||||
end
|
||||
end
|
||||
|
||||
def activate(*labels)
|
||||
labels.each{|label| @active.add label.to_s}
|
||||
end
|
||||
|
||||
def deactivate(*labels)
|
||||
labels.each{|label| @active.delete label.to_s}
|
||||
end
|
||||
|
||||
# Searches all of the loaded repositories for `name`
|
||||
def find(*pattern)
|
||||
# Create a glob pattern from the user's input, for instance
|
||||
# ["rails","2.3"] => "rails*2.3*"
|
||||
pattern = pattern.join('*')
|
||||
pattern << '*' unless pattern =~ /\*$/
|
||||
|
||||
packages = []
|
||||
@repositories.select{|label,_| @active.include? label }.each do |label, repos|
|
||||
repos.each do |repo|
|
||||
packages.concat(repo.scan(pattern))
|
||||
end
|
||||
repositories = Qwandry::Configuration.repositories
|
||||
repositories.each do |repo|
|
||||
packages.concat(repo.scan(pattern))
|
||||
end
|
||||
|
||||
packages
|
||||
end
|
||||
|
||||
@ -76,56 +38,6 @@ module Qwandry
|
||||
# Launch the editor with its options and any paths that we have been passed
|
||||
system(*(editor_and_options + paths))
|
||||
end
|
||||
|
||||
private
|
||||
def configure_repositories!
|
||||
# Get all the paths on ruby's load path:
|
||||
paths = $:
|
||||
|
||||
# Reject binary paths, we only want ruby sources:
|
||||
paths = paths.reject{|path| path =~ /#{RUBY_PLATFORM}$/}
|
||||
|
||||
# Add ruby standard libraries:
|
||||
paths.grep(/lib\/ruby/).each do |path|
|
||||
add :ruby, path, :class=>Qwandry::LibraryRepository
|
||||
end
|
||||
|
||||
# Add gem repositories:
|
||||
($:).grep(/gems/).map{|p| p[/.+\/gems\//]}.uniq.each do |path|
|
||||
add :gem, path
|
||||
end
|
||||
|
||||
# Add perl repositories:
|
||||
perl_paths = `perl -e 'foreach $k (@INC){print $k,"\n";}'` rescue ''
|
||||
perl_paths.split("\n").reject{|path| path == '' || path == '.'}.each do |path|
|
||||
add :perl, path, :class=>Qwandry::LibraryRepository
|
||||
end
|
||||
|
||||
# add python repositories:
|
||||
python_paths = `python -c 'import sys;print(\"\\n\".join(sys.path))'` rescue ''
|
||||
python_paths.split("\n").reject{|path| path == '' || path == '.' || path =~ /\.zip$/ || path =~/lib-dynload$/}.each do |path|
|
||||
add :python, path, :class=>Qwandry::LibraryRepository, :reject => /\.(py[oc])|(egg-info)$/
|
||||
end
|
||||
|
||||
# Qwandry is a ruby app after all, so activate ruby and rubygems by default. Other defaults can be set
|
||||
# with a custom init.rb
|
||||
activate :ruby, :gem
|
||||
end
|
||||
|
||||
def custom_configuration!
|
||||
if config_dir = Qwandry.config_dir
|
||||
custom_path = File.join(config_dir, 'init.rb')
|
||||
if File.exist?(custom_path)
|
||||
begin
|
||||
eval IO.read(custom_path), nil, custom_path, 1
|
||||
rescue Exception=>ex
|
||||
STDERR.puts "Warning: error in custom file: #{custom_path.inspect}"
|
||||
STDERR.puts "Exception: #{ex.message}"
|
||||
STDERR.puts ex.backtrace
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user