rubycut-babushka 0.10.6

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.
Files changed (171) hide show
  1. data/Gemfile +8 -0
  2. data/Gemfile.lock +31 -0
  3. data/README.markdown +246 -0
  4. data/Rakefile +26 -0
  5. data/bin/babushka +11 -0
  6. data/deps/babushka.rb +101 -0
  7. data/deps/dev.rb +12 -0
  8. data/deps/fhs.rb +31 -0
  9. data/deps/git.rb +29 -0
  10. data/deps/homebrew.rb +30 -0
  11. data/deps/os_x.rb +33 -0
  12. data/deps/packages.rb +22 -0
  13. data/deps/pkg_managers.rb +110 -0
  14. data/deps/ruby.rb +23 -0
  15. data/deps/rubygems.rb +24 -0
  16. data/deps/system.rb +10 -0
  17. data/deps/templates/app.rb +68 -0
  18. data/deps/templates/external.rb +12 -0
  19. data/deps/templates/installer.rb +31 -0
  20. data/deps/templates/managed.rb +105 -0
  21. data/deps/templates/ppa.rb +24 -0
  22. data/deps/templates/src.rb +42 -0
  23. data/deps/templates/tmbundle.rb +15 -0
  24. data/lib/babushka.rb +28 -0
  25. data/lib/babushka/accepts_block_for.rb +72 -0
  26. data/lib/babushka/accepts_list_for.rb +49 -0
  27. data/lib/babushka/accepts_value_for.rb +24 -0
  28. data/lib/babushka/base.rb +78 -0
  29. data/lib/babushka/bug_reporter.rb +55 -0
  30. data/lib/babushka/cmdline.rb +133 -0
  31. data/lib/babushka/cmdline/handler.rb +41 -0
  32. data/lib/babushka/cmdline/helpers.rb +127 -0
  33. data/lib/babushka/cmdline/parser.rb +69 -0
  34. data/lib/babushka/colorizer.rb +59 -0
  35. data/lib/babushka/core_patches/array.rb +171 -0
  36. data/lib/babushka/core_patches/blank.rb +22 -0
  37. data/lib/babushka/core_patches/bytes.rb +52 -0
  38. data/lib/babushka/core_patches/hash.rb +107 -0
  39. data/lib/babushka/core_patches/hashish.rb +14 -0
  40. data/lib/babushka/core_patches/integer.rb +25 -0
  41. data/lib/babushka/core_patches/io.rb +8 -0
  42. data/lib/babushka/core_patches/numeric.rb +16 -0
  43. data/lib/babushka/core_patches/object.rb +27 -0
  44. data/lib/babushka/core_patches/string.rb +116 -0
  45. data/lib/babushka/core_patches/symbol.rb +12 -0
  46. data/lib/babushka/core_patches/try.rb +15 -0
  47. data/lib/babushka/core_patches/uri.rb +24 -0
  48. data/lib/babushka/dep.rb +470 -0
  49. data/lib/babushka/dep_context.rb +18 -0
  50. data/lib/babushka/dep_definer.rb +115 -0
  51. data/lib/babushka/dep_pool.rb +49 -0
  52. data/lib/babushka/dep_runner.rb +85 -0
  53. data/lib/babushka/dsl.rb +26 -0
  54. data/lib/babushka/git_repo.rb +185 -0
  55. data/lib/babushka/helpers/git_helpers.rb +32 -0
  56. data/lib/babushka/helpers/log_helpers.rb +176 -0
  57. data/lib/babushka/helpers/path_helpers.rb +34 -0
  58. data/lib/babushka/helpers/run_helpers.rb +145 -0
  59. data/lib/babushka/helpers/shell_helpers.rb +229 -0
  60. data/lib/babushka/helpers/suggest_helpers.rb +16 -0
  61. data/lib/babushka/helpers/uri_helpers.rb +36 -0
  62. data/lib/babushka/ip.rb +160 -0
  63. data/lib/babushka/lambda_chooser.rb +40 -0
  64. data/lib/babushka/levenshtein.rb +125 -0
  65. data/lib/babushka/meta_dep.rb +65 -0
  66. data/lib/babushka/meta_dep_context.rb +15 -0
  67. data/lib/babushka/parameter.rb +143 -0
  68. data/lib/babushka/pkg_helper.rb +81 -0
  69. data/lib/babushka/pkg_helpers/apt_helper.rb +61 -0
  70. data/lib/babushka/pkg_helpers/base_helper.rb +19 -0
  71. data/lib/babushka/pkg_helpers/binpkgsrc_helper.rb +48 -0
  72. data/lib/babushka/pkg_helpers/binports_helper.rb +34 -0
  73. data/lib/babushka/pkg_helpers/brew_helper.rb +110 -0
  74. data/lib/babushka/pkg_helpers/gem_helper.rb +120 -0
  75. data/lib/babushka/pkg_helpers/macports_helper.rb +22 -0
  76. data/lib/babushka/pkg_helpers/npm_helper.rb +45 -0
  77. data/lib/babushka/pkg_helpers/pacman_helper.rb +27 -0
  78. data/lib/babushka/pkg_helpers/pip_helper.rb +45 -0
  79. data/lib/babushka/pkg_helpers/src_helper.rb +16 -0
  80. data/lib/babushka/pkg_helpers/yum_helper.rb +25 -0
  81. data/lib/babushka/popen.rb +40 -0
  82. data/lib/babushka/prompt.rb +176 -0
  83. data/lib/babushka/renderable.rb +67 -0
  84. data/lib/babushka/resource.rb +215 -0
  85. data/lib/babushka/run_reporter.rb +60 -0
  86. data/lib/babushka/shell.rb +108 -0
  87. data/lib/babushka/source.rb +216 -0
  88. data/lib/babushka/source_pool.rb +146 -0
  89. data/lib/babushka/system_definitions.rb +97 -0
  90. data/lib/babushka/system_profile.rb +210 -0
  91. data/lib/babushka/task.rb +142 -0
  92. data/lib/babushka/vars.rb +108 -0
  93. data/lib/babushka/version_of.rb +65 -0
  94. data/lib/babushka/version_str.rb +57 -0
  95. data/lib/babushka/xml_string.rb +28 -0
  96. data/lib/components.rb +82 -0
  97. data/lib/fancypath/fancypath.rb +200 -0
  98. data/lib/inkan/inkan.rb +76 -0
  99. data/spec/acceptance/acceptance.rb +43 -0
  100. data/spec/acceptance_helper.rb +113 -0
  101. data/spec/archives/Blah.app.zip +0 -0
  102. data/spec/archives/archive.tar +0 -0
  103. data/spec/archives/archive.tar.bz2 +0 -0
  104. data/spec/archives/archive.tar.gz +0 -0
  105. data/spec/archives/archive.tbz2 +0 -0
  106. data/spec/archives/archive.tgz +0 -0
  107. data/spec/archives/archive.zip +0 -0
  108. data/spec/archives/content.txt +5 -0
  109. data/spec/archives/invalid_archive +5 -0
  110. data/spec/archives/nested archive/content.txt +5 -0
  111. data/spec/archives/nested_archive.tar +0 -0
  112. data/spec/archives/really_a_gzip.zip +0 -0
  113. data/spec/archives/test-0.3.1.tgz +0 -0
  114. data/spec/archives/tgz_archive +0 -0
  115. data/spec/archives/zip_without_extension +0 -0
  116. data/spec/babushka/accepts_for_spec.rb +174 -0
  117. data/spec/babushka/accepts_for_support.rb +72 -0
  118. data/spec/babushka/cmdline/console_spec.rb +11 -0
  119. data/spec/babushka/cmdline/help_spec.rb +61 -0
  120. data/spec/babushka/cmdline/version_spec.rb +10 -0
  121. data/spec/babushka/core_patches_spec.rb +171 -0
  122. data/spec/babushka/dep_context_spec.rb +58 -0
  123. data/spec/babushka/dep_definer_spec.rb +152 -0
  124. data/spec/babushka/dep_definer_support.rb +36 -0
  125. data/spec/babushka/dep_spec.rb +567 -0
  126. data/spec/babushka/dep_support.rb +29 -0
  127. data/spec/babushka/deps_spec.rb +113 -0
  128. data/spec/babushka/gem_helper_spec.rb +90 -0
  129. data/spec/babushka/git_repo_spec.rb +396 -0
  130. data/spec/babushka/ip_spec.rb +131 -0
  131. data/spec/babushka/lambda_chooser_spec.rb +115 -0
  132. data/spec/babushka/meta_dep_definer_spec.rb +127 -0
  133. data/spec/babushka/meta_dep_wrapper_spec.rb +32 -0
  134. data/spec/babushka/parameter_spec.rb +135 -0
  135. data/spec/babushka/path_helpers_spec.rb +102 -0
  136. data/spec/babushka/prompt_spec.rb +188 -0
  137. data/spec/babushka/renderable_spec.rb +100 -0
  138. data/spec/babushka/resource_spec.rb +141 -0
  139. data/spec/babushka/run_helpers_spec.rb +26 -0
  140. data/spec/babushka/shell_helpers_spec.rb +244 -0
  141. data/spec/babushka/shell_spec.rb +19 -0
  142. data/spec/babushka/source_pool_spec.rb +320 -0
  143. data/spec/babushka/source_pool_support.rb +31 -0
  144. data/spec/babushka/source_spec.rb +382 -0
  145. data/spec/babushka/source_support.rb +17 -0
  146. data/spec/babushka/system_profile_spec.rb +61 -0
  147. data/spec/babushka/task_spec.rb +141 -0
  148. data/spec/babushka/uri_spec.rb +13 -0
  149. data/spec/babushka/vars_spec.rb +59 -0
  150. data/spec/babushka/version_of_spec.rb +110 -0
  151. data/spec/babushka/version_str_spec.rb +130 -0
  152. data/spec/babushka/version_str_support.rb +37 -0
  153. data/spec/babushka/xml_string_spec.rb +98 -0
  154. data/spec/deps/bad/broken.rb +7 -0
  155. data/spec/deps/bad/working.rb +3 -0
  156. data/spec/deps/good/meta.rb +14 -0
  157. data/spec/deps/good/test.rb +11 -0
  158. data/spec/deps/outer/deps.rb +19 -0
  159. data/spec/deps/outer/more deps.rb +11 -0
  160. data/spec/deps/params/params.rb +10 -0
  161. data/spec/fancypath/fancypath_spec.rb +272 -0
  162. data/spec/fancypath_support.rb +10 -0
  163. data/spec/inkan/inkan_spec.rb +217 -0
  164. data/spec/renderable/different_example.conf.erb +4 -0
  165. data/spec/renderable/example.conf.erb +3 -0
  166. data/spec/renderable/example.sh +6 -0
  167. data/spec/renderable/with_binding.conf.erb +4 -0
  168. data/spec/renderable/xml_example.conf.erb +8 -0
  169. data/spec/repos/remote.git.tgz +0 -0
  170. data/spec/spec_helper.rb +87 -0
  171. metadata +238 -0
@@ -0,0 +1,15 @@
1
+ module Babushka
2
+ class MetaDepContext < DepContext
3
+
4
+ def self.template &block
5
+ @template = block unless block.nil?
6
+ @template
7
+ end
8
+
9
+ def define!
10
+ instance_eval(&self.class.template) unless self.class.template.nil?
11
+ super
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,143 @@
1
+ module Babushka
2
+ class Parameter
3
+ attr_reader :name
4
+
5
+ def self.for name, value = nil
6
+ value.is_a?(Parameter) ? value : Parameter.new(name, value)
7
+ end
8
+
9
+ def initialize(name, value = nil)
10
+ @name = name
11
+ @value = value
12
+ end
13
+
14
+ # If #default! is set, the parameter's value will default to it lazily when
15
+ # it's requested, without prompting. If the parameter is set, though (i.e.
16
+ # if an explicit value was supplied, say on the command line), it will
17
+ # override the #default! value.
18
+ #
19
+ # This is useful for setting parameters that have a "standard" value of some
20
+ # kind that won't usually need to be customised.
21
+ #
22
+ # For example, the deps that install babushka itself use a :branch parameter
23
+ # that has #default! set to 'master'. This means that the installation
24
+ # process will install the 'master' branch without asking the user to choose
25
+ # a branch, but a custom branch can still be specified by passing an
26
+ # explicit value, for example by passing 'branch=next' on the command line.
27
+ def default! value
28
+ tap { @default_bang = value }
29
+ end
30
+
31
+ # If #default is set, then when this parameter lazily prompts for a value,
32
+ # it will pass #default to Prompt as the default. That is, Prompt will
33
+ # return #default's value if the user just hits 'enter', if '--defaults' was
34
+ # passed on the commandline, or if babushka is running on a non-terminal
35
+ # STDIN.
36
+ #
37
+ # This is useful for setting parameters that should be customised, or maybe
38
+ # just confirmed by the user, each time the dep is run.
39
+ #
40
+ # For example, the deps that install babushka itself use a :path parameter
41
+ # that has #default set to '/usr/local/babushka' (unless babushka is already
42
+ # in the path, in which case it's a non-prompting default). This means that
43
+ # babushka will ask for a path when it's installed, providing
44
+ # '/usr/local/babushka' as the "just-hit-enter" default.
45
+ def default value
46
+ tap { @default = value }
47
+ end
48
+
49
+ # If #ask is set, then when this parameter lazily prompts for a value, it
50
+ # will pass #ask to Prompt as the message. That is, Prompt will use this
51
+ # string, ending it with a question mark, as the question it shows to the
52
+ # user to give them information about the value it's requesting.
53
+ #
54
+ # For example, the deps that install babushka itself use a :path parameter.
55
+ # if #ask wasn't specified, it would prompt the user with just 'path?',
56
+ # which isn't very clear. Instead, #ask is set to 'Where would you like
57
+ # babushka installed', which, along with the default value, makes it clear
58
+ # to the user what they're being asked for.
59
+ def ask value
60
+ tap { @ask = value }
61
+ end
62
+
63
+ # If #choose is set, then when this parameter lazily prompts for a value, it
64
+ # will only accept a value that is in #choose's list.
65
+ #
66
+ # You can pass either an array or a hash to #choose. If you pass an array of
67
+ # values, Prompt will only accept a value that's included in the array. If
68
+ # you pass a hash of {value => description}, Prompt will only accept a value
69
+ # that's included in the hash's keys, printing a list of the corresponding
70
+ # descriptions before asking for the value.
71
+ def choose *value
72
+ tap {
73
+ @choose = if [[Hash], [Array]].include?(value.map(&:class))
74
+ value.first
75
+ else
76
+ value
77
+ end
78
+ }
79
+ end
80
+
81
+ def set?
82
+ !!@value
83
+ end
84
+
85
+ def == other
86
+ value == other
87
+ end
88
+
89
+ def / other
90
+ value / other
91
+ end
92
+
93
+ def [] other
94
+ value[other]
95
+ end
96
+
97
+ def p
98
+ value.p
99
+ end
100
+
101
+ def to_s
102
+ value.to_s
103
+ end
104
+
105
+ def to_str
106
+ if !value.respond_to?(:to_str)
107
+ raise TypeError, "Can't coerce #{value}:#{value.class.name} into a String"
108
+ else
109
+ value.to_str
110
+ end
111
+ end
112
+
113
+ def inspect
114
+ "#<Babushka::Parameter:#{object_id} #{description}>"
115
+ end
116
+
117
+ def description
118
+ if @value
119
+ "#{name}: #{@value.inspect}"
120
+ elsif @default_bang
121
+ "#{name}: [default!: #{@default_bang.inspect}]"
122
+ elsif @default
123
+ "#{name}: [default: #{@default.inspect}]"
124
+ else
125
+ "#{name}: [unset]"
126
+ end
127
+ end
128
+
129
+ private
130
+
131
+ def value
132
+ @value ||= @default_bang || Prompt.get_value((@ask || name).to_s, prompt_opts)
133
+ end
134
+
135
+ def prompt_opts
136
+ {}.tap {|hsh|
137
+ hsh[:default] = @default unless @default.nil?
138
+ hsh[:choices] = @choose if @choose.is_a?(Array)
139
+ hsh[:choice_descriptions] = @choose if @choose.is_a?(Hash)
140
+ }
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,81 @@
1
+ module Babushka
2
+ class PkgHelper
3
+ class << self
4
+ include LogHelpers
5
+ include ShellHelpers
6
+ include VersionOf::Helpers
7
+
8
+ def pkg_binary; pkg_cmd end
9
+
10
+ def all_manager_keys
11
+ [:apt, :brew, :macports, :yum, :binpkgsrc, :binports]
12
+ end
13
+
14
+ def manager_dep
15
+ manager_key.to_s
16
+ end
17
+
18
+ def has? pkg, opts = {}
19
+ pkg = VersionOf(pkg)
20
+ _has?(pkg).tap {|matching_version|
21
+ matching_pkg = VersionOf(pkg.name, (matching_version if matching_version.is_a?(VersionStr)))
22
+ unless opts[:log] == false
23
+ log "system #{matching_version ? "has" : "doesn't have"} #{matching_pkg} #{pkg_type}", :as => (:ok if matching_version)
24
+ end
25
+ }
26
+ end
27
+ def install! pkgs, opts = nil
28
+ _install! [*pkgs].map {|pkg| VersionOf(pkg) }, opts
29
+ end
30
+ def _install! pkgs, opts
31
+ log_shell "Installing #{pkgs.to_list} via #{manager_key}", "#{pkg_cmd} -y install #{pkgs.join(' ')} #{opts}", :sudo => should_sudo?
32
+ end
33
+ def prefix
34
+ cmd_dir(pkg_binary).p.dir
35
+ end
36
+ def bin_path
37
+ prefix / 'bin'
38
+ end
39
+ def present?
40
+ which pkg_binary
41
+ end
42
+ def cmd_in_path? cmd_name
43
+ if (_cmd_dir = cmd_dir(cmd_name)).nil?
44
+ log_error "The '#{cmd_name}' command is not available. You probably need to add #{bin_path} to your PATH."
45
+ else
46
+ _cmd_dir.starts_with?(prefix)
47
+ end
48
+ end
49
+ def should_sudo?
50
+ !File.writable?(bin_path)
51
+ end
52
+
53
+ def update_pkg_lists_if_required
54
+ if pkg_update_timeout.nil?
55
+ true # not required
56
+ else
57
+ list_age = Time.now - pkg_list_dir.mtime
58
+ if list_age > pkg_update_timeout
59
+ update_pkg_lists "#{manager_dep.capitalize} package lists are #{list_age.round.xsecs} old. Updating"
60
+ else
61
+ debug "#{manager_dep.capitalize} package lists are #{list_age.round.xsecs} old (up to date)."
62
+ true # up to date
63
+ end
64
+ end
65
+ end
66
+ def update_pkg_lists message = "Updating #{manager_dep.capitalize} package lists"
67
+ log_shell message, pkg_update_command, :sudo => should_sudo?
68
+ end
69
+ def pkg_update_timeout
70
+ nil # not required by default
71
+ end
72
+ def pkg_update_command
73
+ "#{pkg_cmd} update"
74
+ end
75
+
76
+ def cmdline_spec_for pkg
77
+ "#{pkg.name}#{" --version '#{pkg.version}'" unless pkg.version.nil?}"
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,61 @@
1
+ module Babushka
2
+ class AptHelper < PkgHelper
3
+ class << self
4
+ def pkg_type; :deb end
5
+ def pkg_cmd; "env DEBCONF_TERSE='yes' DEBIAN_PRIORITY='critical' DEBIAN_FRONTEND='noninteractive' #{pkg_binary}" end
6
+ def pkg_binary
7
+ @_cached_pkg_binary ||= which('aptitude') ? 'aptitude' : 'apt-get'
8
+ end
9
+ def manager_key; :apt end
10
+
11
+ def _install! pkgs, opts
12
+ wait_for_dpkg
13
+ log_shell "Downloading", "#{pkg_cmd} -y -d install #{pkgs.join(' ')}", :sudo => should_sudo?
14
+ super
15
+ end
16
+
17
+ def update_pkg_lists_if_required
18
+ wait_for_dpkg
19
+ if !File.exists? '/var/lib/apt/lists/lock'
20
+ update_pkg_lists "Looks like apt hasn't been used on this system yet. Updating"
21
+ else
22
+ super
23
+ end
24
+ end
25
+
26
+ def source_for_system
27
+ {
28
+ :debian => 'http://archive.debian.org/debian',
29
+ :ubuntu => 'http://archive.ubuntu.com/ubuntu'
30
+ }[Base.host.flavour]
31
+ end
32
+
33
+ private
34
+ def _has? pkg_name
35
+ wait_for_dpkg
36
+ status = raw_shell("dpkg -s #{pkg_name}").stdout.val_for('Status')
37
+ status && status.split(' ').include?('installed')
38
+ end
39
+
40
+ def pkg_update_timeout
41
+ 3600 * 24 # 1 day
42
+ end
43
+ def pkg_list_dir
44
+ '/var/lib/apt/lists'.p
45
+ end
46
+
47
+ def wait_for_dpkg
48
+ if dpkg_locked?
49
+ log_block "Looks like dpkg is already in use - waiting" do
50
+ sleep 1 while dpkg_locked?
51
+ true
52
+ end
53
+ end
54
+ end
55
+
56
+ def dpkg_locked?
57
+ which('fuser') and raw_shell('fuser -v /var/lib/dpkg/lock').stderr[/\bF..../]
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,19 @@
1
+ module Babushka
2
+ class BaseHelper < PkgHelper
3
+ class << self
4
+ def pkg_type; :unknown end
5
+ def manager_key; :unknown end
6
+ def manager_dep; nil end
7
+
8
+ private
9
+
10
+ def _install! pkgs, opts
11
+ raise DepDefiner::UnmeetableDep, "I don't know how to use the package manager on this system."
12
+ end
13
+
14
+ def _has? pkg
15
+ raise DepDefiner::UnmeetableDep, "I don't know how to use the package manager on this system."
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,48 @@
1
+ module Babushka
2
+ class BinPkgSrcHelper < PkgHelper
3
+ class << self
4
+ def existing_packages
5
+ shell("pkg_info -a").lines.to_a.map {|i| i.split(/\s+/)[0] }
6
+ end
7
+
8
+ # Note that with pkg_radd it is possible to override the default
9
+ # repository using PKG_PATH environment variable. See man 1 pkg_add.
10
+
11
+ def pkg_binary; 'pkg_radd' end
12
+ def pkg_cmd; pkg_binary end
13
+ def pkg_type; :pkg end
14
+ def manager_key; :binpkgsrc end
15
+
16
+ def update_pkg_lists_if_required
17
+ if !File.exists? pkg_list_dir
18
+ update_pkg_lists "Looks like pkg summary hasn't been fetched on this system yet. Updating"
19
+ else
20
+ super
21
+ end
22
+ end
23
+
24
+ def pkg_update_timeout
25
+ 3600 * 24 * 14 # 2 weeks
26
+ end
27
+
28
+ def pkg_list_dir
29
+ '/usr/pkgsrc/pkg_summary'.p
30
+ end
31
+
32
+ def pkg_update_command
33
+ "pkg_search -d"
34
+ end
35
+
36
+ def _install! pkgs, opts
37
+ log_shell "Installing #{pkgs.join(', ')}", "pkg_radd #{pkgs.join(' ')}", :sudo => should_sudo?
38
+ end
39
+
40
+ private
41
+
42
+ def _has? pkg
43
+ existing_packages.any? {|i| i.match(/#{pkg}/)}
44
+ end
45
+
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,34 @@
1
+ module Babushka
2
+ class BinPortsHelper < PkgHelper
3
+ class << self
4
+ def existing_packages
5
+ shell("pkg_info").lines.to_a.map {|i| i.split(/\s+/)[0] }
6
+ end
7
+
8
+ # Regarding FreeBSD binary packages the following should be noted:
9
+ # pkg_add uses PACKAGESITE and PACKAGEROOT environment variables
10
+ # to calculate the URL to download packages from.
11
+ #
12
+ # If you're using outdated FreeBSD RELEASE branch (like 6.2-release)
13
+ # that does not have anymore it's public package repository, please
14
+ # either consider to move to the STABLE one (like 6-release)
15
+ # or set PACKAGESITE var to point to appropriate package repository.
16
+
17
+ def pkg_binary; 'pkg_add' end
18
+ def pkg_cmd; "#{pkg_binary} -r" end
19
+ def pkg_type; :tbz end
20
+ def manager_key; :binports end
21
+
22
+ private
23
+
24
+ def _install! pkgs, opts
25
+ log_shell "Installing #{pkgs.join(', ')}", "#{pkg_cmd} #{pkgs.join(' ')}", :sudo => should_sudo?
26
+ end
27
+
28
+ def _has? pkg
29
+ existing_packages.any? {|i| i.match(/#{pkg}/)}
30
+ end
31
+
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,110 @@
1
+ module Babushka
2
+ class BrewHelper < PkgHelper
3
+ class << self
4
+ def pkg_type; :brew end
5
+ def pkg_cmd; 'brew' end
6
+ def manager_key; :brew end
7
+ def manager_dep; 'homebrew' end
8
+
9
+ def _install! pkgs, opts
10
+ check_for_formulas(pkgs) && pkgs.all? {|pkg|
11
+ log "Installing #{pkg} via #{manager_key}" do
12
+ shell(
13
+ "#{pkg_cmd} install #{cmdline_spec_for pkg} #{opts}",
14
+ :sudo => should_sudo?,
15
+ :log => true,
16
+ :closing_status => :status_only
17
+ )
18
+ end
19
+ }
20
+ end
21
+
22
+ def update_pkg_lists_if_required
23
+ super.tap {|result|
24
+ pkg_list_dir.touch if result
25
+ }
26
+ end
27
+
28
+ def brew_path_for pkg_name
29
+ if active_version = active_version_of(pkg_name)
30
+ installed_pkgs_path / pkg_name / active_version
31
+ end
32
+ end
33
+
34
+ def should_sudo?
35
+ super || !installed_pkgs_path.hypothetically_writable?
36
+ end
37
+
38
+
39
+ private
40
+
41
+ class LibraryDep
42
+ attr_reader :names
43
+ def initialize *names
44
+ @names = names
45
+ end
46
+ end
47
+
48
+ def _has? pkg
49
+ versions_of(pkg).sort.reverse.detect {|version| pkg.matches? version }
50
+ end
51
+
52
+ def check_for_formulas pkgs
53
+ pkgs.all? {|pkg|
54
+ has_formula_for?(pkg).tap {|result|
55
+ log_error "There is no formula for '#{pkg}' in #{formulas_path}." unless result
56
+ }
57
+ }
58
+ end
59
+
60
+ def has_formula_for? pkg
61
+ existing_formulas.include? pkg.name
62
+ end
63
+
64
+ def existing_formulas
65
+ Dir[formulas_path / '*.rb'].map {|i| File.basename i, '.rb' }
66
+ end
67
+
68
+ def active_version_of pkg_name
69
+ shell("brew info #{pkg_name}").split("\n\n", 2).first.split("\n").map {|i|
70
+ i.scan(/^#{Regexp.escape(installed_pkgs_path.to_s.end_with('/'))}([^\s]+)/)
71
+ }.flatten.select {|i|
72
+ i[/\d/] # For it to be a version, it has to have at least 1 digit.
73
+ }.map {|i|
74
+ VersionOf i.split('/', 2)
75
+ }.max.version
76
+ end
77
+
78
+ def versions_of pkg
79
+ pkg_name = pkg.respond_to?(:name) ? pkg.name : pkg
80
+ Dir[
81
+ installed_pkgs_path / pkg_name / '*'
82
+ ].map {|i|
83
+ File.basename i.chomp('/')
84
+ }.reject {|i|
85
+ i[/\d|HEAD/].nil? # reject paths that aren't versions, like 'bin' etc
86
+ }.map(&:to_version)
87
+ end
88
+
89
+ def pkg_update_timeout
90
+ 3600 # 1 hour
91
+ end
92
+ def pkg_list_dir
93
+ prefix
94
+ end
95
+
96
+ def installed_pkgs_path
97
+ prefix / 'Cellar'
98
+ end
99
+ def formulas_path
100
+ prefix / 'Library/Formula'
101
+ end
102
+ def formula_path_for pkg
103
+ formulas_path / pkg.to_s.end_with('.rb')
104
+ end
105
+ def homebrew_lib_path
106
+ prefix / 'Library/Homebrew'
107
+ end
108
+ end
109
+ end
110
+ end