warp-dir 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.atom-build.json +22 -0
- data/.codeclimate.yml +22 -0
- data/.gitignore +40 -0
- data/.idea/encodings.xml +6 -0
- data/.idea/misc.xml +14 -0
- data/.idea/modules.xml +8 -0
- data/.idea/runConfigurations/All_Specs.xml +33 -0
- data/.idea/vcs.xml +6 -0
- data/.idea/warp-dir.iml +224 -0
- data/.rspec +4 -0
- data/.rubocop.yml +1156 -0
- data/.travis.yml +13 -0
- data/Gemfile +4 -0
- data/Guardfile +14 -0
- data/LICENSE +22 -0
- data/README.md +114 -0
- data/ROADMAP.md +96 -0
- data/Rakefile +24 -0
- data/bin/console +11 -0
- data/bin/setup +8 -0
- data/bin/warp-dir +13 -0
- data/bin/warp-dir.bash +25 -0
- data/lib/warp.rb +4 -0
- data/lib/warp/dir.rb +65 -0
- data/lib/warp/dir/app/cli.rb +162 -0
- data/lib/warp/dir/app/response.rb +133 -0
- data/lib/warp/dir/command.rb +120 -0
- data/lib/warp/dir/command/add.rb +16 -0
- data/lib/warp/dir/command/help.rb +80 -0
- data/lib/warp/dir/command/install.rb +78 -0
- data/lib/warp/dir/command/list.rb +13 -0
- data/lib/warp/dir/command/ls.rb +31 -0
- data/lib/warp/dir/command/remove.rb +16 -0
- data/lib/warp/dir/command/warp.rb +24 -0
- data/lib/warp/dir/commander.rb +71 -0
- data/lib/warp/dir/config.rb +87 -0
- data/lib/warp/dir/errors.rb +60 -0
- data/lib/warp/dir/formatter.rb +77 -0
- data/lib/warp/dir/point.rb +53 -0
- data/lib/warp/dir/serializer.rb +14 -0
- data/lib/warp/dir/serializer/base.rb +43 -0
- data/lib/warp/dir/serializer/dotfile.rb +36 -0
- data/lib/warp/dir/store.rb +129 -0
- data/lib/warp/dir/version.rb +6 -0
- data/spec/fixtures/warprc +2 -0
- data/spec/spec_helper.rb +71 -0
- data/spec/support/cli_expectations.rb +118 -0
- data/spec/warp/dir/app/cli_spec.rb +225 -0
- data/spec/warp/dir/app/response_spec.rb +131 -0
- data/spec/warp/dir/command_spec.rb +62 -0
- data/spec/warp/dir/commands/add_spec.rb +40 -0
- data/spec/warp/dir/commands/install_spec.rb +20 -0
- data/spec/warp/dir/commands/list_spec.rb +37 -0
- data/spec/warp/dir/config_spec.rb +45 -0
- data/spec/warp/dir/errors_spec.rb +16 -0
- data/spec/warp/dir/formatter_spec.rb +38 -0
- data/spec/warp/dir/point_spec.rb +35 -0
- data/spec/warp/dir/store_spec.rb +105 -0
- data/warp-dir.gemspec +56 -0
- metadata +228 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
require 'warp/dir/command'
|
|
2
|
+
module Warp
|
|
3
|
+
module Dir
|
|
4
|
+
class Command
|
|
5
|
+
class LS < Warp::Dir::Command
|
|
6
|
+
description %q(List directory contents of a Warp Point)
|
|
7
|
+
needs_a_point? true
|
|
8
|
+
aliases :dir
|
|
9
|
+
|
|
10
|
+
# @param [Object] args
|
|
11
|
+
def run(opts, *flags)
|
|
12
|
+
point = store.find_point(point_name)
|
|
13
|
+
STDERR.puts "FLAGS: [#{flags}]".bold.green if config.debug
|
|
14
|
+
|
|
15
|
+
command_flags = if flags && !flags.empty?
|
|
16
|
+
flags
|
|
17
|
+
else
|
|
18
|
+
['-al']
|
|
19
|
+
end
|
|
20
|
+
command = "ls #{command_flags.join(' ')} #{point.path}/"
|
|
21
|
+
STDERR.puts 'Command: '.yellow + command.bold.green if config.debug
|
|
22
|
+
ls_output = `#{command}`
|
|
23
|
+
STDERR.puts 'Output: '.yellow + ls_output.bold.blue if config.debug
|
|
24
|
+
on :success do
|
|
25
|
+
message ls_output.bold
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
require 'warp/dir/command'
|
|
2
|
+
class Warp::Dir::Command
|
|
3
|
+
class Remove < Warp::Dir::Command
|
|
4
|
+
description %q(Removes a given warp point from the database)
|
|
5
|
+
needs_a_point? true
|
|
6
|
+
aliases :rm, :delete
|
|
7
|
+
|
|
8
|
+
def run(*args)
|
|
9
|
+
point_name = self.point_name
|
|
10
|
+
store.remove point_name: point_name
|
|
11
|
+
on :success do
|
|
12
|
+
message "Warp point #{point_name.to_s.yellow} has been removed."
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
require 'warp/dir/command'
|
|
2
|
+
|
|
3
|
+
require 'colored'
|
|
4
|
+
module Warp
|
|
5
|
+
module Dir
|
|
6
|
+
class Command
|
|
7
|
+
class Warp < Warp::Dir::Command
|
|
8
|
+
description %q(Jumps to the pre-defined warp point (command optional))
|
|
9
|
+
needs_a_point? true
|
|
10
|
+
|
|
11
|
+
def run(*args)
|
|
12
|
+
if point.nil? && point_name
|
|
13
|
+
self.point = store[point_name]
|
|
14
|
+
end
|
|
15
|
+
raise ::Warp::Dir::Errors::PointNotFound.new(point) unless point
|
|
16
|
+
p = point
|
|
17
|
+
on :shell do
|
|
18
|
+
message "cd #{p.absolute_path}"
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
require 'set'
|
|
2
|
+
require 'warp/dir/errors'
|
|
3
|
+
require 'warp/dir/formatter'
|
|
4
|
+
require 'singleton'
|
|
5
|
+
module Warp
|
|
6
|
+
module Dir
|
|
7
|
+
class Commander
|
|
8
|
+
include Singleton
|
|
9
|
+
|
|
10
|
+
attr_reader :commands
|
|
11
|
+
attr_accessor :command_map
|
|
12
|
+
|
|
13
|
+
def initialize
|
|
14
|
+
@commands ||= Set.new # a pre-caution, normally it would already by defined by now
|
|
15
|
+
@command_map = {}
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def register(command)
|
|
19
|
+
@commands << command if command
|
|
20
|
+
self
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def installed_commands
|
|
24
|
+
@commands.map(&:command_name)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def lookup(command_name)
|
|
28
|
+
reindex!
|
|
29
|
+
command_map[command_name]
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def find(command_name)
|
|
33
|
+
command = lookup(command_name)
|
|
34
|
+
if command.nil?
|
|
35
|
+
raise ::Warp::Dir::Errors::InvalidCommand.new(command_name)
|
|
36
|
+
end
|
|
37
|
+
command
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def run(command_name, *args)
|
|
41
|
+
cmd = find command_name
|
|
42
|
+
raise ::Warp::Dir::Errors::InvalidCommand.new(command_name) unless cmd.is_a?(warp::Dir::Command)
|
|
43
|
+
cmd.new(*args).run
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def reindex!
|
|
47
|
+
commands.each do |command|
|
|
48
|
+
if command.respond_to?(:aliases)
|
|
49
|
+
command.aliases.each do |an_alias|
|
|
50
|
+
if self.command_map[an_alias] && !self.command_map[an_alias] == command
|
|
51
|
+
raise Warp::Dir::Errors::InvalidCommand.new("Duplicate alias for command #{command}")
|
|
52
|
+
end
|
|
53
|
+
self.command_map[an_alias] = command
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
self.command_map[command.command_name] = command
|
|
57
|
+
end
|
|
58
|
+
self
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def validate!
|
|
62
|
+
self.commands.delete_if do |subclass|
|
|
63
|
+
if !subclass.respond_to?(:abstract_class?) && !subclass.method_defined?(:run)
|
|
64
|
+
raise ::Warp::Dir::Errors::InvalidCommand.new(subclass)
|
|
65
|
+
end
|
|
66
|
+
subclass.respond_to?(:abstract_class?) || !subclass.method_defined?(:run)
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
require 'forwardable'
|
|
2
|
+
|
|
3
|
+
module Warp
|
|
4
|
+
module Dir
|
|
5
|
+
class Config
|
|
6
|
+
|
|
7
|
+
DEFAULTS = {
|
|
8
|
+
warprc: ENV['HOME'] + '/.warprc',
|
|
9
|
+
shell: false,
|
|
10
|
+
force: false,
|
|
11
|
+
debug: false
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
attr_accessor :variables
|
|
15
|
+
|
|
16
|
+
extend ::Forwardable
|
|
17
|
+
def_delegators :@variables, :size, :<<, :map, :each
|
|
18
|
+
def initialize(opts = {})
|
|
19
|
+
configure(opts)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def configure(opts = {})
|
|
23
|
+
options = DEFAULTS.merge(opts)
|
|
24
|
+
|
|
25
|
+
# Move :config hash key->value to :warprc that is expected by the Config
|
|
26
|
+
if options[:config]
|
|
27
|
+
options[:warprc] = options[:config]
|
|
28
|
+
options.delete(:config)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
self.variables = []
|
|
32
|
+
|
|
33
|
+
# OK. I concede. This is very likely a total overkill :O
|
|
34
|
+
# The thing is: I just really like calling hash members via
|
|
35
|
+
# methods, and I didn't want to load HashieMash because
|
|
36
|
+
# it's big. Real big.
|
|
37
|
+
#
|
|
38
|
+
# IRB Session that explains it all:
|
|
39
|
+
#
|
|
40
|
+
# c = Config.new({ foo: "bar", bar: "foo"})
|
|
41
|
+
# => #<Warp::Dir::Config:0x007ff8e39531f0 @variables=[:config, :foo, :bar], @config="/Users/kigster/.warprc", @foo="bar", @bar="foo">
|
|
42
|
+
# > c.foo # => "bar"
|
|
43
|
+
# > c.bar # => "foo"
|
|
44
|
+
# > c.bar? # => true
|
|
45
|
+
# > c.config # => "/Users/kigster/.warprc"
|
|
46
|
+
# > c.color = "red" # => "red"
|
|
47
|
+
# > c.color # => "red"
|
|
48
|
+
# > c.color? # => true
|
|
49
|
+
|
|
50
|
+
options.each_pair do |variable_name, value|
|
|
51
|
+
self.variables << add_config_variable(variable_name, value)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# allow syntax @config[:warprc]
|
|
56
|
+
def [](key)
|
|
57
|
+
self.send(key)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Dispatches redis operations to master/slaves.
|
|
61
|
+
def method_missing(method, *args, &block)
|
|
62
|
+
if method =~ /=$/
|
|
63
|
+
add_config_variable(method.to_s.gsub(/=$/, ''), *args)
|
|
64
|
+
else
|
|
65
|
+
super
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
private
|
|
70
|
+
|
|
71
|
+
def add_config_variable(variable_name, value)
|
|
72
|
+
reader = variable_name.to_sym
|
|
73
|
+
writer = "#{reader}=".to_sym
|
|
74
|
+
boolean = "#{reader}?"
|
|
75
|
+
variable = "@#{reader}".to_sym
|
|
76
|
+
# set this value on the the instance of config class
|
|
77
|
+
instance_variable_set(variable, value)
|
|
78
|
+
# add the reader and the writer to this key
|
|
79
|
+
define_singleton_method(reader) { instance_variable_get(variable) }
|
|
80
|
+
define_singleton_method(writer) { |new_value| instance_variable_set(variable, new_value) }
|
|
81
|
+
define_singleton_method(boolean){ !instance_variable_get(variable).nil? }
|
|
82
|
+
reader
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
module Warp
|
|
2
|
+
module Dir
|
|
3
|
+
module Errors
|
|
4
|
+
class Runtime < RuntimeError;
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
class StoreFormatError < Warp::Dir::Errors::Runtime
|
|
8
|
+
attr_reader :line
|
|
9
|
+
def initialize(msg, line)
|
|
10
|
+
@line = line
|
|
11
|
+
super msg
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
class StoreUninitialized < Warp::Dir::Errors::Runtime; end
|
|
16
|
+
class StoreAlreadyInitialized < Warp::Dir::Errors::Runtime; end
|
|
17
|
+
|
|
18
|
+
# This is a generic Exception that wraps an object passed to the
|
|
19
|
+
# initializer and assumed to be the reason for the failure.
|
|
20
|
+
# Message is optional, but each concrete exception should provide
|
|
21
|
+
# it's own concrete message
|
|
22
|
+
class InstanceError < Warp::Dir::Errors::Runtime
|
|
23
|
+
attr_accessor :instance
|
|
24
|
+
def initialize(message = nil)
|
|
25
|
+
super message ? message : "#{self.class.name}->[#{instance}]"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def name
|
|
29
|
+
super.gsub(%r{#{self.class.name}}, '')
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def color_error instance_type, instance, result
|
|
33
|
+
instance_type.red.bold +
|
|
34
|
+
instance.to_s.yellow.bold +
|
|
35
|
+
result.red.bold
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
class InvalidCommand < ::Warp::Dir::Errors::InstanceError
|
|
40
|
+
def initialize(instance = nil)
|
|
41
|
+
self.instance = instance
|
|
42
|
+
super instance.is_a?(Symbol) ? color_error('Command ', instance, ' is invalid.') : instance
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
class PointNotFound < ::Warp::Dir::Errors::InstanceError
|
|
47
|
+
def initialize(point)
|
|
48
|
+
self.instance = point
|
|
49
|
+
super color_error('Point ', point.to_s, ' was not found.')
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
class PointAlreadyExists < ::Warp::Dir::Errors::InstanceError
|
|
53
|
+
def initialize(point)
|
|
54
|
+
self.instance = point
|
|
55
|
+
super color_error('Point ', point.to_s, ' already exists. Pass --force to overwrite.')
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
require 'warp/dir'
|
|
2
|
+
require 'warp/dir/errors'
|
|
3
|
+
require 'colored'
|
|
4
|
+
require 'thread'
|
|
5
|
+
module Warp
|
|
6
|
+
module Dir
|
|
7
|
+
class Formatter
|
|
8
|
+
DEFAULT_FORMAT = :ascii
|
|
9
|
+
|
|
10
|
+
attr_accessor :store
|
|
11
|
+
|
|
12
|
+
def initialize(store)
|
|
13
|
+
@store = store
|
|
14
|
+
@config = store.config
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def unhappy(exception: nil, message: nil)
|
|
18
|
+
out = 'Whoops! – '.white
|
|
19
|
+
out << "#{exception.message} ".red if exception && !message
|
|
20
|
+
out << "#{message} ".red if !exception && message
|
|
21
|
+
out << "#{exception.message}:\n#{message}".red if message && exception
|
|
22
|
+
out << "\n"
|
|
23
|
+
print ? STDERR.printf(out) : out
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def format_point(point, *args)
|
|
27
|
+
PointFormatter.new(point).format(*args)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def format_store(*args)
|
|
31
|
+
StoreFormatter.new(store).format(*args)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def happy(message: nil)
|
|
35
|
+
STDOUT.printf(message.blue.bold)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
class PointFormatter
|
|
41
|
+
attr_accessor :point
|
|
42
|
+
|
|
43
|
+
def initialize(point)
|
|
44
|
+
@point = point
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def format(type = DEFAULT_FORMAT, width = 0)
|
|
48
|
+
case type
|
|
49
|
+
when :ascii
|
|
50
|
+
point.to_s(width)
|
|
51
|
+
else
|
|
52
|
+
raise ArgumentError.new("Type #{type} is not recognized.")
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
class StoreFormatter
|
|
58
|
+
attr_accessor :store
|
|
59
|
+
|
|
60
|
+
def initialize(store)
|
|
61
|
+
@store = store
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# find the widest warp point name, and indent them all based on that.
|
|
65
|
+
# make it easy to extend to other types, and allow the caller to
|
|
66
|
+
# sort by one of the fields.
|
|
67
|
+
def format(type = DEFAULT_FORMAT, sort_field = :name)
|
|
68
|
+
longest_key_length = store.points.map(&:name).map(&:length).sort.last
|
|
69
|
+
Warp::Dir.sort_by(store.points, sort_field).map do |point|
|
|
70
|
+
PointFormatter.new(point).format(type, longest_key_length)
|
|
71
|
+
end.join("\n")
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
require 'forwardable'
|
|
2
|
+
require 'digest'
|
|
3
|
+
module Warp
|
|
4
|
+
module Dir
|
|
5
|
+
class Point
|
|
6
|
+
attr_accessor :full_path, :name
|
|
7
|
+
|
|
8
|
+
def initialize(name, full_path)
|
|
9
|
+
raise ArgumentError.new ':name is required' if name.nil?
|
|
10
|
+
raise ArgumentError.new ':full_path is required' if full_path.nil?
|
|
11
|
+
@full_path = Warp::Dir.absolute full_path
|
|
12
|
+
@name = name.to_sym
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def absolute_path
|
|
16
|
+
full_path
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def relative_path
|
|
20
|
+
Warp::Dir.relative full_path
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def path
|
|
24
|
+
absolute_path
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def inspect
|
|
28
|
+
sprintf("(#{object_id})[name: '%s', path: '%s']", name, relative_path)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def to_s(width = 0)
|
|
32
|
+
sprintf("%#{width}s -> %s", name, relative_path)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def hash
|
|
36
|
+
Digest::SHA1.base64digest("#{full_path.hash}#{name.hash}").hash
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def <=>(other)
|
|
40
|
+
name <=> other.name
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def eql?(another)
|
|
44
|
+
return false unless another.is_a?(Warp::Dir::Point)
|
|
45
|
+
%i(name full_path).each do |attribute|
|
|
46
|
+
return false unless send(attribute) == another.send(attribute)
|
|
47
|
+
end
|
|
48
|
+
true
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
module Warp
|
|
2
|
+
module Dir
|
|
3
|
+
SERIALIZERS = {}
|
|
4
|
+
module Serializer
|
|
5
|
+
def self.default
|
|
6
|
+
SERIALIZERS.values.first
|
|
7
|
+
end
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
Warp::Dir.require_all_from '/dir/serializer'
|
|
13
|
+
|
|
14
|
+
raise 'No concrete serializer implementations were found' if Warp::Dir::SERIALIZERS.empty?
|