rubycut-babushka 0.10.6
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +8 -0
- data/Gemfile.lock +31 -0
- data/README.markdown +246 -0
- data/Rakefile +26 -0
- data/bin/babushka +11 -0
- data/deps/babushka.rb +101 -0
- data/deps/dev.rb +12 -0
- data/deps/fhs.rb +31 -0
- data/deps/git.rb +29 -0
- data/deps/homebrew.rb +30 -0
- data/deps/os_x.rb +33 -0
- data/deps/packages.rb +22 -0
- data/deps/pkg_managers.rb +110 -0
- data/deps/ruby.rb +23 -0
- data/deps/rubygems.rb +24 -0
- data/deps/system.rb +10 -0
- data/deps/templates/app.rb +68 -0
- data/deps/templates/external.rb +12 -0
- data/deps/templates/installer.rb +31 -0
- data/deps/templates/managed.rb +105 -0
- data/deps/templates/ppa.rb +24 -0
- data/deps/templates/src.rb +42 -0
- data/deps/templates/tmbundle.rb +15 -0
- data/lib/babushka.rb +28 -0
- data/lib/babushka/accepts_block_for.rb +72 -0
- data/lib/babushka/accepts_list_for.rb +49 -0
- data/lib/babushka/accepts_value_for.rb +24 -0
- data/lib/babushka/base.rb +78 -0
- data/lib/babushka/bug_reporter.rb +55 -0
- data/lib/babushka/cmdline.rb +133 -0
- data/lib/babushka/cmdline/handler.rb +41 -0
- data/lib/babushka/cmdline/helpers.rb +127 -0
- data/lib/babushka/cmdline/parser.rb +69 -0
- data/lib/babushka/colorizer.rb +59 -0
- data/lib/babushka/core_patches/array.rb +171 -0
- data/lib/babushka/core_patches/blank.rb +22 -0
- data/lib/babushka/core_patches/bytes.rb +52 -0
- data/lib/babushka/core_patches/hash.rb +107 -0
- data/lib/babushka/core_patches/hashish.rb +14 -0
- data/lib/babushka/core_patches/integer.rb +25 -0
- data/lib/babushka/core_patches/io.rb +8 -0
- data/lib/babushka/core_patches/numeric.rb +16 -0
- data/lib/babushka/core_patches/object.rb +27 -0
- data/lib/babushka/core_patches/string.rb +116 -0
- data/lib/babushka/core_patches/symbol.rb +12 -0
- data/lib/babushka/core_patches/try.rb +15 -0
- data/lib/babushka/core_patches/uri.rb +24 -0
- data/lib/babushka/dep.rb +470 -0
- data/lib/babushka/dep_context.rb +18 -0
- data/lib/babushka/dep_definer.rb +115 -0
- data/lib/babushka/dep_pool.rb +49 -0
- data/lib/babushka/dep_runner.rb +85 -0
- data/lib/babushka/dsl.rb +26 -0
- data/lib/babushka/git_repo.rb +185 -0
- data/lib/babushka/helpers/git_helpers.rb +32 -0
- data/lib/babushka/helpers/log_helpers.rb +176 -0
- data/lib/babushka/helpers/path_helpers.rb +34 -0
- data/lib/babushka/helpers/run_helpers.rb +145 -0
- data/lib/babushka/helpers/shell_helpers.rb +229 -0
- data/lib/babushka/helpers/suggest_helpers.rb +16 -0
- data/lib/babushka/helpers/uri_helpers.rb +36 -0
- data/lib/babushka/ip.rb +160 -0
- data/lib/babushka/lambda_chooser.rb +40 -0
- data/lib/babushka/levenshtein.rb +125 -0
- data/lib/babushka/meta_dep.rb +65 -0
- data/lib/babushka/meta_dep_context.rb +15 -0
- data/lib/babushka/parameter.rb +143 -0
- data/lib/babushka/pkg_helper.rb +81 -0
- data/lib/babushka/pkg_helpers/apt_helper.rb +61 -0
- data/lib/babushka/pkg_helpers/base_helper.rb +19 -0
- data/lib/babushka/pkg_helpers/binpkgsrc_helper.rb +48 -0
- data/lib/babushka/pkg_helpers/binports_helper.rb +34 -0
- data/lib/babushka/pkg_helpers/brew_helper.rb +110 -0
- data/lib/babushka/pkg_helpers/gem_helper.rb +120 -0
- data/lib/babushka/pkg_helpers/macports_helper.rb +22 -0
- data/lib/babushka/pkg_helpers/npm_helper.rb +45 -0
- data/lib/babushka/pkg_helpers/pacman_helper.rb +27 -0
- data/lib/babushka/pkg_helpers/pip_helper.rb +45 -0
- data/lib/babushka/pkg_helpers/src_helper.rb +16 -0
- data/lib/babushka/pkg_helpers/yum_helper.rb +25 -0
- data/lib/babushka/popen.rb +40 -0
- data/lib/babushka/prompt.rb +176 -0
- data/lib/babushka/renderable.rb +67 -0
- data/lib/babushka/resource.rb +215 -0
- data/lib/babushka/run_reporter.rb +60 -0
- data/lib/babushka/shell.rb +108 -0
- data/lib/babushka/source.rb +216 -0
- data/lib/babushka/source_pool.rb +146 -0
- data/lib/babushka/system_definitions.rb +97 -0
- data/lib/babushka/system_profile.rb +210 -0
- data/lib/babushka/task.rb +142 -0
- data/lib/babushka/vars.rb +108 -0
- data/lib/babushka/version_of.rb +65 -0
- data/lib/babushka/version_str.rb +57 -0
- data/lib/babushka/xml_string.rb +28 -0
- data/lib/components.rb +82 -0
- data/lib/fancypath/fancypath.rb +200 -0
- data/lib/inkan/inkan.rb +76 -0
- data/spec/acceptance/acceptance.rb +43 -0
- data/spec/acceptance_helper.rb +113 -0
- data/spec/archives/Blah.app.zip +0 -0
- data/spec/archives/archive.tar +0 -0
- data/spec/archives/archive.tar.bz2 +0 -0
- data/spec/archives/archive.tar.gz +0 -0
- data/spec/archives/archive.tbz2 +0 -0
- data/spec/archives/archive.tgz +0 -0
- data/spec/archives/archive.zip +0 -0
- data/spec/archives/content.txt +5 -0
- data/spec/archives/invalid_archive +5 -0
- data/spec/archives/nested archive/content.txt +5 -0
- data/spec/archives/nested_archive.tar +0 -0
- data/spec/archives/really_a_gzip.zip +0 -0
- data/spec/archives/test-0.3.1.tgz +0 -0
- data/spec/archives/tgz_archive +0 -0
- data/spec/archives/zip_without_extension +0 -0
- data/spec/babushka/accepts_for_spec.rb +174 -0
- data/spec/babushka/accepts_for_support.rb +72 -0
- data/spec/babushka/cmdline/console_spec.rb +11 -0
- data/spec/babushka/cmdline/help_spec.rb +61 -0
- data/spec/babushka/cmdline/version_spec.rb +10 -0
- data/spec/babushka/core_patches_spec.rb +171 -0
- data/spec/babushka/dep_context_spec.rb +58 -0
- data/spec/babushka/dep_definer_spec.rb +152 -0
- data/spec/babushka/dep_definer_support.rb +36 -0
- data/spec/babushka/dep_spec.rb +567 -0
- data/spec/babushka/dep_support.rb +29 -0
- data/spec/babushka/deps_spec.rb +113 -0
- data/spec/babushka/gem_helper_spec.rb +90 -0
- data/spec/babushka/git_repo_spec.rb +396 -0
- data/spec/babushka/ip_spec.rb +131 -0
- data/spec/babushka/lambda_chooser_spec.rb +115 -0
- data/spec/babushka/meta_dep_definer_spec.rb +127 -0
- data/spec/babushka/meta_dep_wrapper_spec.rb +32 -0
- data/spec/babushka/parameter_spec.rb +135 -0
- data/spec/babushka/path_helpers_spec.rb +102 -0
- data/spec/babushka/prompt_spec.rb +188 -0
- data/spec/babushka/renderable_spec.rb +100 -0
- data/spec/babushka/resource_spec.rb +141 -0
- data/spec/babushka/run_helpers_spec.rb +26 -0
- data/spec/babushka/shell_helpers_spec.rb +244 -0
- data/spec/babushka/shell_spec.rb +19 -0
- data/spec/babushka/source_pool_spec.rb +320 -0
- data/spec/babushka/source_pool_support.rb +31 -0
- data/spec/babushka/source_spec.rb +382 -0
- data/spec/babushka/source_support.rb +17 -0
- data/spec/babushka/system_profile_spec.rb +61 -0
- data/spec/babushka/task_spec.rb +141 -0
- data/spec/babushka/uri_spec.rb +13 -0
- data/spec/babushka/vars_spec.rb +59 -0
- data/spec/babushka/version_of_spec.rb +110 -0
- data/spec/babushka/version_str_spec.rb +130 -0
- data/spec/babushka/version_str_support.rb +37 -0
- data/spec/babushka/xml_string_spec.rb +98 -0
- data/spec/deps/bad/broken.rb +7 -0
- data/spec/deps/bad/working.rb +3 -0
- data/spec/deps/good/meta.rb +14 -0
- data/spec/deps/good/test.rb +11 -0
- data/spec/deps/outer/deps.rb +19 -0
- data/spec/deps/outer/more deps.rb +11 -0
- data/spec/deps/params/params.rb +10 -0
- data/spec/fancypath/fancypath_spec.rb +272 -0
- data/spec/fancypath_support.rb +10 -0
- data/spec/inkan/inkan_spec.rb +217 -0
- data/spec/renderable/different_example.conf.erb +4 -0
- data/spec/renderable/example.conf.erb +3 -0
- data/spec/renderable/example.sh +6 -0
- data/spec/renderable/with_binding.conf.erb +4 -0
- data/spec/renderable/xml_example.conf.erb +8 -0
- data/spec/repos/remote.git.tgz +0 -0
- data/spec/spec_helper.rb +87 -0
- metadata +238 -0
@@ -0,0 +1,18 @@
|
|
1
|
+
module Babushka
|
2
|
+
class DepContext < DepDefiner
|
3
|
+
include DepRunner
|
4
|
+
|
5
|
+
accepts_list_for :desc
|
6
|
+
accepts_list_for :requires
|
7
|
+
accepts_list_for :requires_when_unmet
|
8
|
+
accepts_value_for :run_in
|
9
|
+
|
10
|
+
accepts_block_for :setup
|
11
|
+
accepts_block_for :met?
|
12
|
+
|
13
|
+
accepts_block_for :prepare
|
14
|
+
accepts_block_for :before
|
15
|
+
accepts_block_for :meet
|
16
|
+
accepts_block_for :after
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
module Babushka
|
2
|
+
class DepDefiner
|
3
|
+
include LogHelpers
|
4
|
+
extend LogHelpers
|
5
|
+
include ShellHelpers
|
6
|
+
extend ShellHelpers
|
7
|
+
include PathHelpers
|
8
|
+
extend PathHelpers
|
9
|
+
include RunHelpers
|
10
|
+
extend RunHelpers
|
11
|
+
|
12
|
+
include Prompt::Helpers
|
13
|
+
extend Prompt::Helpers
|
14
|
+
include VersionOf::Helpers
|
15
|
+
extend VersionOf::Helpers
|
16
|
+
|
17
|
+
include AcceptsListFor
|
18
|
+
include AcceptsValueFor
|
19
|
+
include AcceptsBlockFor
|
20
|
+
|
21
|
+
attr_reader :dependency, :payload, :block
|
22
|
+
|
23
|
+
def name; dependency.name end
|
24
|
+
def basename; dependency.basename end
|
25
|
+
def load_path; dependency.load_path end
|
26
|
+
|
27
|
+
include Vars::Helpers
|
28
|
+
extend Vars::Helpers
|
29
|
+
|
30
|
+
def initialize dep, &block
|
31
|
+
@dependency = dep
|
32
|
+
@payload = {}
|
33
|
+
@block = block
|
34
|
+
end
|
35
|
+
|
36
|
+
def define!
|
37
|
+
define_params!
|
38
|
+
|
39
|
+
unless block.nil?
|
40
|
+
raise "Dep block arguments aren't supported anymore. Instead, specify parameter names as symbols after the dep name. More details here: http://github.com/benhoskings/babushka/commit/40054c2" if block.arity > 0
|
41
|
+
instance_eval(&block)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def result message, opts = {}
|
46
|
+
opts[:result].tap {
|
47
|
+
dependency.result_message = message
|
48
|
+
}
|
49
|
+
end
|
50
|
+
|
51
|
+
def met message
|
52
|
+
result message, :result => true
|
53
|
+
end
|
54
|
+
|
55
|
+
def unmet message
|
56
|
+
result message, :result => false
|
57
|
+
end
|
58
|
+
|
59
|
+
def unmeetable message
|
60
|
+
raise Babushka::UnmeetableDep, message
|
61
|
+
end
|
62
|
+
|
63
|
+
def file_and_line
|
64
|
+
get_file_and_line_for(block)
|
65
|
+
end
|
66
|
+
|
67
|
+
def file_and_line_for block_name
|
68
|
+
get_file_and_line_for send(block_name) if has_block? block_name
|
69
|
+
end
|
70
|
+
|
71
|
+
def get_file_and_line_for blk
|
72
|
+
blk.inspect.scan(/\#\<Proc\:0x[0-9a-f]+\@([^:]+):(\d+)>/).flatten
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
|
77
|
+
def define_params!
|
78
|
+
dependency.params.each {|param|
|
79
|
+
if respond_to?(param)
|
80
|
+
raise DepParameterError, "You can't use #{param.inspect} as a parameter (on '#{dependency.name}'), because that's already a method on #{method(param).owner}."
|
81
|
+
else
|
82
|
+
metaclass.send :define_method, param do
|
83
|
+
dependency.args[param] ||= Parameter.new(param)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
}
|
87
|
+
end
|
88
|
+
|
89
|
+
def pkg_manager
|
90
|
+
BaseHelper
|
91
|
+
end
|
92
|
+
|
93
|
+
def on platform, &blk
|
94
|
+
if [*chooser].include? platform
|
95
|
+
@current_platform = platform
|
96
|
+
blk.call.tap {
|
97
|
+
@current_platform = nil
|
98
|
+
}
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def chooser
|
103
|
+
Base.host.match_list
|
104
|
+
end
|
105
|
+
|
106
|
+
def chooser_choices
|
107
|
+
SystemDefinitions.all_tokens
|
108
|
+
end
|
109
|
+
|
110
|
+
def self.source_template
|
111
|
+
Dep.base_template
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Babushka
|
2
|
+
class DepPool
|
3
|
+
|
4
|
+
def initialize source
|
5
|
+
clear!
|
6
|
+
@source = source
|
7
|
+
end
|
8
|
+
|
9
|
+
def count
|
10
|
+
@pool.length
|
11
|
+
end
|
12
|
+
|
13
|
+
def names
|
14
|
+
@pool.keys
|
15
|
+
end
|
16
|
+
def items
|
17
|
+
@pool.values
|
18
|
+
end
|
19
|
+
def for spec
|
20
|
+
spec.respond_to?(:name) ? @pool[spec.name] : @pool[spec]
|
21
|
+
end
|
22
|
+
|
23
|
+
def add_dep name, params, block
|
24
|
+
if self.for name
|
25
|
+
self.for name
|
26
|
+
else
|
27
|
+
opts = params.extract_options!
|
28
|
+
Dep.new name, @source, params, opts, block
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def add_template name, in_opts, block
|
33
|
+
MetaDep.for name, @source, in_opts, &block
|
34
|
+
end
|
35
|
+
|
36
|
+
def clear!
|
37
|
+
@pool = {}
|
38
|
+
end
|
39
|
+
def uncache!
|
40
|
+
items.each {|i| i.send :uncache! }
|
41
|
+
end
|
42
|
+
|
43
|
+
def register item
|
44
|
+
raise "Already registered '#{item.name}'." if @pool.has_key?(item.name)
|
45
|
+
@pool[item.name] = item
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
module Babushka
|
2
|
+
module DepRunner
|
3
|
+
include GitHelpers
|
4
|
+
include UriHelpers
|
5
|
+
|
6
|
+
private
|
7
|
+
|
8
|
+
# TODO: solve cmd/app and string/version handling better.
|
9
|
+
def in_path? provided_list
|
10
|
+
apps, command_names = [*provided_list].partition {|i| i.to_s[/\.app\/?$/] }
|
11
|
+
commands = command_names.versions
|
12
|
+
apps_in_path?(apps) and cmds_in_path?(commands) and matching_versions?(commands)
|
13
|
+
end
|
14
|
+
|
15
|
+
def apps_in_path? apps
|
16
|
+
present, missing = [*apps].partition {|app_name| app_dir(app_name) }
|
17
|
+
|
18
|
+
missing.empty?.tap {|result|
|
19
|
+
if result
|
20
|
+
log "#{present.map {|i| "'#{i}'" }.to_list} #{present.length == 1 ? 'is' : 'are'} present." unless present.empty?
|
21
|
+
else
|
22
|
+
log "#{missing.map {|i| "'#{i}'" }.to_list} #{missing.length == 1 ? 'is' : 'are'}n't present anywhere in $PATH."
|
23
|
+
end
|
24
|
+
}
|
25
|
+
end
|
26
|
+
|
27
|
+
def cmds_in_path? commands
|
28
|
+
dir_hash = [*commands].group_by {|cmd| cmd_dir(cmd.name) }
|
29
|
+
|
30
|
+
if dir_hash.keys.compact.length > 1
|
31
|
+
unmeetable "The commands for '#{name}' run from more than one place.\n" +
|
32
|
+
dir_hash.values.map {|cmds|
|
33
|
+
cmd_location_str_for cmds
|
34
|
+
}.to_list(:oxford => true, :conj => 'but').end_with('.')
|
35
|
+
else
|
36
|
+
cmds = dir_hash.values.first
|
37
|
+
dir_hash[nil].blank?.tap {|result|
|
38
|
+
if result
|
39
|
+
log cmd_location_str_for(cmds).end_with('.') unless cmds.blank?
|
40
|
+
else
|
41
|
+
log "#{dir_hash[nil].map {|i| "'#{i}'" }.to_list} #{dir_hash[nil].length == 1 ? 'is' : 'are'} missing."
|
42
|
+
end
|
43
|
+
}
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def matching_versions? commands
|
48
|
+
versions = commands.select {|cmd|
|
49
|
+
!cmd.version.nil?
|
50
|
+
}.inject({}) {|hsh,cmd|
|
51
|
+
hsh[cmd] = (shell("#{cmd.name} --version") || '').split(/[\s\-]/).detect {|piece|
|
52
|
+
begin
|
53
|
+
cmd.matches? piece.to_version
|
54
|
+
rescue VersionStrError
|
55
|
+
false
|
56
|
+
end
|
57
|
+
}
|
58
|
+
log "#{cmd.name} is #{hsh[cmd]}, which is#{"n't" unless hsh[cmd]} #{cmd.version}.", :as => (:ok if hsh[cmd])
|
59
|
+
hsh
|
60
|
+
}
|
61
|
+
versions.values.all?
|
62
|
+
end
|
63
|
+
|
64
|
+
def app_dir app_name
|
65
|
+
prefix.find {|app_path|
|
66
|
+
(app_path.to_s / app_name).glob.select {|entry|
|
67
|
+
(entry / 'Contents/MacOS').exists?
|
68
|
+
}.first
|
69
|
+
}
|
70
|
+
end
|
71
|
+
|
72
|
+
def cmd_location_str_for cmds
|
73
|
+
"#{cmds.map {|i| "'#{i.name}'" }.to_list(:conj => '&')} run#{'s' if cmds.length == 1} from #{cmd_dir(cmds.first.name)}"
|
74
|
+
end
|
75
|
+
|
76
|
+
def call_task task_name
|
77
|
+
if (task_block = send(task_name)).nil?
|
78
|
+
true
|
79
|
+
else
|
80
|
+
instance_eval(&task_block)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
end
|
data/lib/babushka/dsl.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
module Babushka
|
2
|
+
module DSL
|
3
|
+
# Use +spec+ to look up a dep. Because +spec+ might include a source
|
4
|
+
# prefix, the dep this method returns could be from any of the currently
|
5
|
+
# known sources.
|
6
|
+
# If no dep matching +spec+ is found, nil is returned.
|
7
|
+
def Dep spec, opts = {}
|
8
|
+
Base.sources.dep_for spec, opts
|
9
|
+
end
|
10
|
+
|
11
|
+
# Define and return a dep named +name+, and whose implementation is found
|
12
|
+
# in +block+. This is the usual top-level entry point of the babushka
|
13
|
+
# DSL (along with +meta+); templated or not, this is how deps are
|
14
|
+
# defined.
|
15
|
+
def dep name, *params, &block
|
16
|
+
Base.sources.current_load_source.deps.add_dep name, params, block
|
17
|
+
end
|
18
|
+
|
19
|
+
# Define and return a meta dep named +name+, and whose implementation is
|
20
|
+
# found in +block+. This method, along with +dep, together are the
|
21
|
+
# top level of babushka's DSL.
|
22
|
+
def meta name, opts = {}, &block
|
23
|
+
Base.sources.current_load_source.templates.add_template name, opts, block
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,185 @@
|
|
1
|
+
module Babushka
|
2
|
+
class GitRepoError < StandardError
|
3
|
+
end
|
4
|
+
class GitRepoExists < GitRepoError
|
5
|
+
end
|
6
|
+
# This class is used for manipulating git repositories (see {#initialize} how to start). Mostly it provides shortcuts to most often used git commands.
|
7
|
+
# @example Example of usage:
|
8
|
+
# @repo ||= Babushka::GitRepo.new('.')
|
9
|
+
# @repo.clone "https://github.com/benhoskings/babushka"
|
10
|
+
# @repo.checkout! "devel"
|
11
|
+
#
|
12
|
+
# For practical example how to use GitRepo class, see Ben Hoskings {https://github.com/benhoskings/babushka-deps/blob/master/push.rb push dep}
|
13
|
+
#
|
14
|
+
# Methods for checking repositrory state:
|
15
|
+
#
|
16
|
+
# * {#clean?}
|
17
|
+
# * {#dirty?}
|
18
|
+
# * {#include?} ref
|
19
|
+
# * {#ahead?}
|
20
|
+
# * {#behind?}
|
21
|
+
# * {#rebasing?}
|
22
|
+
# * {#applying?}
|
23
|
+
# * {#merging?}
|
24
|
+
# * {#bisecting?}
|
25
|
+
# * {#rebase_merging?}
|
26
|
+
# * {#rebasing_interactively?}
|
27
|
+
#
|
28
|
+
# Methods for repository operations:
|
29
|
+
#
|
30
|
+
# * {#clone!}
|
31
|
+
# * {#branch!}
|
32
|
+
# * {#track!}
|
33
|
+
# * {#checkout!}
|
34
|
+
# * {#reset_hard!} refspec
|
35
|
+
|
36
|
+
class GitRepo
|
37
|
+
include ShellHelpers
|
38
|
+
extend ShellHelpers
|
39
|
+
|
40
|
+
def self.repo_for path
|
41
|
+
maybe = shell("git rev-parse --git-dir", :cd => path) if path.p.dir?
|
42
|
+
maybe == '.git' ? path.p : maybe / '..' unless maybe.nil?
|
43
|
+
end
|
44
|
+
# @example Initialize repo in current dir
|
45
|
+
# @repo ||= Babushka::GitRepo.new('.')
|
46
|
+
def initialize path
|
47
|
+
@raw_path = path
|
48
|
+
end
|
49
|
+
|
50
|
+
def path
|
51
|
+
@path ||= @raw_path.p
|
52
|
+
end
|
53
|
+
|
54
|
+
def root
|
55
|
+
@root ||= self.class.repo_for(path)
|
56
|
+
end
|
57
|
+
|
58
|
+
def git_dir
|
59
|
+
root / '.git'
|
60
|
+
end
|
61
|
+
|
62
|
+
def exists?
|
63
|
+
!root.nil? && root.exists?
|
64
|
+
end
|
65
|
+
# executes shell command setting current directory to repository root
|
66
|
+
#
|
67
|
+
def repo_shell cmd, opts = {}, &block
|
68
|
+
if !exists?
|
69
|
+
raise GitRepoError, "There is no repo at #{@path}."
|
70
|
+
else
|
71
|
+
shell cmd, opts.merge(:cd => root), &block
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def clean?
|
76
|
+
repo_shell("git status") # Sometimes git caches invalid index info; this clears it.
|
77
|
+
repo_shell("git diff-index --name-status HEAD", &:stdout).blank?
|
78
|
+
end
|
79
|
+
|
80
|
+
def dirty?
|
81
|
+
!clean?
|
82
|
+
end
|
83
|
+
|
84
|
+
def include? ref
|
85
|
+
repo_shell("git rev-list -n 1 '#{ref}'")
|
86
|
+
end
|
87
|
+
|
88
|
+
def ahead?
|
89
|
+
!remote_branch_exists? ||
|
90
|
+
!repo_shell("git rev-list origin/#{current_branch}..").split("\n").empty?
|
91
|
+
end
|
92
|
+
|
93
|
+
def behind?
|
94
|
+
remote_branch_exists? &&
|
95
|
+
!repo_shell("git rev-list ..origin/#{current_branch}").split("\n").empty?
|
96
|
+
end
|
97
|
+
|
98
|
+
def rebasing?
|
99
|
+
%w[rebase rebase-apply ../.dotest].any? {|d|
|
100
|
+
(git_dir / d).exists?
|
101
|
+
} or rebase_merging? or rebasing_interactively?
|
102
|
+
end
|
103
|
+
|
104
|
+
def applying?
|
105
|
+
%w[rebase rebase-apply ../.dotest].any? {|d|
|
106
|
+
(git_dir / d / 'applying').exists?
|
107
|
+
}
|
108
|
+
end
|
109
|
+
|
110
|
+
def merging?
|
111
|
+
(git_dir / 'MERGE_HEAD').exists? or rebase_merging?
|
112
|
+
end
|
113
|
+
|
114
|
+
def bisecting?
|
115
|
+
(git_dir / 'BISECT_LOG').exists?
|
116
|
+
end
|
117
|
+
|
118
|
+
def rebase_merging?
|
119
|
+
%w[rebase-merge .dotest-merge].any? {|d|
|
120
|
+
(git_dir / d).exists?
|
121
|
+
}
|
122
|
+
end
|
123
|
+
|
124
|
+
def rebasing_interactively?
|
125
|
+
%w[rebase-merge .dotest-merge].any? {|d|
|
126
|
+
(git_dir / d / 'interactive').exists?
|
127
|
+
}
|
128
|
+
end
|
129
|
+
|
130
|
+
def branches
|
131
|
+
repo_shell('git branch').split("\n").map {|l| l.sub(/^[* ]+/, '') }
|
132
|
+
end
|
133
|
+
|
134
|
+
def current_branch
|
135
|
+
repo_shell("cat .git/HEAD").strip.sub(/^.*refs\/heads\//, '')
|
136
|
+
end
|
137
|
+
|
138
|
+
def current_head
|
139
|
+
repo_shell("git rev-parse --short HEAD")
|
140
|
+
end
|
141
|
+
|
142
|
+
def current_full_head
|
143
|
+
repo_shell("git rev-parse HEAD")
|
144
|
+
end
|
145
|
+
|
146
|
+
def remote_branch_exists?
|
147
|
+
repo_shell('git branch -a').split("\n").map(&:strip).detect {|b|
|
148
|
+
b[/^(remotes\/)?origin\/#{current_branch}$/]
|
149
|
+
}
|
150
|
+
end
|
151
|
+
|
152
|
+
def clone! from
|
153
|
+
raise GitRepoExists, "Can't clone #{from} to existing path #{path}." if exists?
|
154
|
+
shell("git clone '#{from}' '#{path.basename}'", :cd => path.parent, :create => true) {|shell|
|
155
|
+
shell.ok? || raise(GitRepoError, "Couldn't clone to #{path}: #{error_message_for shell.stderr}")
|
156
|
+
}
|
157
|
+
end
|
158
|
+
|
159
|
+
def branch! branch
|
160
|
+
repo_shell("git branch '#{branch}'")
|
161
|
+
end
|
162
|
+
|
163
|
+
def track! branch
|
164
|
+
repo_shell("git checkout -t '#{branch}'")
|
165
|
+
end
|
166
|
+
|
167
|
+
def checkout! branch
|
168
|
+
repo_shell("git checkout '#{branch}'")
|
169
|
+
end
|
170
|
+
|
171
|
+
def reset_hard! refspec = 'HEAD'
|
172
|
+
repo_shell("git reset --hard #{refspec}")
|
173
|
+
end
|
174
|
+
|
175
|
+
def inspect
|
176
|
+
"#<GitRepo:#{root} : #{current_branch}@#{current_head}#{' (dirty)' if dirty?}>"
|
177
|
+
end
|
178
|
+
|
179
|
+
private
|
180
|
+
|
181
|
+
def error_message_for git_error
|
182
|
+
git_error.sub(/^fatal\: /, '').sub(/\n.*$/m, '').end_with('.')
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|