tap_dance 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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