bosh_cli 1.2831.0 → 1.2839.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.
@@ -0,0 +1,210 @@
1
+ module Bosh::Cli::Resources
2
+ class Package
3
+ BUILD_HOOK_FILES = ['packaging', 'pre_packaging']
4
+
5
+ # We have two ways of getting/storing a package:
6
+ # development versions of packages, kept in release directory
7
+ # final versions of packages, kept in blobstore
8
+ # development packages and their metadata should always be gitignored
9
+ # final build tarballs should be ignored as well
10
+ # final builds metadata should be checked in
11
+
12
+ # @param [String] directory base Release directory
13
+ def self.discover(release_base)
14
+ Dir[File.join(release_base, 'packages', '*')].inject([]) do |packages, package_base|
15
+ next unless File.directory?(package_base)
16
+ packages << new(package_base, release_base)
17
+ end
18
+ end
19
+
20
+ attr_reader :package_base, :release_base
21
+
22
+ def initialize(package_base, release_base)
23
+ @release_base = Pathname.new(release_base)
24
+ @package_base = Pathname.new(package_base)
25
+ end
26
+
27
+ def spec
28
+ @spec ||= load_yaml_file(package_base.join('spec'))
29
+ rescue
30
+ raise Bosh::Cli::InvalidPackage, 'Package spec is missing'
31
+ end
32
+
33
+ def name
34
+ spec['name']
35
+ end
36
+
37
+ def dependencies
38
+ @dependencies ||= Array(spec['dependencies']).sort
39
+ end
40
+
41
+ def singular_type
42
+ 'package'
43
+ end
44
+
45
+ def plural_type
46
+ 'packages'
47
+ end
48
+
49
+ def files
50
+ validate!
51
+ known_files = {}
52
+
53
+ files = []
54
+ files += resolved_globs.map do |match|
55
+ known_files[match.path] = true
56
+ [match.full_path, match.path]
57
+ end
58
+
59
+ BUILD_HOOK_FILES.each do |build_hook_file|
60
+ source_file = package_base.join(build_hook_file)
61
+ if source_file.exist?
62
+ if known_files.has_key?(build_hook_file)
63
+ raise Bosh::Cli::InvalidPackage, "Package '#{name}' has '#{build_hook_file}' file " +
64
+ "which conflicts with BOSH packaging"
65
+ end
66
+
67
+ files << [source_file.to_s, build_hook_file]
68
+ end
69
+ end
70
+
71
+ files
72
+ end
73
+
74
+ def validate!
75
+ basename = File.basename(package_base.to_s)
76
+
77
+ unless name == basename
78
+ raise Bosh::Cli::InvalidPackage, "Found '#{name}' package in '#{basename}' directory, please fix it"
79
+ end
80
+
81
+ unless name.bosh_valid_id?
82
+ raise Bosh::Cli::InvalidPackage, "Package name, '#{name}', should be a valid BOSH identifier"
83
+ end
84
+
85
+ unless spec['files'].is_a?(Array) && spec['files'].size > 0
86
+ raise Bosh::Cli::InvalidPackage, "Package '#{name}' doesn't include any files"
87
+ end
88
+
89
+ resolve_globs
90
+ end
91
+
92
+ def additional_fingerprints
93
+ dependencies
94
+ end
95
+
96
+ def format_fingerprint(digest, filename, name, file_mode)
97
+ is_hook = BUILD_HOOK_FILES.include?(name)
98
+ "%s%s%s" % [name, digest, is_hook ? '' : file_mode]
99
+ end
100
+
101
+ def run_script(script_name, *args)
102
+ if BUILD_HOOK_FILES.include?(script_name.to_s)
103
+ send(:"run_script_#{script_name}", *args)
104
+ end
105
+ end
106
+
107
+ # ---
108
+
109
+ private
110
+
111
+ def excluded_files
112
+ @excluded_files ||= Array(spec['excluded_files']).sort
113
+ end
114
+
115
+ # @return Array<Bosh::Cli::GlobMatch>
116
+ def resolve_globs
117
+ @resolved_globs ||= begin
118
+ all_matches = Set.new
119
+
120
+ spec['files'].each do |glob|
121
+ glob_matches = Set.new
122
+ src_matches = resolve_glob_in_dir(glob, release_src)
123
+ glob_matches += src_matches.map { |path| Bosh::Cli::GlobMatch.new(release_src, path) }
124
+
125
+ # Blobs directory is a little bit different: whatever matches a blob
126
+ # will complement already found matches, unless this particular path
127
+ # has already been matched. The GlobMatch class defines <=> to compare
128
+ # path, thereby rejecting blobs if the file exists in src.
129
+ if File.directory?(File.join(release_blobs))
130
+ blob_matches = resolve_glob_in_dir(glob, release_blobs)
131
+ glob_matches += blob_matches.map { |path| Bosh::Cli::GlobMatch.new(release_blobs, path) }
132
+ end
133
+
134
+ if glob_matches.empty?
135
+ raise Bosh::Cli::InvalidPackage, "Package '#{name}' has a glob that resolves to an empty file list: #{glob}"
136
+ end
137
+
138
+ all_matches += glob_matches
139
+ end
140
+
141
+ all_matches.reject! do |match|
142
+ excluded_files.detect { |excluded_glob| File.fnmatch(excluded_glob, match.path) }
143
+ end
144
+
145
+ all_matches.sort
146
+ end
147
+ end
148
+
149
+ def resolve_glob_in_dir(glob, dir)
150
+ Dir.chdir(dir) do
151
+ Dir.glob(glob, File::FNM_DOTMATCH).reject do |fn|
152
+ %w(. ..).include?(File.basename(fn))
153
+ end
154
+ end
155
+ end
156
+
157
+ def resolved_globs
158
+ @resolved_globs
159
+ end
160
+
161
+ def release_src
162
+ release_base.join('src')
163
+ end
164
+
165
+ def release_alt
166
+ release_base.join('src_alt')
167
+ end
168
+
169
+ def release_blobs
170
+ release_base.join('blobs')
171
+ end
172
+
173
+ def run_script_pre_packaging(staging_dir)
174
+ pre_packaging_script = package_base.join('pre_packaging')
175
+
176
+ if File.exists?(pre_packaging_script)
177
+ say('Pre-packaging...')
178
+ FileUtils.cp(pre_packaging_script, staging_dir, :preserve => true)
179
+
180
+ old_env = ENV
181
+
182
+ begin
183
+ ENV.delete_if { |key, _| key[0, 7] == 'BUNDLE_' }
184
+ if ENV['RUBYOPT']
185
+ ENV['RUBYOPT'] = ENV['RUBYOPT'].sub('-rbundler/setup', '')
186
+ end
187
+ # todo: test these
188
+ ENV['BUILD_DIR'] = staging_dir
189
+ ENV['RELEASE_DIR'] = release_base.to_s
190
+ Dir.chdir(staging_dir) do
191
+ output = `bash -x pre_packaging 2>&1`
192
+
193
+ unless $?.exitstatus == 0
194
+ output.split("\n").each do |line|
195
+ say("> #{line}")
196
+ end
197
+ raise Bosh::Cli::InvalidPackage, "'#{name}' pre-packaging failed"
198
+ end
199
+ end
200
+
201
+ ensure
202
+ ENV.delete('BUILD_DIR')
203
+ old_env.each { |k, v| ENV[k] = old_env[k] }
204
+ end
205
+
206
+ FileUtils.rm(File.join(staging_dir, 'pre_packaging'))
207
+ end
208
+ end
209
+ end
210
+ end
data/lib/cli/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module Bosh
2
2
  module Cli
3
- VERSION = '1.2831.0'
3
+ VERSION = '1.2839.0'
4
4
  end
5
5
  end
@@ -10,12 +10,12 @@ module Bosh::Cli::Versions
10
10
  @name_prefix = name_prefix
11
11
  end
12
12
 
13
- def put_file(version, src_file_path)
13
+ def put_file(version, origin_file_path)
14
14
  destination = file_path(version)
15
- unless File.exist?(src_file_path)
16
- raise "Trying to store non-existant file `#{src_file_path}' for version `#{version}'"
15
+ unless File.exist?(origin_file_path)
16
+ raise "Trying to store non-existant file `#{origin_file_path}' for version `#{version}'"
17
17
  end
18
- FileUtils.cp(src_file_path, destination, :preserve => true)
18
+ FileUtils.cp(origin_file_path, destination, :preserve => true)
19
19
 
20
20
  File.expand_path(destination)
21
21
  end
@@ -9,7 +9,6 @@ module Bosh::Cli::Versions
9
9
 
10
10
  def find_file(blobstore_id, sha1, version, desc)
11
11
  if @storage.has_file?(version)
12
- say('FOUND LOCAL'.make_green)
13
12
  file_path = @storage.get_file(version)
14
13
  file_sha1 = Digest::SHA1.file(file_path).hexdigest
15
14
  if file_sha1 == sha1
@@ -22,8 +21,7 @@ module Bosh::Cli::Versions
22
21
  err("Cannot find #{desc}")
23
22
  end
24
23
 
25
- say('FOUND REMOTE'.make_yellow)
26
- say("Downloading #{desc} from blobstore (id=#{blobstore_id})...".make_green)
24
+ say("Downloading from blobstore (id=#{blobstore_id})...".make_green)
27
25
 
28
26
  tmp_file_path = File.join(@tmpdir, "bosh-tmp-file-#{SecureRandom.uuid}")
29
27
  begin
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bosh_cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2831.0
4
+ version: 1.2839.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - VMware
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-02-04 00:00:00.000000000 Z
11
+ date: 2015-02-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bosh_common
@@ -16,28 +16,28 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 1.2831.0
19
+ version: 1.2839.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 1.2831.0
26
+ version: 1.2839.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: bosh-template
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 1.2831.0
33
+ version: 1.2839.0
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 1.2831.0
40
+ version: 1.2839.0
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: json_pure
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -114,14 +114,14 @@ dependencies:
114
114
  requirements:
115
115
  - - "~>"
116
116
  - !ruby/object:Gem::Version
117
- version: 1.2831.0
117
+ version: 1.2839.0
118
118
  type: :runtime
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
122
  - - "~>"
123
123
  - !ruby/object:Gem::Version
124
- version: 1.2831.0
124
+ version: 1.2839.0
125
125
  - !ruby/object:Gem::Dependency
126
126
  name: net-ssh
127
127
  requirement: !ruby/object:Gem::Requirement
@@ -194,7 +194,7 @@ dependencies:
194
194
  version: 0.5.4
195
195
  description: |-
196
196
  BOSH CLI
197
- 4cf37f
197
+ 41b440
198
198
  email: support@cloudfoundry.com
199
199
  executables:
200
200
  - bosh
@@ -203,9 +203,13 @@ extra_rdoc_files: []
203
203
  files:
204
204
  - bin/bosh
205
205
  - lib/cli.rb
206
+ - lib/cli/archive_builder.rb
207
+ - lib/cli/archive_repository.rb
208
+ - lib/cli/archive_repository_provider.rb
206
209
  - lib/cli/backup_destination_path.rb
207
210
  - lib/cli/base_command.rb
208
211
  - lib/cli/blob_manager.rb
212
+ - lib/cli/build_artifact.rb
209
213
  - lib/cli/changeset_helper.rb
210
214
  - lib/cli/client/compiled_packages_client.rb
211
215
  - lib/cli/client/director.rb
@@ -255,8 +259,8 @@ files:
255
259
  - lib/cli/download_with_progress.rb
256
260
  - lib/cli/errors.rb
257
261
  - lib/cli/file_with_progress_bar.rb
262
+ - lib/cli/glob_match.rb
258
263
  - lib/cli/interactive_progress_renderer.rb
259
- - lib/cli/job_builder.rb
260
264
  - lib/cli/job_command_args.rb
261
265
  - lib/cli/job_property_collection.rb
262
266
  - lib/cli/job_property_validator.rb
@@ -266,8 +270,6 @@ files:
266
270
  - lib/cli/manifest_warnings.rb
267
271
  - lib/cli/name_version_pair.rb
268
272
  - lib/cli/non_interactive_progress_renderer.rb
269
- - lib/cli/package_builder.rb
270
- - lib/cli/packaging_helper.rb
271
273
  - lib/cli/public_stemcell.rb
272
274
  - lib/cli/public_stemcell_presenter.rb
273
275
  - lib/cli/public_stemcells.rb
@@ -275,6 +277,8 @@ files:
275
277
  - lib/cli/release_builder.rb
276
278
  - lib/cli/release_compiler.rb
277
279
  - lib/cli/release_tarball.rb
280
+ - lib/cli/resources/job.rb
281
+ - lib/cli/resources/package.rb
278
282
  - lib/cli/resurrection.rb
279
283
  - lib/cli/runner.rb
280
284
  - lib/cli/source_control/git_ignore.rb
@@ -1,277 +0,0 @@
1
- module Bosh::Cli
2
- class JobBuilder
3
- include PackagingHelper
4
-
5
- attr_reader :name, :version, :packages, :templates,
6
- :release_dir, :built_packages, :tarball_path
7
-
8
- # @return [Hash] Properties defined in this job
9
- attr_reader :properties
10
-
11
- def self.run_prepare_script(script_path)
12
- unless File.exists?(script_path)
13
- raise InvalidJob, "Prepare script at `#{script_path}' doesn't exist"
14
- end
15
-
16
- unless File.executable?(script_path)
17
- raise InvalidJob, "Prepare script at `#{script_path}' is not executable"
18
- end
19
-
20
- old_env = ENV
21
-
22
- script_dir = File.dirname(script_path)
23
- script_name = File.basename(script_path)
24
-
25
- begin
26
- # We need to temporarily delete some rubygems related artefacts
27
- # because preparation scripts shouldn't share any assumptions
28
- # with CLI itself
29
- %w{ BUNDLE_GEMFILE RUBYOPT }.each { |key| ENV.delete(key) }
30
-
31
- output = nil
32
- Dir.chdir(script_dir) do
33
- cmd = "./#{script_name} 2>&1"
34
- output = `#{cmd}`
35
- end
36
-
37
- unless $?.exitstatus == 0
38
- raise InvalidJob, "`#{script_path}' script failed: #{output}"
39
- end
40
-
41
- output
42
- ensure
43
- ENV.each_pair { |k, v| ENV[k] = old_env[k] }
44
- end
45
- end
46
-
47
- # @param [String] directory Release directory
48
- # @param [Hash] options Build options
49
- def self.discover(directory, options = {})
50
- builders = []
51
-
52
- Dir[File.join(directory, "jobs", "*")].each do |job_dir|
53
- next unless File.directory?(job_dir)
54
- job_dirname = File.basename(job_dir)
55
-
56
- prepare_script = File.join(job_dir, "prepare")
57
- if File.exists?(prepare_script)
58
- run_prepare_script(prepare_script)
59
- end
60
-
61
- job_spec = load_yaml_file(File.join(job_dir, "spec"))
62
- if job_spec["name"] != job_dirname
63
- raise InvalidJob,
64
- "Found `#{job_spec["name"]}' job in " +
65
- "`#{job_dirname}' directory, please fix it"
66
- end
67
-
68
- final = options[:final]
69
- dry_run = options[:dry_run]
70
- blobstore = options[:blobstore]
71
- package_names = options[:package_names]
72
-
73
- builder = new(job_spec, directory, final, blobstore, package_names)
74
- builder.dry_run = true if dry_run
75
- builders << builder
76
- end
77
-
78
- builders
79
- end
80
-
81
- def initialize(spec, release_dir, final, blobstore, built_packages = [])
82
- spec = load_yaml_file(spec) if spec.is_a?(String) && File.file?(spec)
83
-
84
- @name = spec["name"]
85
- @version = nil
86
- @tarball_path = nil
87
- @packages = spec["packages"].to_a
88
- @built_packages = built_packages.to_a
89
- @release_dir = release_dir
90
- @templates_dir = File.join(job_dir, "templates")
91
- @tarballs_dir = File.join(release_dir, "tmp", "jobs")
92
- @final = final
93
- @blobstore = blobstore
94
- @artefact_type = "job"
95
-
96
- case spec["templates"]
97
- when Hash
98
- @templates = spec["templates"].keys
99
- else
100
- raise InvalidJob, "Incorrect templates section in `#{@name}' " +
101
- "job spec (Hash expected, #{spec["properties"].class} given)"
102
- end
103
-
104
- if spec.has_key?("properties")
105
- if spec["properties"].is_a?(Hash)
106
- @properties = spec["properties"]
107
- else
108
- raise InvalidJob, "Incorrect properties section in `#{@name}' " +
109
- "job spec (Hash expected, #{spec["properties"].class} given)"
110
- end
111
- else
112
- @properties = {}
113
- end
114
-
115
- if @name.blank?
116
- raise InvalidJob, "Job name is missing"
117
- end
118
-
119
- if @templates.nil?
120
- raise InvalidJob, "Please include templates section with at least 1 " +
121
- "(possibly dummy) file into `#{@name}' job spec"
122
- end
123
-
124
- unless @name.bosh_valid_id?
125
- raise InvalidJob, "`#{@name}' is not a valid BOSH identifier"
126
- end
127
-
128
- unless File.exists?(File.join(job_dir, "spec"))
129
- raise InvalidJob, "Cannot find spec file for '#{name}'"
130
- end
131
-
132
- if missing_packages.size > 0
133
- raise InvalidJob, "Some packages required by '#{name}' job " +
134
- "are missing: %s" % [missing_packages.join(", ")]
135
- end
136
-
137
- if missing_templates.size > 0
138
- raise InvalidJob, "Some template files required by '#{name}' job " +
139
- "are missing: %s" % [missing_templates.join(", ")]
140
- end
141
-
142
- if extra_templates.size > 0
143
- raise InvalidJob, "There are unused template files for job " +
144
- "'#{name}': %s" % [extra_templates.join(", ")]
145
- end
146
-
147
- unless monit_files.size > 0
148
- raise InvalidJob, "Cannot find monit file for '#{name}'"
149
- end
150
-
151
- @dev_builds_dir = File.join(@release_dir, ".dev_builds", "jobs", @name)
152
- @final_builds_dir = File.join(@release_dir, ".final_builds",
153
- "jobs", @name)
154
-
155
- FileUtils.mkdir_p(job_dir)
156
- FileUtils.mkdir_p(@dev_builds_dir)
157
- FileUtils.mkdir_p(@final_builds_dir)
158
-
159
- init_indices
160
- end
161
-
162
- def copy_files
163
- FileUtils.mkdir_p(File.join(build_dir, "templates"))
164
- copied = 0
165
-
166
- templates.each do |template|
167
- src = File.join(@templates_dir, template)
168
- dst = File.join(build_dir, "templates", template)
169
- FileUtils.mkdir_p(File.dirname(dst))
170
-
171
- FileUtils.cp(src, dst, :preserve => true)
172
- copied += 1
173
- end
174
-
175
- monit_files.each do |file|
176
- FileUtils.cp(file, build_dir, :preserve => true)
177
- copied += 1
178
- end
179
-
180
- FileUtils.cp(File.join(job_dir, "spec"), File.join(build_dir, "job.MF"),
181
- :preserve => true)
182
- copied += 1
183
- copied
184
- end
185
-
186
- def prepare_files
187
- File.join(job_dir, "prepare")
188
- end
189
-
190
- def build_dir
191
- @build_dir ||= Dir.mktmpdir
192
- end
193
-
194
- def job_dir
195
- File.join(@release_dir, "jobs", @name)
196
- end
197
-
198
- def dev_builds_dir
199
- File.join(@release_dir, ".dev_builds", "jobs", name)
200
- end
201
-
202
- def final_builds_dir
203
- File.join(@release_dir, ".final_builds", "jobs", name)
204
- end
205
-
206
- def fingerprint
207
- @fingerprint ||= make_fingerprint
208
- end
209
-
210
- def monit_files
211
- glob = File.join(job_dir, '*.monit')
212
- files = Dir.glob(glob)
213
- monit = File.join(job_dir, "monit")
214
- files << monit if File.exist?(monit)
215
- files
216
- end
217
-
218
- def reload
219
- @fingerprint = nil
220
- @build_dir = nil
221
- self
222
- end
223
-
224
- # @return [Array<String>] Returns full paths of all templates in the job
225
- # (regular job templates and monit)
226
- def all_templates
227
- regular_templates = @templates.map do |template|
228
- File.join(@templates_dir, template)
229
- end
230
-
231
- regular_templates.sort + monit_files
232
- end
233
-
234
- private
235
-
236
- def make_fingerprint
237
- versioning_scheme = 2
238
- contents = "v#{versioning_scheme}"
239
-
240
- files = all_templates
241
- files << File.join(job_dir, "spec")
242
-
243
- files.each do |filename|
244
- path = File.basename(filename)
245
- digest = Digest::SHA1.file(filename).hexdigest
246
- contents << "%s%s%s" % [path, digest, tracked_permissions(filename)]
247
- end
248
-
249
- Digest::SHA1.hexdigest(contents)
250
- end
251
-
252
- def missing_packages
253
- @missing_packages ||= packages - built_packages
254
- end
255
-
256
- def missing_templates
257
- templates.select do |template|
258
- !File.exists?(File.join(@templates_dir, template))
259
- end
260
- end
261
-
262
- def extra_templates
263
- return [] if !File.directory?(@templates_dir)
264
-
265
- Dir.chdir(@templates_dir) do
266
- Dir["**/*"].reject do |file|
267
- File.directory?(file) || templates.include?(file)
268
- end
269
- end
270
- end
271
-
272
- def in_build_dir(&block)
273
- Dir.chdir(build_dir) { yield }
274
- end
275
-
276
- end
277
- end