batali 0.3.14 → 0.4.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 56e09e21e418f24e83792d17a8c9498c0b46a2df
4
- data.tar.gz: 0590ade5cc488326df250797dcffc72820c49245
3
+ metadata.gz: 0415b35e7fad280740b21548ef140b5c12f98c96
4
+ data.tar.gz: 4afcc45cb368ebf1c156f0b9d96aa0f33ebb0ce1
5
5
  SHA512:
6
- metadata.gz: f82d8b530f540eeed8436fef0f84f84dadbdea515ef757516a6f50f5c6ed64964ebed25293a5babd6895a2bb3e881b6e82e72e0b8d50201af202f58b27e973c1
7
- data.tar.gz: 9d322ab00a9088b89b5f78c2bf0745588f8ff294676b03a9737df32d1eeb97df560e3efb74d6d265acb6201a6a90b6a7f8a6224f3cd916b3f93751c7c566dd87
6
+ metadata.gz: 567206dc928b7c3040bafe757ac18565a932c822f0d8d4301ec611035c01bcf773f4b982c52c7b2333432c8f5bebd9e45027e406c6bc1aef99736f8323a5e0d1
7
+ data.tar.gz: 9ecde47ac49072af4a436a39b11a465f43785482980e60f74dbd51c16c6aa33127709da278f604f58c87f565222311e81e0f30493ba123a55e00614a18cfd23d
data/CHANGELOG.md CHANGED
@@ -1,3 +1,6 @@
1
+ # v0.4.0
2
+ * [feature] Add `supermarket` command for static repository generation
3
+
1
4
  # v0.3.14
2
5
  * [enhancement] Use threads when installing cookbooks (#72 thanks @sawanoboly!)
3
6
 
data/README.md CHANGED
@@ -425,6 +425,31 @@ within the `batali.manifest` file. If cookbooks are defined within the
425
425
  `batali.manifest` file that have not been uploaded to the Chef server, those
426
426
  cookbooks will be uploaded.
427
427
 
428
+ ## Supermarket
429
+
430
+ Batali can generate a static supermarket repository from a `batali.manifest`. The resultant
431
+ directory can then be hosted with an httpd of choice. To generate a supermarket repository,
432
+ first run `resolve`:
433
+
434
+ ```
435
+ $ batali resolve
436
+ ```
437
+
438
+ Next, run the `supermarket` command to generate the repository:
439
+
440
+ ```
441
+ $ batali supermarket
442
+ ```
443
+
444
+ A new directory will be created (`./supermarket`) which contains the newly generated
445
+ supermarket respository. The generated `universe` file will contain URLs pointing
446
+ to `localhost`, which is the default behavior. In practice, it will be desirable to
447
+ update the URL to provide the customized location:
448
+
449
+ ```
450
+ $ batali supermarket --remote-supermarket-url="http://supermarket.example.com"
451
+ ```
452
+
428
453
  # Info
429
454
 
430
455
  * Repository: https://github.com/hw-labs/batali
data/bin/batali CHANGED
@@ -80,4 +80,24 @@ Bogo::Cli::Setup.define do
80
80
  end
81
81
  end
82
82
 
83
+ command 'supermarket' do
84
+ description 'Generate a supermarket'
85
+ self.instance_exec(&global_opts)
86
+ on :p, 'path=', 'Cookbook install path'
87
+ on :I, 'infrastructure', 'Resolve infrastructure cookbooks'
88
+ on :s, 'skip-install', 'Skip cookbook installation'
89
+ on :S, 'supermarket-path=', 'Supermarket output directory', :default => 'supermarket'
90
+ on :A, 'assets-path=', 'Supermarket assets storage path', :default => File.join('supermarket', 'assets')
91
+ on :R, 'remote-supermarket-url=', 'Custom remote supermarket URL (https://myhost.com:443/supermarket)', :default => 'http://localhost'
92
+ on :D, 'download-prefix=', 'Remote location prefixed to asset name', :default => '/assets'
93
+ on :T, 'location-type=', 'Name of location type', :default => 'batali'
94
+ on :P, 'pretty-universe', 'Output formatted universe JSON'
95
+ on :U, 'universe-only', 'Only generate the supermarket universe.json file'
96
+ on :C, 'clean-assets', 'Replace any existing compressed assets'
97
+
98
+ run do |opts, args|
99
+ Batali::Command::Supermarket.new(opts, args).execute!
100
+ end
101
+ end
102
+
83
103
  end
@@ -0,0 +1,141 @@
1
+ require 'batali'
2
+ require 'rubygems/package'
3
+ require 'zlib'
4
+
5
+ module Batali
6
+ class Command
7
+ # Generate a supermarket
8
+ class Supermarket < Batali::Command
9
+
10
+ # Generate supermarket
11
+ def execute!
12
+ ui.info "Batali supermarket generator #{ui.color('started', :bold)}"
13
+ if(config[:skip_install])
14
+ ui.warn 'Skipping cookbook installation.'
15
+ else
16
+ Install.new(config.merge(:ui => ui, :install => {}), arguments).execute!
17
+ end
18
+ run_action 'Prepare supermarket destination directory' do
19
+ FileUtils.mkdir_p(File.join(config[:supermarket_path], 'api', 'v1', 'cookbooks'))
20
+ FileUtils.mkdir_p(config[:assets_path])
21
+ nil
22
+ end
23
+ new_universe = new_universe_file = universe_diff = nil
24
+ run_action 'Generate supermarket universe.json file' do
25
+ new_universe, new_universe_file = generate_universe
26
+ nil
27
+ end
28
+ unless(config[:universe_only])
29
+ if(config[:clean_assets])
30
+ Dir.glob(File.join(config[:assets_path], '*')).each do |old_asset|
31
+ FileUtils.rm(old_asset)
32
+ end
33
+ end
34
+ new_assets = generate_cookbook_assets
35
+ valid_items = new_universe.values.map(&:values).flatten.map do |info|
36
+ File.basename(info[:download_url])
37
+ end
38
+ prune_universe(valid_items)
39
+ populate_universe(valid_items)
40
+ end
41
+ run_action 'Write supermarket universe file' do
42
+ FileUtils.cp(
43
+ new_universe_file.path,
44
+ File.join(config[:supermarket_path], 'universe')
45
+ )
46
+ FileUtils.chmod(0644, File.join(config[:supermarket_path], 'universe'))
47
+ new_universe_file.delete
48
+ nil
49
+ end
50
+ ui.info "Batali supermarket generator #{ui.color('complete!', :bold, :green)}"
51
+ ui.puts " Supermarket content written to: #{config[:supermarket_path]}"
52
+ end
53
+
54
+ # Generate compressed cookbook assets
55
+ def generate_cookbook_assets
56
+ manifest.cookbook.map do |ckbk|
57
+ base_name = "#{ckbk.name}-#{ckbk.version}.tgz"
58
+ ckbk_name = infrastructure? ? "#{ckbk.name}-#{ckbk.version}" : ckbk.name
59
+ tar_ckbk_name = "#{ckbk.name}-#{ckbk.version}"
60
+ ckbk_content_path = File.join('cookbooks', ckbk_name)
61
+ ckbk_path = File.join(config[:assets_path], base_name)
62
+ unless(File.exist?(ckbk_path))
63
+ ckbk_io = File.open(ckbk_path, 'wb')
64
+ gz_io = Zlib::GzipWriter.new(ckbk_io, Zlib::BEST_COMPRESSION)
65
+ begin
66
+ gz_io.mtime = Time.now
67
+ Gem::Package::TarWriter.new(gz_io) do |tar|
68
+ unless(File.directory?(ckbk_content_path))
69
+ raise "Cookbook path not found! Run `install`. (#{ckbk_content_path})"
70
+ end
71
+ Dir.glob(File.join(ckbk_content_path, '**', '**', '*')).each do |c_file|
72
+ next unless File.file?(c_file)
73
+ stat = File.stat(c_file)
74
+ c_path = c_file.sub(File.join(ckbk_content_path, ''), '')
75
+ tar.add_file_simple(File.join(tar_ckbk_name, c_path), stat.mode, stat.size) do |dst|
76
+ File.open(c_file, 'rb') do |src|
77
+ until(src.eof?)
78
+ dst.write src.read(4096)
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
84
+ ensure
85
+ gz_io.close
86
+ end
87
+ base_name
88
+ end
89
+ end.compact
90
+ end
91
+
92
+ # Prune assets from universe
93
+ #
94
+ # @param items [Array<String>] names of assets
95
+ # TODO: This is a stub for custom action
96
+ def prune_universe(items)
97
+ end
98
+
99
+ # Add assets to universe
100
+ #
101
+ # @param items [Array<String>] names of assets
102
+ # TODO: This is a stub for custom action
103
+ def populate_universe(items)
104
+ end
105
+
106
+ # Generate the supermarket universe.json file
107
+ #
108
+ # @return [Smash, File] universe content hash, universe file
109
+ def generate_universe
110
+ universe = Smash.new.tap do |uni|
111
+ manifest.cookbook.each do |ckbk|
112
+ uni.set(ckbk.name, ckbk.version.to_s,
113
+ Smash.new(
114
+ :location_type => config[:location_type],
115
+ :location_path => File.join(config[:remote_supermarket_url], 'api', 'v1'),
116
+ :download_url => File.join(
117
+ config[:remote_supermarket_url],
118
+ config[:download_prefix],
119
+ "#{ckbk.name}-#{ckbk.version}.tgz"
120
+ ),
121
+ :dependencies => Smash[
122
+ ckbk.dependencies.map do |dep|
123
+ [dep.name, dep.requirement]
124
+ end
125
+ ]
126
+ )
127
+ )
128
+ end
129
+ end
130
+
131
+ new_universe_file = Tempfile.new('batali-universe')
132
+ new_universe_file.puts MultiJson.dump(universe, :pretty => !!config[:pretty_universe])
133
+ new_universe_file.flush
134
+ new_universe_file.rewind
135
+ [universe, new_universe_file]
136
+ end
137
+
138
+ end
139
+
140
+ end
141
+ end
@@ -14,6 +14,7 @@ module Batali
14
14
  autoload :Display, 'batali/command/display'
15
15
  autoload :Install, 'batali/command/install'
16
16
  autoload :Resolve, 'batali/command/resolve'
17
+ autoload :Supermarket, 'batali/command/supermarket'
17
18
  autoload :Update, 'batali/command/update'
18
19
 
19
20
  # Set UI when loading via command
@@ -10,7 +10,7 @@ module Batali
10
10
  class RemoteSite < Origin
11
11
 
12
12
  # Site suffix for API endpoint
13
- COOKBOOK_API_SUFFIX = 'api/v1/cookbooks'
13
+ API_SUFFIX = 'api/v1/'
14
14
 
15
15
  include Bogo::Memoization
16
16
 
@@ -22,7 +22,8 @@ module Batali
22
22
 
23
23
  def initialize(*_)
24
24
  super
25
- endpoint = URI.join(self.endpoint, COOKBOOK_API_SUFFIX).to_s
25
+ # NOTE: We currently don't require API_SUFFIX information
26
+ # self.endpoint = URI.join(endpoint, API_SUFFIX).to_s
26
27
  self.identifier = Digest::SHA256.hexdigest(endpoint)
27
28
  unless(name?)
28
29
  self.name = identifier
@@ -1,5 +1,5 @@
1
1
  # Batali namespace
2
2
  module Batali
3
3
  # Current version
4
- VERSION = Gem::Version.new('0.3.14')
4
+ VERSION = Gem::Version.new('0.4.0')
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: batali
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.14
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Roberts
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-01-04 00:00:00.000000000 Z
11
+ date: 2016-01-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: attribute_struct
@@ -220,6 +220,7 @@ files:
220
220
  - lib/batali/command/display.rb
221
221
  - lib/batali/command/install.rb
222
222
  - lib/batali/command/resolve.rb
223
+ - lib/batali/command/supermarket.rb
223
224
  - lib/batali/command/update.rb
224
225
  - lib/batali/config.rb
225
226
  - lib/batali/git.rb