omnibus 5.0.0 → 5.1.0

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 (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