tap_dance 0.0.1

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.
@@ -0,0 +1,36 @@
1
+ require 'tap_dance/ui'
2
+ require 'tap_dance/brew_cli'
3
+
4
+ module TapDance
5
+ class Tap
6
+ attr_accessor :name
7
+ attr_accessor :url
8
+
9
+ def initialize(name, url, opts={})
10
+ @name = name.to_sym
11
+ @url = url.to_s
12
+ @opts = opts
13
+ end
14
+
15
+ def entap
16
+ BrewCLI.tap(@url)
17
+ end
18
+
19
+ def untap
20
+ BrewCLI.untap(@url)
21
+ end
22
+
23
+ def tapped?
24
+ BrewCLI.tap_list.out.each_line { |t|
25
+ return true if @url == t.strip
26
+ }
27
+
28
+ return false
29
+ end
30
+
31
+ def to_s
32
+ "#{@name}:#{@url}"
33
+ end
34
+
35
+ end
36
+ end
@@ -0,0 +1,159 @@
1
+ require 'rubygems/user_interaction'
2
+
3
+ module TapDance
4
+ class UI
5
+ attr_reader :log
6
+
7
+ def warn(message, newline = nil)
8
+ end
9
+
10
+ def debug(message, newline = nil)
11
+ end
12
+
13
+ def trace(message, newline = nil)
14
+ end
15
+
16
+ def error(message, newline = nil)
17
+ end
18
+
19
+ def info(message, newline = nil)
20
+ end
21
+
22
+ def confirm(message, newline = nil)
23
+ end
24
+
25
+ def detail(message, newline = nil)
26
+ end
27
+
28
+ def debug?
29
+ false
30
+ end
31
+
32
+ def ask(message)
33
+ end
34
+
35
+ class Shell < UI
36
+ LEVELS = %w(silent error warn detail confirm info debug)
37
+
38
+ attr_writer :shell
39
+
40
+ def initialize(options = {})
41
+ if options["no-color"] || !STDOUT.tty?
42
+ Thor::Base.shell = Thor::Shell::Basic
43
+ end
44
+ @shell = Thor::Base.shell.new
45
+ @level = ENV['DEBUG'] ? "debug" : "info"
46
+ end
47
+
48
+ def info(msg, newline = nil)
49
+ tell_me(msg, nil, newline) if level("info")
50
+ end
51
+
52
+ def confirm(msg, newline = nil)
53
+ tell_me(msg, :green, newline) if level("confirm")
54
+ end
55
+
56
+ def detail(msg, newline = nil)
57
+ tell_me(msg, :cyan, newline) if level("detail")
58
+ end
59
+
60
+ def warn(msg, newline = nil)
61
+ tell_me(msg, :yellow, newline) if level("warn")
62
+ end
63
+
64
+ def error(msg, newline = nil)
65
+ tell_me(msg, :red, newline) if level("error")
66
+ end
67
+
68
+ def debug(msg, newline = nil)
69
+ tell_me(msg, nil, newline) if level("debug")
70
+ end
71
+
72
+ def debug?
73
+ # needs to be false instead of nil to be newline param to other methods
74
+ level("debug")
75
+ end
76
+
77
+ def quiet?
78
+ LEVELS.index(@level) <= LEVELS.index("warn")
79
+ end
80
+
81
+ def ask(msg)
82
+ @shell.ask(msg)
83
+ end
84
+
85
+ def level=(level)
86
+ raise ArgumentError unless LEVELS.include?(level.to_s)
87
+ @level = level
88
+ end
89
+
90
+ def level(name = nil)
91
+ name ? LEVELS.index(name) <= LEVELS.index(@level) : @level
92
+ end
93
+
94
+ def trace(e, newline = nil)
95
+ msg = ["#{e.class}: #{e.message}", *e.backtrace].join("\n")
96
+ if debug?
97
+ tell_me(msg, nil, newline)
98
+ elsif @trace
99
+ STDERR.puts "#{msg}#{newline}"
100
+ end
101
+ end
102
+
103
+ def silence
104
+ old_level, @level = @level, "silent"
105
+ yield
106
+ ensure
107
+ @level = old_level
108
+ end
109
+
110
+ private
111
+
112
+ def tell_me(msg, color = nil, newline = nil)
113
+ return if (msg.nil? || msg == "") && newline.nil?
114
+ msg = word_wrap(msg) if newline.is_a?(Hash) && newline[:wrap]
115
+ line = if newline.nil? then [] else [newline] end
116
+
117
+ if msg.is_a? ShellResult
118
+ unless msg.out.chomp == ""
119
+ @shell.say(msg.out.chomp, color, *line)
120
+ logger(msg.out.chomp, *line)
121
+ end
122
+
123
+ unless msg.err.chomp == ""
124
+ @shell.say(msg.err.chomp, :red)
125
+ logger(msg.err.chomp)
126
+ end
127
+ else
128
+ @shell.say(msg, color, *line)
129
+ logger(msg, *line)
130
+ end
131
+ end
132
+
133
+ def logger(message, newline=(message.to_s !~ /( |\t)$/))
134
+ @log ||= ""
135
+ @log << message
136
+ @log << $/ if newline
137
+ end
138
+
139
+ def word_wrap(text, line_width = @shell.terminal_width)
140
+ text.split("\n").collect do |line|
141
+ line.length > line_width ? line.gsub(/(.{1,#{line_width}})(\s+|$)/, "\\1\n").strip : line
142
+ end * "\n"
143
+ end
144
+ end
145
+
146
+ class Logger < Shell
147
+
148
+ private
149
+
150
+ def tell_me(msg, color = nil, newline = nil)
151
+ if newline.nil?
152
+ logger(msg)
153
+ else
154
+ logger(msg, newline)
155
+ end
156
+ end
157
+ end
158
+ end
159
+ end
@@ -0,0 +1,3 @@
1
+ module TapDance
2
+ VERSION = "0.0.1"
3
+ end
data/lib/tap_dance.rb ADDED
@@ -0,0 +1,21 @@
1
+ require 'tap_dance/version'
2
+ require 'tap_dance/cli'
3
+ require 'tap_dance/ui'
4
+
5
+ module TapDance
6
+ def self.respond_to?(method)
7
+ TapDance.instance_methods.include? method
8
+ end
9
+
10
+ def self.method_missing(method, *args, &block)
11
+ TapDance::CLI.new.send(method, *args, &block)
12
+ end
13
+
14
+ class << self
15
+ attr_writer :ui
16
+
17
+ def ui
18
+ @ui ||= UI.new
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,24 @@
1
+ cmd = "./bin/dance"
2
+
3
+ describe "dancer" do
4
+ it "should output basic usage info" do
5
+ system(cmd).should be_true
6
+ end
7
+
8
+ it "should have an install task" do
9
+ system("#{cmd} install").should be_true
10
+ end
11
+
12
+ it "should have an update task" do
13
+ system("#{cmd} update").should be_true
14
+ end
15
+
16
+ it "should use the default Brewfile without args" do
17
+ `#{cmd}`.should include(File.join File.expand_path(Dir.pwd), "Brewfile")
18
+ end
19
+
20
+ it "should use the given Brewfile" do
21
+ brewfile = "lib/tap_dance/Brewfile"
22
+ `#{cmd} -B #{brewfile}`.should include(File.join File.expand_path(Dir.pwd), brewfile)
23
+ end
24
+ end
@@ -0,0 +1,13 @@
1
+ require 'tap_dance/brew_cli'
2
+ require 'tap_dance/ui'
3
+ require 'tap_dance'
4
+ require 'thor'
5
+
6
+ describe TapDance::BrewCLI do
7
+ it "should be able to do a dry-run on volatile actions" do
8
+ TapDance.ui = TapDance::UI::Logger.new
9
+ TapDance::BrewCLI.dry_run = true
10
+ TapDance::BrewCLI.install "git"
11
+ TapDance.ui.log.should include("Would run: brew install git")
12
+ end
13
+ end
@@ -0,0 +1,133 @@
1
+ require 'tap_dance/brew'
2
+ require 'tap_dance/tap'
3
+ require 'tap_dance/brew_cli'
4
+ require 'tap_dance/shell_result'
5
+
6
+ describe TapDance::Brew do
7
+ it "should let me create a brew without options" do
8
+ brew = TapDance::Brew.new(:git)
9
+ brew.should_not be_nil
10
+ end
11
+
12
+ it "should let me create a brew with options" do
13
+ tap = TapDance::Tap.new(:dev, "nybblr/dev")
14
+ brew = TapDance::Brew.new(:git, :tap => tap)
15
+ brew.should_not be_nil
16
+ brew.tap.should eql(tap)
17
+ end
18
+
19
+ it "should say git is a brewable formula" do
20
+ brew = TapDance::Brew.new(:git)
21
+ brew.brewable?.should be_true
22
+ end
23
+
24
+ it "should say asdfgh is not a brewable formula" do
25
+ brew = TapDance::Brew.new(:asdfgh)
26
+ brew.brewable?.should be_false
27
+ end
28
+
29
+ it "should be able to parse out correct installed versions" do
30
+ brew = TapDance::Brew.new(:git)
31
+ TapDance::BrewCLI.stub :list_versions => TapDance::ShellResult.new("git 1.8.2.1 1.8.2.2 2.0.0.alpha")
32
+
33
+ brew.installed_versions.should eql(%w[1.8.2.1 1.8.2.2 2.0.0.alpha])
34
+ end
35
+
36
+ it "should return nil if the brew isn't installed" do
37
+ brew = TapDance::Brew.new(:asdfgh)
38
+
39
+ brew.latest_version.should be_nil
40
+ end
41
+
42
+ it "should return the latest if the brew is installed" do
43
+ brew = TapDance::Brew.new(:asdfgh)
44
+ TapDance::BrewCLI.stub :list_versions => TapDance::ShellResult.new("git 1.8.2.1 1.8.2.2 2.0.0.alpha")
45
+
46
+ brew.latest_version.should eql("2.0.0.alpha")
47
+ end
48
+
49
+ it "should say a brew isn't installed when it isn't" do
50
+ brew = TapDance::Brew.new(:asdfgh)
51
+
52
+ brew.installed?.should be_false
53
+ end
54
+
55
+ it "should say a brew is installed when it is" do
56
+ brew = TapDance::Brew.new(:git)
57
+ TapDance::BrewCLI.stub :list_versions => TapDance::ShellResult.new("git 1.8.2.1 1.8.2.2 2.0.0.alpha")
58
+
59
+ brew.installed?.should be_true
60
+ end
61
+
62
+ it "should get any formula version if it exists" do
63
+ brew = TapDance::Brew.new(:git)
64
+
65
+ version = brew.formula_version
66
+ version.should_not be_nil
67
+ version.strip.should_not eql("")
68
+ end
69
+
70
+ it "should get the correct formula version when it exists" do
71
+ TapDance::BrewCLI.stub :formula_info => TapDance::ShellResult.new(<<-eos)
72
+ git: stable 1.8.2.3, HEAD
73
+ http://git-scm.com
74
+ /usr/local/Cellar/git/1.8.2.1 (1289 files, 27M)
75
+ Built from source
76
+ /usr/local/Cellar/git/1.8.2.2 (1290 files, 27M) *
77
+ Built from source
78
+ https://github.com/mxcl/homebrew/commits/master/Library/Formula/git.rb
79
+ ==> Dependencies
80
+ Optional: pcre, gettext
81
+ ==> Options
82
+ --with-blk-sha1
83
+ Compile with the block-optimized SHA1 implementation
84
+ --with-gettext
85
+ Build with gettext support
86
+ --with-pcre
87
+ Build with pcre support
88
+ --without-completions
89
+ Disable bash/zsh completions from "contrib" directory
90
+ ==> Caveats
91
+ The OS X keychain credential helper has been installed to:
92
+ /usr/local/bin/git-credential-osxkeychain
93
+
94
+ The 'contrib' directory has been installed to:
95
+ /usr/local/share/git-core/contrib
96
+
97
+ Bash completion has been installed to:
98
+ /usr/local/etc/bash_completion.d
99
+
100
+ zsh completion has been installed to:
101
+ /usr/local/share/zsh/site-functions"
102
+ eos
103
+
104
+ brew = TapDance::Brew.new(:git)
105
+ brew.formula_version.should eql("1.8.2.3")
106
+ end
107
+
108
+ it "should return nil when no formula version exists" do
109
+ brew = TapDance::Brew.new(:asdfgh)
110
+
111
+ brew.formula_version.should be_nil
112
+ end
113
+
114
+ it "should be able to fetch all formula versions" do
115
+ TapDance::BrewCLI.stub :formula_versions => TapDance::ShellResult.new(<<-eos, "Error", 1)
116
+ 1.8.3 git checkout 34ce866 /usr/local/Library/Formula/git.rb
117
+ 1.8.2.3 git checkout e33b2f0 /usr/local/Library/Formula/git.rb
118
+ 1.8.2.2 git checkout 015cd6e /usr/local/Library/Formula/git.rb
119
+ 1.8.2.1 git checkout fef0e87 /usr/local/Library/Formula/git.rb
120
+ 1.8.2 git checkout 583272d /usr/local/Library/Formula/git.rb
121
+
122
+ eos
123
+
124
+ brew = TapDance::Brew.new(:git)
125
+ brew.formula_versions.should eql([
126
+ %w[1.8.3 34ce866 /usr/local/Library/Formula/git.rb],
127
+ %w[1.8.2.3 e33b2f0 /usr/local/Library/Formula/git.rb],
128
+ %w[1.8.2.2 015cd6e /usr/local/Library/Formula/git.rb],
129
+ %w[1.8.2.1 fef0e87 /usr/local/Library/Formula/git.rb],
130
+ %w[1.8.2 583272d /usr/local/Library/Formula/git.rb],
131
+ ])
132
+ end
133
+ end
@@ -0,0 +1,23 @@
1
+ require 'tap_dance/cli'
2
+
3
+ describe TapDance::CLI do
4
+ it "outputs hello when installing" do
5
+ # TapDance::Dance.new.install.should eql("hello world!")
6
+ # TapDance::CLI.new.install
7
+ end
8
+
9
+ it "outputs goodbye when updating" do
10
+ # TapDance::Dance.new.update.should eql("goodbye world!")
11
+ # TapDance::CLI.new.update
12
+ end
13
+
14
+ it "should be able to install with Brewfile including flags" do
15
+ TapDance.ui = TapDance::UI::Shell.new
16
+ TapDance::BrewCLI.dry_run = true
17
+
18
+ cli = TapDance::CLI.new [], ["--brewfile", File.join(Dir.pwd, "examples/01_brewfile.rb")]
19
+ cli.install
20
+ # TapDance.ui.log.should include("Would run: brew install git")
21
+ end
22
+ end
23
+
@@ -0,0 +1,7 @@
1
+ require 'tap_dance/dsl'
2
+
3
+ describe TapDance::DSL do
4
+ it "should run a simple Brewfile" do
5
+ TapDance::DSL.evaluate "examples/01_brewfile.rb"
6
+ end
7
+ end
@@ -0,0 +1,78 @@
1
+ require 'tap_dance/shell_result'
2
+
3
+ describe TapDance::ShellResult do
4
+ it "should report error if the result is failure" do
5
+ res = TapDance::ShellResult.new "Hello world!", "", 0
6
+
7
+ res.error?.should be_false
8
+ res.okay?.should be_true
9
+ end
10
+
11
+ it "should report error even if nil is used" do
12
+ res = TapDance::ShellResult.new "Hello world!", nil, 0
13
+
14
+ res.error?.should be_false
15
+ res.okay?.should be_true
16
+ end
17
+
18
+ it "should use exit status as ultimatum" do
19
+ res = TapDance::ShellResult.new "Hello world!", nil, 1
20
+
21
+ res.error?.should be_true
22
+ res.okay?.should be_false
23
+
24
+ res = TapDance::ShellResult.new "Hello world!", "Something...", 1
25
+
26
+ res.error?.should be_true
27
+ res.okay?.should be_false
28
+ end
29
+
30
+ it "should notice standard output or error prefixed with Error" do
31
+ res = TapDance::ShellResult.new "Error: something", nil, 0
32
+
33
+ res.error?.should be_true
34
+ res.okay?.should be_false
35
+
36
+ res = TapDance::ShellResult.new "Hello world!", "Error: hello", 0
37
+
38
+ res.error?.should be_true
39
+ res.okay?.should be_false
40
+ end
41
+
42
+ it "should report stdout and stderr if it is not blank" do
43
+ res = TapDance::ShellResult.new "Hello world!", "", 0
44
+
45
+ res.stdout?.should be_true
46
+ res.stderr?.should be_false
47
+
48
+ res = TapDance::ShellResult.new "Hello world!", "That's bad.", 0
49
+
50
+ res.stdout?.should be_true
51
+ res.stderr?.should be_true
52
+ end
53
+
54
+ it "should make a pretty string using stdout if available" do
55
+ res = TapDance::ShellResult.new "Hello world!", "", 0
56
+ res.to_s.should eql("Hello world!")
57
+
58
+ res = TapDance::ShellResult.new "Hello world!", "That's bad.", 0
59
+ res.to_s.should eql("Hello world!")
60
+
61
+ res = TapDance::ShellResult.new "", "That's bad.", 0
62
+ res.to_s.should eql("That's bad.")
63
+ end
64
+
65
+ it "should correctly get exit status of command" do
66
+ res = TapDance::ShellResult.of("echo hello && exit 1")
67
+ res.status.should eql(1)
68
+ res.out.chomp.should eql("hello")
69
+ res.err.chomp.should eql("")
70
+ end
71
+
72
+ it "should correctly get stderr when included" do
73
+ res = TapDance::ShellResult.of("echo hello >&2 && exit 0")
74
+ res.status.should eql(0)
75
+ res.out.chomp.should eql("")
76
+ res.err.chomp.should eql("hello")
77
+ end
78
+ end
@@ -0,0 +1,28 @@
1
+ require 'tap_dance/tap'
2
+ require 'tap_dance/brew'
3
+ require 'tap_dance/brew_cli'
4
+ require 'tap_dance/shell_result'
5
+
6
+ describe TapDance::Tap do
7
+ it "should say it is tapped if it already is" do
8
+ tap = TapDance::Tap.new(:dev, "nybblr/dev")
9
+ TapDance::BrewCLI.stub :tab_list => <<-eos
10
+ homebrew/dupes
11
+ homebrew/science
12
+ nybblr/dev
13
+ samueljohn/python
14
+ eos
15
+
16
+ tap.tapped?.should be_true
17
+ end
18
+
19
+ it "should say it isn't tapped if it isn't" do
20
+ tap = TapDance::Tap.new(:dev, "nybblr/dev")
21
+ TapDance::BrewCLI.stub :tap_list => TapDance::ShellResult.new(<<-eos)
22
+ homebrew/dupes
23
+ homebrew/science
24
+ eos
25
+
26
+ tap.tapped?.should be_false
27
+ end
28
+ end
File without changes
@@ -0,0 +1,9 @@
1
+ require 'tap_dance'
2
+
3
+ describe TapDance do
4
+ it "shouldn't mind aliasing to the module" do
5
+ # TapDance.install.should eql(TapDance::CLI.new.install)
6
+ # TapDance.update.should eql(TapDance::CLI.new.update)
7
+ end
8
+ end
9
+
data/tap_dance.gemspec ADDED
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'tap_dance/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "tap_dance"
8
+ spec.version = TapDance::VERSION
9
+ spec.authors = ["Jonathan Martin"]
10
+ spec.email = ["me@nybblr.com"]
11
+ spec.description = %q{Manage your OSX binaries on a per project and system basis. Powered by Homebrew, inspired by Bundler.}
12
+ spec.summary = %q{Homebrew rocks, but managing system level dependencies can become a pain to track across multiple machines. Bundler was designed to make explicit declaration of Ruby dependencies consistent and painless. TapDance aims to do the same for system binaries.}
13
+ spec.homepage = "https://github.com/nybblr/tap_dance"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib", "ext"]
20
+
21
+ spec.add_dependency "thor"
22
+ spec.add_development_dependency "bundler"
23
+ spec.add_development_dependency "rake"
24
+ spec.add_development_dependency "rspec"
25
+ spec.add_development_dependency "guard"
26
+ spec.add_development_dependency "guard-rspec"
27
+ end