rubycut-babushka 0.10.6

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