omnibus 5.0.0 → 5.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +2 -0
  3. data/.travis.yml +1 -0
  4. data/CHANGELOG.md +26 -0
  5. data/Gemfile +3 -0
  6. data/MAINTAINERS.md +1 -0
  7. data/appveyor.yml +1 -1
  8. data/bin/omnibus +5 -0
  9. data/lib/omnibus/builder.rb +165 -26
  10. data/lib/omnibus/digestable.rb +4 -2
  11. data/lib/omnibus/fetcher.rb +18 -5
  12. data/lib/omnibus/fetchers/git_fetcher.rb +38 -22
  13. data/lib/omnibus/fetchers/net_fetcher.rb +106 -37
  14. data/lib/omnibus/fetchers/path_fetcher.rb +13 -12
  15. data/lib/omnibus/file_syncer.rb +33 -14
  16. data/lib/omnibus/generator_files/README.md.erb +1 -1
  17. data/lib/omnibus/generator_files/package_scripts/postinst.erb +3 -3
  18. data/lib/omnibus/generator_files/package_scripts/postrm.erb +1 -1
  19. data/lib/omnibus/generator_files/package_scripts/preinst.erb +1 -1
  20. data/lib/omnibus/generator_files/package_scripts/prerm.erb +3 -3
  21. data/lib/omnibus/git_cache.rb +20 -7
  22. data/lib/omnibus/health_check.rb +144 -12
  23. data/lib/omnibus/packagers/bff.rb +57 -5
  24. data/lib/omnibus/packagers/deb.rb +2 -2
  25. data/lib/omnibus/packagers/pkg.rb +2 -2
  26. data/lib/omnibus/packagers/solaris.rb +18 -6
  27. data/lib/omnibus/project.rb +1 -1
  28. data/lib/omnibus/s3_cache.rb +8 -2
  29. data/lib/omnibus/software.rb +152 -18
  30. data/lib/omnibus/sugarable.rb +1 -5
  31. data/lib/omnibus/util.rb +1 -1
  32. data/lib/omnibus/version.rb +1 -1
  33. data/omnibus.gemspec +4 -1
  34. data/resources/bff/config.erb +7 -0
  35. data/resources/deb/md5sums.erb +1 -1
  36. data/spec/functional/builder_spec.rb +89 -2
  37. data/spec/functional/fetchers/git_fetcher_spec.rb +44 -37
  38. data/spec/functional/fetchers/net_fetcher_spec.rb +36 -5
  39. data/spec/functional/fetchers/path_fetcher_spec.rb +28 -28
  40. data/spec/unit/builder_spec.rb +143 -11
  41. data/spec/unit/fetchers/git_fetcher_spec.rb +23 -59
  42. data/spec/unit/fetchers/net_fetcher_spec.rb +151 -63
  43. data/spec/unit/fetchers/path_fetcher_spec.rb +4 -35
  44. data/spec/unit/git_cache_spec.rb +13 -14
  45. data/spec/unit/health_check_spec.rb +90 -0
  46. data/spec/unit/library_spec.rb +1 -1
  47. data/spec/unit/packagers/bff_spec.rb +126 -3
  48. data/spec/unit/packagers/deb_spec.rb +8 -3
  49. data/spec/unit/packagers/pkg_spec.rb +19 -19
  50. data/spec/unit/packagers/solaris_spec.rb +13 -1
  51. data/spec/unit/software_spec.rb +242 -38
  52. metadata +7 -6
  53. data/lib/omnibus/generator_files/package_scripts/makeselfinst.erb +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1471f1e4e874c7a6d1146332f02e3a2b01ce2b47
4
- data.tar.gz: 15c244b4ee8b8814058f17eecec80ff44b08337f
3
+ metadata.gz: d6c6004b5090f1bef33eea64eec8e741fef4af4d
4
+ data.tar.gz: 540e7c85bff51d2e8865325d388e08260be11b98
5
5
  SHA512:
6
- metadata.gz: 186d0842eb7d493a482f3c661f9248d155db72c58dd8797a160c13900ba01fe7ce893c645bccfe981e922602f023f0e1261114405ddf9e303d169978bccd539f
7
- data.tar.gz: 5be67f512343718da2c35bbbc6c18c1e7f0e67fff96a3d3a2b25a7ef5d67706a4b1f9398883e1d28be87529f6a544f63dc3b0ee8d567411135c7663efda38ca6
6
+ metadata.gz: 3d4e0d40424b6e0e5d2ebbaa0fa411fe9435bde23c508dfa22e84a10337153415e6467c9c40a41cfed138c9cb1ec77660c19a211fe491e8d9839cf83e587a358
7
+ data.tar.gz: a6d063e1f4772956aa11a0264d5a06611b6de49ea184cc4a89aa0296a1c0cc02be3b21e721270b31730e9ccadff4578dca5edc0df60f5d10e91d77afc24b5efc
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ -fd
@@ -8,6 +8,7 @@ branches:
8
8
  - 2.0-stable
9
9
  - 3.0-stable
10
10
  - master
11
+ before_install: gem install bundler
11
12
  script: bundle exec rake travis:ci
12
13
  notifications:
13
14
  slack:
@@ -1,6 +1,32 @@
1
1
  Omnibus CHANGELOG
2
2
  =================
3
3
 
4
+ v5.1.0 (March 10, 2016)
5
+ -----------------------
6
+ ### New Features
7
+ - New `configure` dsl method. (#572)
8
+ - New `maintainer` dsl method. (#618)
9
+ - New `update_config_guess` dsl method. (#632)
10
+ - Ability to enable building software components from source on windows. (#572, #583, #584, #586, #612)
11
+
12
+ ### Bug Fixes
13
+ - Default to UTF-8 external encoding globally. (#573)
14
+ - Restore invalid file names on AIX. (#575)
15
+ - Fix bff log loop. (#579)
16
+ - Use 7z.exe instead of tar.exe on windows. (#578)
17
+ - Make generated package scripts old-school Unix friendly. (#582)
18
+ - Fix directory cleanup logic in `git_fetcher`. (#509)
19
+ - Use -O2 when building with standard compiler flags. (#591)
20
+ - Cache software sources under `.../src/<software name>/<package>`. (#597)
21
+ - Add libmd.so.* to freebsd whitelist. (#600)
22
+ - Remove existing links in the destination when syncing files. (#602)
23
+ - Skip adding DEBIAN directory to md5sums file. (#595)
24
+ - Autoprunes files with spaces on Solaris. (#609)
25
+ - Allow assets with non-md5 checksums to be cached in s3. (#611)
26
+ - Print NetFetcher retries at the info level. (#614)
27
+ - Do not modify CRLF when git caching. (#616)
28
+ - Ensure we always swap chown back to default. (#617)
29
+
4
30
  v5.0.0 (November 10, 2015)
5
31
  --------------------------
6
32
  ### New Features
data/Gemfile CHANGED
@@ -1,6 +1,9 @@
1
1
  source 'https://rubygems.org'
2
2
  gemspec
3
3
 
4
+ # Fork to allow for a recent version of multipart-post.
5
+ gem 'pedump', git: 'https://github.com/ksubrama/pedump', branch: 'patch-1'
6
+
4
7
  group :docs do
5
8
  gem 'yard', '~> 0.8'
6
9
  gem 'redcarpet', '~> 2.2.2'
@@ -25,3 +25,4 @@ project lead.
25
25
  * [Steven Danna](https://github.com/stevendanna)
26
26
  * [Yvonne Lam](http://github.com/yzl)
27
27
  * [Thom May](https://github.com/thommay)
28
+ * [Kartik Null Cating-Subramanian](https://github.com/ksubrama)
@@ -20,7 +20,7 @@ install:
20
20
  - echo %PATH%
21
21
  - ruby --version
22
22
  - gem --version
23
- - gem install bundler --quiet --no-ri --no-rdoc
23
+ - gem install bundler -v 1.10.6 --quiet --no-ri --no-rdoc
24
24
  - bundler --version
25
25
  - cp C:\Ruby21%ruby_version:~3%\Devkit\mingw\bin\bsdtar.exe C:\Ruby21%ruby_version:~3%\Devkit\mingw\bin\tar.exe
26
26
  - appveyor DownloadFile http://curl.haxx.se/ca/cacert.pem -FileName C:\cacert.pem
@@ -8,4 +8,9 @@ $:.push File.expand_path('../../lib', __FILE__)
8
8
  $stdout.sync = true
9
9
 
10
10
  require 'omnibus/cli'
11
+
12
+ # Some platforms do not have a UTF-8 locale, so we need to enforce one
13
+ # or else the cacert chain will break among other things
14
+ Encoding.default_external = Encoding::UTF_8
15
+
11
16
  Omnibus::CLI::Runner.new(ARGV.dup).execute!
@@ -91,6 +91,9 @@ module Omnibus
91
91
  # use of +gmake+ over +make+. If applicable, this method will also set
92
92
  # the `MAKE=gmake` environment variable when gmake is to be preferred.
93
93
  #
94
+ # On windows you need to have the msys-base package (or some equivalent)
95
+ # before you can invoke this.
96
+ #
94
97
  # @example With no arguments
95
98
  # make
96
99
  #
@@ -105,27 +108,87 @@ module Omnibus
105
108
  #
106
109
  def make(*args)
107
110
  options = args.last.is_a?(Hash) ? args.pop : {}
108
- command = args.join(' ')
109
111
 
110
- make = if makebin = options.delete(:bin)
111
- makebin
112
- elsif Omnibus.which('gmake')
113
- env = options.delete(:env) || {}
114
- env = { 'MAKE' => 'gmake' }.merge(env)
115
- options[:env] = env
116
- 'gmake'
117
- else
118
- 'make'
119
- end
112
+ make = options.delete(:bin) ||
113
+ # Prefer gmake on non-windows environments.
114
+ if !windows? && Omnibus.which('gmake')
115
+ env = options.delete(:env) || {}
116
+ env = { 'MAKE' => 'gmake' }.merge(env)
117
+ options[:env] = env
118
+ 'gmake'
119
+ else
120
+ 'make'
121
+ end
120
122
 
121
- command("#{make} #{command}".strip, options)
123
+ options[:in_msys_bash] = true
124
+ make_cmd = ([make] + args).join(' ').strip
125
+ command(make_cmd, options)
122
126
  end
123
127
  expose :make
124
128
 
129
+ # Run a prexisting "./configure" script that was generated by autotools.
130
+ # On windows, this will run configure within an msys bash shell with
131
+ # the given arguments. --host is also set on your behalf based on
132
+ # windows_arch. A default prefix of "#{install_bin}/embedded" is
133
+ # appended.
134
+ #
135
+ # @example With no arguments
136
+ # configure
137
+ # On POSIX systems, this results in:
138
+ # ./configure --prefix=/path/to/embedded
139
+ # On Windows 64-bit, this results in:
140
+ # ./configure --host=x86_64-w64-mingw32 --prefix=C:/path/to/embedded
141
+ # Note that the windows case uses a windows compabile path with forward
142
+ # slashes - not an msys path. Ensure that the final Makefile is happy
143
+ # with this and doesn't perform path gymnastics on it. Don't pass
144
+ # \\ paths unless you particularly enjoy discovering exactly home many
145
+ # times configure and the Makefile it generates sends your path back
146
+ # and forth through bash/sh, mingw32 native binaries and msys binaries
147
+ # and how many backslashes it takes for you to quit software development.
148
+ #
149
+ # @example With custom arguments
150
+ # configure '--enable-shared'
151
+ #
152
+ # @example With custom location of configure bin
153
+ # configure '--enable-shared', bin: '../foo/configure'
154
+ # The path to configure must be a "unix-y" path for both windows and posix
155
+ # as this path is run under an msys bash shell on windows. Prefer relative
156
+ # paths lest you incur the wrath of the msys path gods for they are not
157
+ # kind, just or benevolent.
158
+ #
159
+ # @param (see #command)
160
+ # @return (see #command)
161
+ #
162
+ def configure(*args)
163
+ options = args.last.is_a?(Hash) ? args.pop : {}
164
+
165
+ configure = options.delete(:bin) || './configure'
166
+ configure_cmd = [configure]
167
+
168
+ # Pass the host platform as well. msys is configured for 32-bits even
169
+ # if the actual installed compiler has 64-bit support.
170
+ configure_cmd << '--host=x86_64-w64-mingw32' if windows? && !windows_arch_i386?
171
+
172
+ # Accept a prefix override if provided. Can be set to '' to suppress
173
+ # this functionality.
174
+ prefix = options.delete(:prefix) || "#{install_dir}/embedded"
175
+ configure_cmd << "--prefix=#{prefix}" if prefix && prefix != ''
176
+
177
+ configure_cmd.concat args
178
+ configure_cmd = configure_cmd.join(' ').strip
179
+
180
+ options[:in_msys_bash] = true
181
+ command(configure_cmd, options)
182
+ end
183
+ expose :configure
184
+
125
185
  #
126
186
  # Apply the patch by the given name. This method will search all possible
127
187
  # locations for a patch (such as {Config#software_gems}).
128
188
  #
189
+ # On windows, you must have the the patch package installed before you can
190
+ # invoke this.
191
+ #
129
192
  # @example
130
193
  # patch source: 'ncurses-clang.patch'
131
194
  #
@@ -155,19 +218,26 @@ module Omnibus
155
218
  raise MissingPatch.new(source, locations)
156
219
  end
157
220
 
158
- # Apply patches nicely on Windows
159
- patch_path = windows_safe_path(patch_path)
221
+ # Using absolute paths to the patch when invoking patch from within msys
222
+ # is going to end is tears and table-flips. Use relative paths instead.
223
+ # It's windows - we don't reasonably expect symlinks to show up any-time
224
+ # soon and if you're using junction points, you're on your own.
225
+ clean_patch_path = patch_path
226
+ if windows?
227
+ clean_patch_path = Pathname.new(patch_path).relative_path_from(
228
+ Pathname.new(software.project_dir)).to_s
229
+ end
160
230
 
161
231
  if target
162
- command = "cat #{patch_path} | patch -p#{plevel} #{target}"
232
+ patch_cmd = "cat #{clean_patch_path} | patch -p#{plevel} #{target}"
163
233
  else
164
- command = "patch -d #{software.project_dir} -p#{plevel} -i #{patch_path}"
234
+ patch_cmd = "patch -p#{plevel} -i #{clean_patch_path}"
165
235
  end
166
236
 
167
237
  patches << patch_path
168
-
238
+ options[:in_msys_bash] = true
169
239
  build_commands << BuildCommand.new("Apply patch `#{source}'") do
170
- shellout!(command, options)
240
+ shellout!(patch_cmd, options)
171
241
  end
172
242
  end
173
243
  expose :patch
@@ -218,7 +288,7 @@ module Omnibus
218
288
  #
219
289
  def ruby(command, options = {})
220
290
  build_commands << BuildCommand.new("ruby `#{command}'") do
221
- bin = windows_safe_path("#{install_dir}/embedded/bin/ruby")
291
+ bin = embedded_bin('ruby')
222
292
  shellout!("#{bin} #{command}", options)
223
293
  end
224
294
  end
@@ -235,7 +305,7 @@ module Omnibus
235
305
  #
236
306
  def gem(command, options = {})
237
307
  build_commands << BuildCommand.new("gem `#{command}'") do
238
- bin = windows_safe_path("#{install_dir}/embedded/bin/gem")
308
+ bin = embedded_bin('gem')
239
309
  shellout!("#{bin} #{command}", options)
240
310
  end
241
311
  end
@@ -255,7 +325,7 @@ module Omnibus
255
325
  #
256
326
  def bundle(command, options = {})
257
327
  build_commands << BuildCommand.new("bundle `#{command}'") do
258
- bin = windows_safe_path("#{install_dir}/embedded/bin/bundle")
328
+ bin = embedded_bin('bundle')
259
329
  shellout!("#{bin} #{command}", options)
260
330
  end
261
331
  end
@@ -270,18 +340,26 @@ module Omnibus
270
340
  # @example
271
341
  # appbundle 'chef'
272
342
  #
343
+ # @param software_name [String]
344
+ # The omnibus software definition name that you want to appbundle. We
345
+ # assume that this software definition is a gem that already has `bundle
346
+ # install` ran on it so it has a Gemfile.lock to appbundle.
273
347
  # @param (see #command)
274
348
  # @return (see #command)
275
349
  #
276
- def appbundle(app_name, options = {})
277
- build_commands << BuildCommand.new("appbundle `#{app_name}'") do
350
+ def appbundle(software_name, options = {})
351
+ build_commands << BuildCommand.new("appbundle `#{software_name}'") do
352
+ app_software = project.softwares.find do |p|
353
+ p.name == software_name
354
+ end
355
+
278
356
  bin_dir = "#{install_dir}/bin"
279
- appbundler_bin = windows_safe_path("#{install_dir}/embedded/bin/appbundler")
357
+ appbundler_bin = embedded_bin('appbundler')
280
358
 
281
359
  # Ensure the main bin dir exists
282
360
  FileUtils.mkdir_p(bin_dir)
283
361
 
284
- shellout!("#{appbundler_bin} '#{Omnibus::Config.source_dir}/#{app_name}' '#{bin_dir}'", options)
362
+ shellout!("#{appbundler_bin} '#{app_software.project_dir}' '#{bin_dir}'", options)
285
363
  end
286
364
  end
287
365
  expose :appbundle
@@ -298,7 +376,7 @@ module Omnibus
298
376
  #
299
377
  def rake(command, options = {})
300
378
  build_commands << BuildCommand.new("rake `#{command}'") do
301
- bin = windows_safe_path("#{install_dir}/embedded/bin/rake")
379
+ bin = embedded_bin('rake')
302
380
  shellout!("#{bin} #{command}", options)
303
381
  end
304
382
  end
@@ -565,6 +643,35 @@ module Omnibus
565
643
  end
566
644
  expose :sync
567
645
 
646
+ #
647
+ # Helper method to update config_guess in the software's source
648
+ # directory.
649
+ # You should add a dependency on the +config_guess+ software definition if you
650
+ # want to use this command.
651
+ # @param [Hash] options
652
+ # Supported options are:
653
+ # target [String] subdirectory under the software source to copy
654
+ # config.guess.to. Default: "."
655
+ # install [Array<Symbol>] parts of config.guess to copy.
656
+ # Default: [:config_guess, :config_sub]
657
+ def update_config_guess(target: ".", install: [:config_guess, :config_sub])
658
+ build_commands << BuildCommand.new("update_config_guess `target: #{target} install: #{install.inspect}'") do
659
+ config_guess_dir = "#{install_dir}/embedded/lib/config_guess"
660
+ %w{config.guess config.sub}.each do |c|
661
+ unless File.exist?(File.join(config_guess_dir, c))
662
+ raise "Can not find #{c}. Make sure you add a dependency on 'config_guess' in your software definition"
663
+ end
664
+ end
665
+
666
+ destination = File.join(software.project_dir, target)
667
+ FileUtils.mkdir_p(destination)
668
+
669
+ FileUtils.cp_r("#{config_guess_dir}/config.guess", destination) if install.include? :config_guess
670
+ FileUtils.cp_r("#{config_guess_dir}/config.sub", destination) if install.include? :config_sub
671
+ end
672
+ end
673
+ expose :update_config_guess
674
+
568
675
  #
569
676
  # @!endgroup
570
677
  # --------------------------------------------------
@@ -637,6 +744,14 @@ module Omnibus
637
744
 
638
745
  private
639
746
 
747
+ def embedded_bin(bin)
748
+ windows_safe_path("#{install_dir}/embedded/bin/#{bin}")
749
+ end
750
+
751
+ def embedded_msys_bin(bin)
752
+ windows_safe_path("#{install_dir}/embedded/msys/1.0/bin/#{bin}")
753
+ end
754
+
640
755
  #
641
756
  # The **in-order** list of {BuildCommand} for this builder.
642
757
  #
@@ -670,12 +785,36 @@ module Omnibus
670
785
  # This is a helper method that wraps {Util#shellout!} for the purposes of
671
786
  # setting the +:cwd+ value.
672
787
  #
788
+ # It also accepts an :in_msys_bash option which controls whether the
789
+ # given command is wrapped and run with bash.exe -c on windows.
790
+ #
673
791
  # @see (Util#shellout!)
674
792
  #
675
793
  def shellout!(command_string, options = {})
676
794
  # Make sure the PWD is set to the correct directory
795
+ # Also make a clone of options so that we can mangle it safely below.
677
796
  options = { cwd: software.project_dir }.merge(options)
678
797
 
798
+ if options.delete(:in_msys_bash) && windows?
799
+ # The command needs to be run within an msys bash environment.
800
+ # TODO: Eventually, have command search through "build time dependencies"
801
+ # for bash instead.
802
+ bash_bin = embedded_msys_bin('bash.exe')
803
+ unless File.exist?(bash_bin)
804
+ # Fallback to just looking at the embedded_bin directory in case
805
+ # we're using devkit or older chef-dk.
806
+ bash_bin = embedded_bin('bash.exe')
807
+ unless File.exist?(bash_bin)
808
+ bash_bin = "bash.exe"
809
+ end
810
+ end
811
+ # Mixlib will handle escaping characters for cmd but our command might
812
+ # contain '. For now, assume that won't happen because I don't know
813
+ # whether this command is going to be played via cmd or through
814
+ # ProcessCreate.
815
+ command_string = "\"#{bash_bin}\" -c \'#{command_string}\'"
816
+ end
817
+
679
818
  # Set the log level to :info so users will see build commands
680
819
  options[:log_level] ||= :info
681
820
 
@@ -62,14 +62,16 @@ module Omnibus
62
62
  # the path of the directory to digest
63
63
  # @param [Symbol] type
64
64
  # the type of digest to use
65
+ # @param [Hash] options
66
+ # options to pass through to the FileSyncer when scanning for files
65
67
  #
66
68
  # @return [String]
67
69
  # the hexdigest of the directory
68
70
  #
69
- def digest_directory(path, type = :md5)
71
+ def digest_directory(path, type = :md5, options = {})
70
72
  digest = digest_from_type(type)
71
73
  log.info(log_key) { "Digesting #{path} with #{type}" }
72
- FileSyncer.glob("#{path}/**/*").each do |filename|
74
+ FileSyncer.all_files_under(path, options).each do |filename|
73
75
  # Calculate the filename relative to the given path. Since directories
74
76
  # are SHAed according to their filepath, two difference directories on
75
77
  # disk would have different SHAs even if they had the same content.
@@ -55,7 +55,17 @@ module Omnibus
55
55
  attr_reader :described_version
56
56
 
57
57
  #
58
- # The path where extracted software should live.
58
+ # The path where fetched software should live.
59
+ #
60
+ # Only files under this directory are modified. If the source to fetch
61
+ # is a directory, it is staged rooted here. If it's a file, it's copied
62
+ # underneath this directory. If it's a tarball, it's extracted here. If
63
+ # it's a repo, its checkout is rooted here. You get the idea.
64
+ #
65
+ # It's named project_dir instead of extract_dir/extract_path because of
66
+ # legacy reasons. This has nothing to do with project definitions or the
67
+ # underlying relative_path for a software definition (except for legacy
68
+ # behavior).
59
69
  #
60
70
  # @return [String]
61
71
  #
@@ -66,11 +76,14 @@ module Omnibus
66
76
  #
67
77
  # Create a new Fetcher object from the given software.
68
78
  #
69
- # @param [Software] software
79
+ # The parameters correspond to the relevant portions of a software
80
+ # definition that a fetcher needs access to. This avoids strongly coupling
81
+ # the software object with all fetchers.
82
+ #
83
+ # @param [ManifestEntry] manifest_entry
84
+ # @param [String] project_dir
85
+ # @param [String] build_dir
70
86
  #
71
- # To preserve the original interface, this still takes a software-like
72
- # argument, but to avoid coupling with the software object, we pull out
73
- # what we need and don't touch it again.
74
87
  def initialize(manifest_entry, project_dir, build_dir)
75
88
  @name = manifest_entry.name
76
89
  @source = manifest_entry.locked_source
@@ -23,7 +23,7 @@ module Omnibus
23
23
  # @return [true, false]
24
24
  #
25
25
  def fetch_required?
26
- !(cloned? && same_revision?(resolved_version))
26
+ !(cloned? && contains_revision?(resolved_version))
27
27
  end
28
28
 
29
29
  #
@@ -37,19 +37,19 @@ module Omnibus
37
37
  end
38
38
 
39
39
  #
40
- # Clean the project directory by removing the contents from disk.
40
+ # Clean the project directory by resetting the current working tree to
41
+ # the required revision.
41
42
  #
42
43
  # @return [true, false]
43
- # true if the project directory was removed, false otherwise
44
+ # true if the project directory was cleaned, false otherwise.
45
+ # In our case, we always return true because we always call
46
+ # git checkout/clean.
44
47
  #
45
48
  def clean
46
- if cloned?
47
- log.info(log_key) { 'Cleaning existing clone' }
48
- git('clean -fdx')
49
- true
50
- else
51
- false
52
- end
49
+ log.info(log_key) { 'Cleaning existing clone' }
50
+ git_checkout
51
+ git('clean -fdx')
52
+ true
53
53
  end
54
54
 
55
55
  #
@@ -62,22 +62,30 @@ module Omnibus
62
62
  create_required_directories
63
63
 
64
64
  if cloned?
65
- git_fetch unless same_revision?(resolved_version)
65
+ git_fetch
66
66
  else
67
67
  force_recreate_project_dir! unless dir_empty?(project_dir)
68
68
  git_clone
69
- git_checkout
70
69
  end
71
70
  end
72
71
 
73
72
  #
74
- # The version for this item in the cache. The is the parsed revision of the
75
- # item on disk.
73
+ # The version for this item in the cache.
74
+ #
75
+ # This method is called *before* clean but *after* fetch. Do not ever
76
+ # use the contents of the project_dir here.
77
+ #
78
+ # We aren't including the source/repo path here as there could be
79
+ # multiple branches/tags that all point to the same commit. We're
80
+ # assuming that we won't realistically ever get two git commits
81
+ # that are unique but share sha1s.
82
+ #
83
+ # TODO: Does this work with submodules?
76
84
  #
77
85
  # @return [String]
78
86
  #
79
87
  def version_for_cache
80
- "revision:#{current_revision}"
88
+ "revision:#{resolved_version}"
81
89
  end
82
90
 
83
91
  private
@@ -142,7 +150,10 @@ module Omnibus
142
150
  # @return [void]
143
151
  #
144
152
  def git_checkout
145
- git("checkout #{resolved_version}")
153
+ # We are hoping to perform a checkout with detached HEAD (that's the
154
+ # default when a sha1 is provided). git older than 1.7.5 doesn't
155
+ # support the --detach flag.
156
+ git("checkout #{resolved_version} -f -q")
146
157
  end
147
158
 
148
159
  #
@@ -154,7 +165,6 @@ module Omnibus
154
165
  fetch_cmd = "fetch #{source_url} #{described_version}"
155
166
  fetch_cmd << ' --recurse-submodules=on-demand' if clone_submodules?
156
167
  git(fetch_cmd)
157
- git("reset --hard #{resolved_version}")
158
168
  end
159
169
 
160
170
  #
@@ -163,18 +173,24 @@ module Omnibus
163
173
  # @return [String]
164
174
  #
165
175
  def current_revision
166
- git('rev-parse HEAD').stdout.strip
176
+ cmd = git('rev-parse HEAD')
177
+ cmd.stdout.strip
167
178
  rescue CommandFailed
179
+ log.debug(log_key) { "unable to determine current revision" }
168
180
  nil
169
181
  end
170
182
 
171
183
  #
172
- # Determine if the given revision matches the current revision.
184
+ # Check if the current clone has the requested commit id.
173
185
  #
174
186
  # @return [true, false]
175
187
  #
176
- def same_revision?(rev=resolved_version)
177
- current_revision == rev
188
+ def contains_revision?(rev)
189
+ cmd = git("cat-file -t #{rev}")
190
+ cmd.stdout.strip == 'commit'
191
+ rescue CommandFailed
192
+ log.debug(log_key) { "unable to determine presence of commit #{rev}" }
193
+ false
178
194
  end
179
195
 
180
196
  #
@@ -236,7 +252,7 @@ module Omnibus
236
252
  # allows us to return the SHA of the tagged commit for annotated
237
253
  # tags. We take care to only return exact matches in
238
254
  # process_remote_list.
239
- remote_list = shellout!("git ls-remote \"#{source[:git]}\" #{ref}*").stdout
255
+ remote_list = shellout!("git ls-remote \"#{source[:git]}\" \"#{ref}*\"").stdout
240
256
  commit_ref = dereference_annotated_tag(remote_list, ref)
241
257
 
242
258
  unless commit_ref