omnibus-sonian 1.2.0.1

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 (70) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +9 -0
  3. data/.rspec +1 -0
  4. data/.travis.yml +5 -0
  5. data/.yardopts +6 -0
  6. data/CHANGELOG.md +96 -0
  7. data/Gemfile +9 -0
  8. data/LICENSE +201 -0
  9. data/NOTICE +9 -0
  10. data/README.md +195 -0
  11. data/Rakefile +7 -0
  12. data/bin/makeself-header.sh +401 -0
  13. data/bin/makeself.sh +407 -0
  14. data/bin/omnibus +11 -0
  15. data/lib/omnibus.rb +304 -0
  16. data/lib/omnibus/artifact.rb +151 -0
  17. data/lib/omnibus/build_version.rb +285 -0
  18. data/lib/omnibus/builder.rb +328 -0
  19. data/lib/omnibus/clean_tasks.rb +30 -0
  20. data/lib/omnibus/cli.rb +35 -0
  21. data/lib/omnibus/cli/application.rb +140 -0
  22. data/lib/omnibus/cli/base.rb +118 -0
  23. data/lib/omnibus/cli/build.rb +62 -0
  24. data/lib/omnibus/cli/cache.rb +60 -0
  25. data/lib/omnibus/cli/release.rb +49 -0
  26. data/lib/omnibus/config.rb +224 -0
  27. data/lib/omnibus/exceptions.rb +143 -0
  28. data/lib/omnibus/fetcher.rb +184 -0
  29. data/lib/omnibus/fetchers.rb +22 -0
  30. data/lib/omnibus/fetchers/git_fetcher.rb +212 -0
  31. data/lib/omnibus/fetchers/net_fetcher.rb +193 -0
  32. data/lib/omnibus/fetchers/path_fetcher.rb +65 -0
  33. data/lib/omnibus/fetchers/s3_cache_fetcher.rb +42 -0
  34. data/lib/omnibus/health_check.rb +356 -0
  35. data/lib/omnibus/library.rb +62 -0
  36. data/lib/omnibus/overrides.rb +69 -0
  37. data/lib/omnibus/package_release.rb +163 -0
  38. data/lib/omnibus/project.rb +715 -0
  39. data/lib/omnibus/reports.rb +99 -0
  40. data/lib/omnibus/s3_cacher.rb +138 -0
  41. data/lib/omnibus/software.rb +441 -0
  42. data/lib/omnibus/templates/Berksfile.erb +3 -0
  43. data/lib/omnibus/templates/Gemfile.erb +4 -0
  44. data/lib/omnibus/templates/README.md.erb +102 -0
  45. data/lib/omnibus/templates/Vagrantfile.erb +95 -0
  46. data/lib/omnibus/templates/gitignore.erb +8 -0
  47. data/lib/omnibus/templates/omnibus.rb.example.erb +5 -0
  48. data/lib/omnibus/templates/package_scripts/makeselfinst.erb +27 -0
  49. data/lib/omnibus/templates/package_scripts/postinst.erb +17 -0
  50. data/lib/omnibus/templates/package_scripts/postrm.erb +9 -0
  51. data/lib/omnibus/templates/project.rb.erb +21 -0
  52. data/lib/omnibus/templates/software/c-example.rb.erb +42 -0
  53. data/lib/omnibus/templates/software/erlang-example.rb.erb +38 -0
  54. data/lib/omnibus/templates/software/ruby-example.rb.erb +24 -0
  55. data/lib/omnibus/util.rb +61 -0
  56. data/lib/omnibus/version.rb +20 -0
  57. data/omnibus.gemspec +34 -0
  58. data/spec/artifact_spec.rb +106 -0
  59. data/spec/build_version_spec.rb +266 -0
  60. data/spec/data/overrides/bad_line.overrides +3 -0
  61. data/spec/data/overrides/good.overrides +5 -0
  62. data/spec/data/overrides/with_dupes.overrides +4 -0
  63. data/spec/data/software/erchef.rb +40 -0
  64. data/spec/fetchers/net_fetcher_spec.rb +16 -0
  65. data/spec/overrides_spec.rb +114 -0
  66. data/spec/package_release_spec.rb +197 -0
  67. data/spec/s3_cacher_spec.rb +47 -0
  68. data/spec/software_spec.rb +85 -0
  69. data/spec/spec_helper.rb +28 -0
  70. metadata +252 -0
@@ -0,0 +1,22 @@
1
+ #
2
+ # Copyright:: Copyright (c) 2012 Opscode, Inc.
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ #
17
+
18
+ require 'omnibus/fetcher'
19
+ require 'omnibus/fetchers/net_fetcher'
20
+ require 'omnibus/fetchers/git_fetcher'
21
+ require 'omnibus/fetchers/path_fetcher'
22
+ require 'omnibus/fetchers/s3_cache_fetcher'
@@ -0,0 +1,212 @@
1
+ #
2
+ # Copyright:: Copyright (c) 2012 Opscode, Inc.
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ #
17
+
18
+ module Omnibus
19
+
20
+ # Fetcher implementation for projects in git.
21
+ class GitFetcher < Fetcher
22
+
23
+ name :git
24
+
25
+ attr_reader :source
26
+ attr_reader :project_dir
27
+ attr_reader :version
28
+
29
+ def initialize(software)
30
+ @name = software.name
31
+ @source = software.source
32
+ @version = software.version
33
+ @project_dir = software.project_dir
34
+ end
35
+
36
+ def description
37
+ s=<<-E
38
+ repo URI: #{@source[:git]}
39
+ local location: #{@project_dir}
40
+ E
41
+ end
42
+
43
+ def version_guid
44
+ "git:#{current_revision}".chomp
45
+ rescue
46
+ end
47
+
48
+ def clean
49
+ if existing_git_clone?
50
+ log "cleaning existing build"
51
+ clean_cmd = "git clean -fdx"
52
+ shell = Mixlib::ShellOut.new(clean_cmd, :live_stream => STDOUT, :cwd => project_dir)
53
+ shell.run_command
54
+ shell.error!
55
+ end
56
+ rescue Exception => e
57
+ ErrorReporter.new(e, self).explain("Failed to clean git repository '#{@source[:git]}'")
58
+ raise
59
+ end
60
+
61
+ def fetch_required?
62
+ !existing_git_clone? || !current_rev_matches_target_rev?
63
+ end
64
+
65
+ def fetch
66
+ retries ||= 0
67
+ if existing_git_clone?
68
+ fetch_updates unless current_rev_matches_target_rev?
69
+ else
70
+ clone
71
+ checkout
72
+ end
73
+ rescue Exception => e
74
+ if retries >= 3
75
+ ErrorReporter.new(e, self).explain("Failed to fetch git repository '#{@source[:git]}'")
76
+ raise
77
+ else
78
+ # Deal with github failing all the time :(
79
+ time_to_sleep = 5 * (2 ** retries)
80
+ retries += 1
81
+ log "git clone/fetch failed for #{@source} #{retries} time(s), retrying in #{time_to_sleep}s"
82
+ sleep(time_to_sleep)
83
+ retry
84
+ end
85
+ end
86
+
87
+ private
88
+
89
+ def clone
90
+ puts "cloning the source from git"
91
+ clone_cmd = "git clone #{@source[:git]} #{project_dir}"
92
+ shell = Mixlib::ShellOut.new(clone_cmd, :live_stream => STDOUT)
93
+ shell.run_command
94
+ shell.error!
95
+ end
96
+
97
+ def checkout
98
+ sha_ref = target_revision
99
+
100
+ checkout_cmd = "git checkout #{sha_ref}"
101
+ shell = Mixlib::ShellOut.new(checkout_cmd, :live_stream => STDOUT, :cwd => project_dir)
102
+ shell.run_command
103
+ shell.error!
104
+ end
105
+
106
+ def fetch_updates
107
+ puts "fetching updates and resetting to revision #{target_revision}"
108
+ fetch_cmd = "git fetch origin && git fetch origin --tags && git reset --hard #{target_revision}"
109
+ shell = Mixlib::ShellOut.new(fetch_cmd, :live_stream => STDOUT, :cwd => project_dir)
110
+ shell.run_command
111
+ shell.error!
112
+ end
113
+
114
+ def existing_git_clone?
115
+ File.exist?("#{project_dir}/.git")
116
+ end
117
+
118
+ def current_rev_matches_target_rev?
119
+ current_revision && current_revision.strip.to_i(16) == target_revision.strip.to_i(16)
120
+ end
121
+
122
+ def current_revision
123
+ @current_rev ||= begin
124
+ rev_cmd = "git rev-parse HEAD"
125
+ shell = Mixlib::ShellOut.new(rev_cmd, :live_stream => STDOUT, :cwd => project_dir)
126
+ shell.run_command
127
+ shell.error!
128
+ output = shell.stdout
129
+
130
+ sha_hash?(output) ? output : nil
131
+ end
132
+ end
133
+
134
+ def target_revision
135
+ @target_rev ||= begin
136
+ if sha_hash?(version)
137
+ version
138
+ else
139
+ revision_from_remote_reference(version)
140
+ end
141
+ end
142
+ end
143
+
144
+ def sha_hash?(rev)
145
+ rev =~ /^[0-9a-f]{40}$/
146
+ end
147
+
148
+ # Return the SHA corresponding to ref. If ref is an annotated tag,
149
+ # return the SHA that was tagged not the SHA of the tag itself.
150
+ def revision_from_remote_reference(ref)
151
+ retries ||= 0
152
+ # execute `git ls-remote` the trailing '*' does globbing. This
153
+ # allows us to return the SHA of the tagged commit for annotated
154
+ # tags. We take care to only return exact matches in
155
+ # process_remote_list.
156
+ cmd = "git ls-remote origin #{ref}*"
157
+ shell = Mixlib::ShellOut.new(cmd, :live_stream => STDOUT, :cwd => project_dir)
158
+ shell.run_command
159
+ shell.error!
160
+ commit_ref = process_remote_list(shell.stdout, ref)
161
+ if !commit_ref
162
+ raise "Could not parse SHA reference"
163
+ end
164
+ commit_ref
165
+ rescue Exception => e
166
+ if retries >= 3
167
+ ErrorReporter.new(e, self).explain("Failed to fetch git repository '#{@source[:git]}'")
168
+ raise
169
+ else
170
+ # Deal with github failing all the time :(
171
+ time_to_sleep = 5 * (2 ** retries)
172
+ retries += 1
173
+ log "git ls-remote failed for #{@source} #{retries} time(s), retrying in #{time_to_sleep}s"
174
+ sleep(time_to_sleep)
175
+ retry
176
+ end
177
+ end
178
+
179
+ def process_remote_list(stdout, ref)
180
+ # Dereference annotated tags.
181
+ #
182
+ # Output will look like this:
183
+ #
184
+ # a2ed66c01f42514bcab77fd628149eccb4ecee28 refs/tags/rel-0.11.0
185
+ # f915286abdbc1907878376cce9222ac0b08b12b8 refs/tags/rel-0.11.0^{}
186
+ #
187
+ # The SHA with ^{} is the commit pointed to by an annotated
188
+ # tag. If ref isn't an annotated tag, there will not be a line
189
+ # with trailing ^{}.
190
+ #
191
+ # We'll return the SHA corresponding to the ^{} which is the
192
+ # commit pointed to by an annotated tag. If no such commit
193
+ # exists (not an annotated tag) then we return the SHA of the
194
+ # ref. If nothing matches, return "".
195
+ lines = stdout.split("\n")
196
+ matches = lines.map { |line| line.split("\t") }
197
+ # first try for ^{} indicating the commit pointed to by an
198
+ # annotated tag
199
+ tagged_commit = matches.find { |m| m[1].end_with?("#{ref}^{}") }
200
+ if tagged_commit
201
+ tagged_commit[0]
202
+ else
203
+ found = matches.find { |m| m[1].end_with?("#{ref}") }
204
+ if found
205
+ found[0]
206
+ else
207
+ nil
208
+ end
209
+ end
210
+ end
211
+ end
212
+ end
@@ -0,0 +1,193 @@
1
+ #
2
+ # Copyright:: Copyright (c) 2012 Opscode, Inc.
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ #
17
+
18
+ module Omnibus
19
+
20
+ class UnsupportedURIScheme < ArgumentError
21
+ end
22
+
23
+ class InvalidSourceFile < RuntimeError
24
+ end
25
+
26
+ # Fetcher Implementation for HTTP and FTP hosted tarballs
27
+ class NetFetcher < Fetcher
28
+
29
+ name :net
30
+
31
+ attr_reader :name
32
+ attr_reader :project_file
33
+ attr_reader :source
34
+ attr_reader :source_uri
35
+ attr_reader :source_dir
36
+ attr_reader :project_dir
37
+
38
+ def initialize(software)
39
+ @name = software.name
40
+ @checksum = software.checksum
41
+ @source = software.source
42
+ @project_file = software.project_file
43
+ @source_uri = software.source_uri
44
+ @source_dir = software.source_dir
45
+ @project_dir = software.project_dir
46
+ end
47
+
48
+ def description
49
+ s=<<-E
50
+ source URI: #{source_uri}
51
+ checksum: #{@checksum}
52
+ local location: #@project_file
53
+ E
54
+ end
55
+
56
+ def version_guid
57
+ "md5:#{@checksum}"
58
+ end
59
+
60
+ def fetch_required?
61
+ !File.exists?(project_file) || Digest::MD5.file(project_file) != @checksum
62
+ end
63
+
64
+
65
+ def clean
66
+ if File.exists?(project_dir)
67
+ log "cleaning existing build from #{project_dir}"
68
+ FileUtils.rm_rf(project_dir)
69
+ end
70
+ extract
71
+ end
72
+
73
+ def fetch
74
+ if fetch_required?
75
+ download
76
+ verify_checksum!
77
+ else
78
+ log "Cached copy of source tarball up to date"
79
+ end
80
+ end
81
+
82
+ def get_with_redirect(url, headers, limit = 10)
83
+ raise ArgumentError, 'HTTP redirect too deep' if limit == 0
84
+ log "getting from #{url} with #{limit} redirects left"
85
+
86
+ if !url.kind_of?(URI)
87
+ url = URI.parse(url)
88
+ end
89
+
90
+ req = Net::HTTP::Get.new(url.request_uri, headers)
91
+ http_client = Net::HTTP.new(url.host, url.port)
92
+ http_client.use_ssl = (url.scheme == "https")
93
+
94
+ response = http_client.start { |http| http.request(req) }
95
+ case response
96
+ when Net::HTTPSuccess
97
+ open(project_file, "wb") do |f|
98
+ f.write(response.body)
99
+ end
100
+ when Net::HTTPRedirection
101
+ get_with_redirect(response['location'], headers, limit - 1)
102
+ else
103
+ response.error!
104
+ end
105
+ end
106
+
107
+ def download
108
+ tries = 5
109
+ begin
110
+ log "\033[1;31m#{source[:warning]}\033[0m" if source.has_key?(:warning)
111
+ log "fetching #{project_file} from #{source_uri}"
112
+
113
+ case source_uri.scheme
114
+ when /https?/
115
+ headers = {
116
+ 'accept-encoding' => '',
117
+ }
118
+ if source.has_key?(:cookie)
119
+ headers['Cookie'] = source[:cookie]
120
+ end
121
+ get_with_redirect(source_uri, headers)
122
+ when "ftp"
123
+ Net::FTP.open(source_uri.host) do |ftp|
124
+ ftp.passive = true
125
+ ftp.login
126
+ ftp.getbinaryfile(source_uri.path, project_file)
127
+ ftp.close
128
+ end
129
+ else
130
+ raise UnsupportedURIScheme, "Don't know how to download from #{source_uri}"
131
+ end
132
+ rescue Exception => e
133
+ if ( tries -= 1 ) != 0
134
+ log "retrying failed download..."
135
+ retry
136
+ else
137
+ raise
138
+ end
139
+ end
140
+ rescue Exception => e
141
+ ErrorReporter.new(e, self).explain("Failed to fetch source from #source_uri (#{e.class}: #{e.message.strip})")
142
+ raise
143
+ end
144
+
145
+ def verify_checksum!
146
+ actual_md5 = Digest::MD5.file(project_file)
147
+ unless actual_md5 == @checksum
148
+ log "Invalid MD5 for #@name"
149
+ log "Expected: #{@checksum}"
150
+ log "Actual: #{actual_md5}"
151
+ raise InvalidSourceFile, "Checksum of downloaded file #{project_file} doesn't match expected"
152
+ end
153
+ end
154
+
155
+ def extract
156
+ log "extracting the source in #{project_file} to #{source_dir}"
157
+ cmd = extract_cmd
158
+ case cmd
159
+ when Proc
160
+ cmd.call
161
+ when String
162
+ shell = Mixlib::ShellOut.new(cmd, :live_stream => STDOUT)
163
+ shell.run_command
164
+ shell.error!
165
+ else
166
+ raise "Don't know how to extract command for #{cmd.class} class"
167
+ end
168
+ rescue Exception => e
169
+ ErrorReporter.new(e, self).explain("Failed to unpack archive at #{project_file} (#{e.class}: #{e.message.strip})")
170
+ raise
171
+ end
172
+
173
+ def extract_cmd
174
+ if project_file.end_with?(".gz") || project_file.end_with?(".tgz")
175
+ "gzip -dc #{project_file} | ( cd #{source_dir} && tar -xf - )"
176
+ elsif project_file.end_with?(".bz2")
177
+ "bzip2 -dc #{project_file} | ( cd #{source_dir} && tar -xf - )"
178
+ elsif project_file.end_with?(".7z")
179
+ "7z.exe x #{project_file} -o#{source_dir} -r -y"
180
+ elsif project_file.end_with?(".zip")
181
+ "unzip #{project_file} -d #{source_dir}"
182
+ else
183
+ #if we don't recognize the extension, simply copy over the file
184
+ Proc.new do
185
+ log "#{project_file} not an archive. Copying to #{project_dir}"
186
+ # hack hack hack, no project dir yet
187
+ FileUtils.mkdir_p(project_dir)
188
+ FileUtils.cp(project_file, project_dir)
189
+ end
190
+ end
191
+ end
192
+ end
193
+ end
@@ -0,0 +1,65 @@
1
+ #
2
+ # Copyright:: Copyright (c) 2012 Opscode, Inc.
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ #
17
+
18
+ module Omnibus
19
+
20
+ # Fetcher implementation for projects on the filesystem
21
+ class PathFetcher < Fetcher
22
+
23
+ name :path
24
+
25
+ def initialize(software)
26
+ @name = software.name
27
+ @source = software.source
28
+ @project_dir = software.project_dir
29
+ @version = software.version
30
+ end
31
+
32
+ def description
33
+ s=<<-E
34
+ source path: #{@source[:path]}
35
+ local location: #{@project_dir}
36
+ E
37
+ end
38
+
39
+ def rsync
40
+ if OHAI.platform == "windows"
41
+ # Robocopy's return code is 1 if it succesfully copies over the
42
+ # files and 0 if the files are already existing at the destination
43
+ sync_cmd = "robocopy #{@source[:path]}\\ #{@project_dir}\\ /MIR /S"
44
+ shell = Mixlib::ShellOut.new(sync_cmd, :returns => [0, 1])
45
+ else
46
+ sync_cmd = "rsync --delete -a #{@source[:path]}/ #{@project_dir}/"
47
+ shell = Mixlib::ShellOut.new(sync_cmd)
48
+ end
49
+ shell.run_command
50
+ end
51
+
52
+ def clean
53
+ # Here, clean will do the same as fetch: reset source to pristine state
54
+ rsync
55
+ end
56
+
57
+ def fetch
58
+ rsync
59
+ end
60
+
61
+ def fetch_required?
62
+ true
63
+ end
64
+ end
65
+ end