librarian-puppet-simple-force 0.0.5
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 +7 -0
- data/.gitignore +19 -0
- data/Gemfile +3 -0
- data/LICENSE +13 -0
- data/README.md +69 -0
- data/bin/librarian-puppet +8 -0
- data/lib/librarian/puppet/simple/cli.rb +285 -0
- data/lib/librarian/puppet/simple/installer.rb +113 -0
- data/lib/librarian/puppet/simple/iterator.rb +56 -0
- data/lib/librarian/puppet/simple/util.rb +51 -0
- data/lib/librarian/puppet/simple/version.rb +7 -0
- data/lib/librarian/puppet/simple.rb +9 -0
- data/librarian-puppet-simple-force.gemspec +25 -0
- data/spec/fixtures/Puppetfile +13 -0
- data/spec/functional/clean_spec.rb +42 -0
- data/spec/functional/install_spec.rb +74 -0
- data/spec/spec_helper.rb +25 -0
- metadata +95 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 4dcc659f7b1e17ed2c2cd38c3b2494b706608569
|
4
|
+
data.tar.gz: 5cfa4319360802b23895e27788ab2f0a0c630497
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: cdeb6ca3cf01a89c5b03fb7da22a2dca8b875b7b8f65d51e6deacbe9b1e22580c3083e59348f21aa18995e5f5ff5843c7fb60366b0af70869c4e36290b652d20
|
7
|
+
data.tar.gz: e5abec691441b7bfb0f00e30ad3291a4ca4d1c57cd344509d7ce5953e22ee7ac9f5c30d9718ed2febbaab2d30a65fea4b4d6dbe2a138ba2ee69a97a953971526
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
Copyright 2013-2014 Dan Bode
|
2
|
+
|
3
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
you may not use this file except in compliance with the License.
|
5
|
+
You may obtain a copy of the License at
|
6
|
+
|
7
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
|
9
|
+
Unless required by applicable law or agreed to in writing, software
|
10
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
See the License for the specific language governing permissions and
|
13
|
+
limitations under the License.
|
data/README.md
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
# librarian-puppet-simple
|
2
|
+
|
3
|
+
This project was created out of my frustration with dependency management in librarian-puppet, some people need external dependencies, I just need to be able to pin revisions for a collection of modules, and I found the dependency managment features of librarian-puppet too heavy for my simple use case.
|
4
|
+
|
5
|
+
This project just has fewer commands, but they should be compatible with the original librarian-puppet:
|
6
|
+
|
7
|
+
### Clean
|
8
|
+
Remove the directory where the modules will be installed. At the moment the supported options are:
|
9
|
+
* `--verbose` display progress messages
|
10
|
+
* `--path` override the default `./modules` where modules will be installed
|
11
|
+
|
12
|
+
```
|
13
|
+
librarian-puppet clean [--verbose] [--path]
|
14
|
+
```
|
15
|
+
|
16
|
+
### Install
|
17
|
+
Iterates through your Puppetfile and installs git sources. At the moment the supported options are:
|
18
|
+
* `--verbose` display progress messages
|
19
|
+
* `--clean` remove the directory before installing modules
|
20
|
+
* `--path` override the default `./modules` where modules will be installed
|
21
|
+
* `--puppetfile` override the default `./Puppetfile` used to find the modules
|
22
|
+
|
23
|
+
```
|
24
|
+
librarian-puppet install [--verbose] [--clean] [--path] [--puppetfile]
|
25
|
+
```
|
26
|
+
|
27
|
+
### Update
|
28
|
+
Iterates through your Puppetfile and updates git sources. If a SHA-1 hash is specified in the `:ref`, the module will not be updated.
|
29
|
+
|
30
|
+
Supported options are:<br/>
|
31
|
+
<li>`--verbose` display progress messages</li>
|
32
|
+
<li>`--path` override the default `./modules` where modules will be installed</li>
|
33
|
+
<li> `--puppetfile` override the default `./Puppetfile` used to find the modules</li>
|
34
|
+
|
35
|
+
```
|
36
|
+
librarian-puppet update [--verbose] [--path] [--puppetfile]
|
37
|
+
```
|
38
|
+
|
39
|
+
## Puppetfile
|
40
|
+
The processed Puppetfile may contain two different types of modules, `git` and `tarball`. The `git` option accepts an optional `ref` parameter.
|
41
|
+
|
42
|
+
The module names can be namespaced, but the created directory will only contain the last part of the name. For example, a module named `puppetlabs/ntp` will generate a directory `ntp`, and so will a module simply named `ntp`.
|
43
|
+
|
44
|
+
Here's an example of a valid Puppetfile showcasing all valid options:
|
45
|
+
|
46
|
+
```
|
47
|
+
mod "puppetlabs/ntp",
|
48
|
+
:git => "git://github.com/puppetlabs/puppetlabs-ntp.git",
|
49
|
+
:ref => "99bae40f225db0dd052efbf1d4078a21f0333331"
|
50
|
+
|
51
|
+
mod "apache",
|
52
|
+
:tarball => "https://forge.puppetlabs.com/puppetlabs/apache/0.6.0.tar.gz"
|
53
|
+
```
|
54
|
+
|
55
|
+
## Setting up for development and running the specs
|
56
|
+
Just clone the repo and run the following commands:
|
57
|
+
```
|
58
|
+
bundle exec install --path=vendor
|
59
|
+
bundle exec rspec
|
60
|
+
```
|
61
|
+
|
62
|
+
Beware that the functional tests will download files from GitHub and PuppetForge and will break if either is unavailable.
|
63
|
+
|
64
|
+
## License
|
65
|
+
|
66
|
+
See [LICENSE](/LICENSE)
|
67
|
+
|
68
|
+
## Credits
|
69
|
+
The untar and ungzip methods came from https://gist.github.com/sinisterchipmunk/1335041
|
@@ -0,0 +1,285 @@
|
|
1
|
+
require 'librarian/puppet/simple/installer'
|
2
|
+
require 'librarian/puppet/simple/iterator'
|
3
|
+
require 'fileutils'
|
4
|
+
|
5
|
+
module Librarian
|
6
|
+
module Puppet
|
7
|
+
module Simple
|
8
|
+
class CLI < Thor
|
9
|
+
|
10
|
+
include Librarian::Puppet::Simple::Util
|
11
|
+
include Librarian::Puppet::Simple::Installer
|
12
|
+
include Librarian::Puppet::Simple::Iterator
|
13
|
+
|
14
|
+
class_option :verbose, :type => :boolean,
|
15
|
+
:desc => 'verbose output for executed commands'
|
16
|
+
|
17
|
+
class_option :path, :type => :string,
|
18
|
+
:desc => "overrides target directory, default is ./modules"
|
19
|
+
class_option :puppetfile, :type => :string,
|
20
|
+
:desc => "overrides used Puppetfile",
|
21
|
+
:default => './Puppetfile'
|
22
|
+
|
23
|
+
|
24
|
+
def self.bin!
|
25
|
+
start
|
26
|
+
end
|
27
|
+
|
28
|
+
desc 'install', 'installs all git sources from your Puppetfile'
|
29
|
+
method_option :clean, :type => :boolean, :desc => "calls clean before executing install"
|
30
|
+
def install
|
31
|
+
@verbose = options[:verbose]
|
32
|
+
clean if options[:clean]
|
33
|
+
@custom_module_path = options[:path]
|
34
|
+
# evaluate the file to populate @modules
|
35
|
+
eval(File.read(File.expand_path(options[:puppetfile])))
|
36
|
+
install!
|
37
|
+
end
|
38
|
+
|
39
|
+
desc 'update', 'updates all git sources from your Puppetfile'
|
40
|
+
method_option :update, :type => :boolean, :desc => "Updates git sources"
|
41
|
+
def update
|
42
|
+
@verbose = options[:verbose]
|
43
|
+
@custom_module_path = options[:path]
|
44
|
+
eval(File.read(File.expand_path(options[:puppetfile])))
|
45
|
+
each_module_of_type(:git) do |repo|
|
46
|
+
if Dir.exists?(File.join(module_path, repo[:name]))
|
47
|
+
Dir.chdir(File.join(module_path, repo[:name])) do
|
48
|
+
remote = repo[:git]
|
49
|
+
# if no ref is given, assume master
|
50
|
+
branch = repo[:ref] || 'master'
|
51
|
+
if branch =~ /^origin\/(.*)$/
|
52
|
+
branch = $1
|
53
|
+
end
|
54
|
+
co_cmd = 'git checkout FETCH_HEAD'
|
55
|
+
update_cmd = "git fetch #{repo[:git]} #{branch} && #{co_cmd}"
|
56
|
+
print_verbose "\n\n#{repo[:name]} -- #{update_cmd}"
|
57
|
+
git_pull_cmd = system_cmd(update_cmd)
|
58
|
+
end
|
59
|
+
else
|
60
|
+
install_git module_path, repo[:name], repo[:git], repo[:ref]
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
desc 'clean', 'clean modules directory'
|
66
|
+
def clean
|
67
|
+
target_directory = options[:path] || File.expand_path("./modules")
|
68
|
+
puts "Target Directory: #{target_directory}" if options[:verbose]
|
69
|
+
FileUtils.rm_rf target_directory
|
70
|
+
end
|
71
|
+
|
72
|
+
desc 'git_status', 'determine the current status of checked out git repos'
|
73
|
+
def git_status
|
74
|
+
@custom_module_path = options[:path]
|
75
|
+
# populate @modules
|
76
|
+
eval(File.read(File.expand_path(options[:puppetfile])))
|
77
|
+
each_module_of_type(:git) do |repo|
|
78
|
+
Dir.chdir(File.join(module_path, repo[:name])) do
|
79
|
+
status = system_cmd('git status')
|
80
|
+
if status.include?('nothing to commit (working directory clean)')
|
81
|
+
puts "Module #{repo[:name]} has not changed" if options[:verbose]
|
82
|
+
else
|
83
|
+
puts "Uncommitted changes for: #{repo[:name]}"
|
84
|
+
puts " #{status.join("\n ")}"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
desc 'dev_setup', 'adds development r/w remotes to each repo (assumes remote has the same name as current repo)'
|
91
|
+
def dev_setup(remote_name)
|
92
|
+
@custom_module_path = options[:path]
|
93
|
+
# populate @modules
|
94
|
+
eval(File.read(File.expand_path(options[:puppetfile])))
|
95
|
+
each_module_of_type(:git) do |repo|
|
96
|
+
Dir.chdir(File.join((options[:path] || 'modules'), repo[:name])) do
|
97
|
+
print_verbose "Adding development remote for git repo #{repo[:name]}"
|
98
|
+
remotes = system_cmd('git remote')
|
99
|
+
if remotes.include?(remote_name)
|
100
|
+
puts "Did not have to add remote #{remote_name} to #{repo[:name]}"
|
101
|
+
elsif ! remotes.include?('origin')
|
102
|
+
raise(TestException, "Repo #{repo[:name]} has no remote called origin, failing")
|
103
|
+
else
|
104
|
+
remote_url = system_cmd('git remote show origin').detect {|x| x =~ /\s+Push\s+URL: / }
|
105
|
+
if remote_url =~ /(git|https?):\/\/(.+)\/(.+)?\/(.+)/
|
106
|
+
url = "git@#{$2}:#{remote_name}/#{$4}"
|
107
|
+
puts "Adding remote #{remote_name} as #{url}"
|
108
|
+
system_cmd("git remote add #{remote_name} #{url}")
|
109
|
+
elsif remote_url =~ /^git@/
|
110
|
+
puts "Origin is already a read/write remote, skipping b/c this is unexpected"
|
111
|
+
else
|
112
|
+
puts "remote_url #{remote_url} did not have the expected format. weird..."
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
#
|
120
|
+
# I am not sure if anyone besides me (Dan Bode) should use this command.
|
121
|
+
# It is specifically for the use case where you are managing downstream versions
|
122
|
+
# of Puppet modules, where you want to track the relationship between your downstream
|
123
|
+
# forks and upstream.
|
124
|
+
# It required a specially formatted Puppetfile that expects an environment variable called
|
125
|
+
# repo_to_use that accepts the values 'upstream' and 'downstream'. It should use that environment
|
126
|
+
# variable to be able to generate either the upstream or downstream set of repos.
|
127
|
+
#
|
128
|
+
# Given those requirements, it can be used to compare the revision history differences betwee
|
129
|
+
# those commits.
|
130
|
+
#
|
131
|
+
desc 'compare_repos', 'compares the specified upstream and downstream repos'
|
132
|
+
method_option :output_file, :type => :string,
|
133
|
+
:desc => "Name of Puppetfile to save the results as"
|
134
|
+
method_option :ignore_merges, :type => :boolean,
|
135
|
+
:desc => 'Indicates that merge commits should be ignored'
|
136
|
+
method_option :show_diffs, :type => :boolean,
|
137
|
+
:desc => 'Show code differences of divergent commits (add -u)'
|
138
|
+
# I was really just using this for testing
|
139
|
+
# not sure if end users need it
|
140
|
+
method_option :existing_tmp_dir, :type => :string,
|
141
|
+
:desc => 'Uses an existing directory. Assumes the downstream repos have already been populated.'
|
142
|
+
method_option :upstream_only, :type => :boolean,
|
143
|
+
:desc => 'Only show commits that are only in the upstream'
|
144
|
+
method_option :downstream_only, :type => :boolean,
|
145
|
+
:desc => 'Only show commits that are only in downstream'
|
146
|
+
method_option :oneline, :type => :boolean,
|
147
|
+
:desc => 'Condense log output to one line'
|
148
|
+
|
149
|
+
|
150
|
+
def compare_repos
|
151
|
+
|
152
|
+
repo_hash = {}
|
153
|
+
@verbose = options[:verbose]
|
154
|
+
abort('path not supported by compare_repos command') if options[:path]
|
155
|
+
if options[:downstream_only] and options[:upstream_only]
|
156
|
+
abort('Cannot specify both downstream_only and upstream_only')
|
157
|
+
end
|
158
|
+
|
159
|
+
# create path where code will be stored
|
160
|
+
if options[:existing_tmp_dir]
|
161
|
+
path = options[:existing_tmp_dir]
|
162
|
+
else
|
163
|
+
path = File.join('.tmp', Time.now.strftime("%Y_%m_%d_%H_%S"))
|
164
|
+
end
|
165
|
+
|
166
|
+
FileUtils.mkdir_p(path)
|
167
|
+
@custom_module_path = path
|
168
|
+
|
169
|
+
# install the downstream modules in our tmp directory and build out a hash
|
170
|
+
downstream = build_puppetfile_hash('downstream', !options[:existing_tmp_dir])
|
171
|
+
# just build a hash of the downstream modules
|
172
|
+
upstream = build_puppetfile_hash('upstream', false)
|
173
|
+
|
174
|
+
unless ( (downstream.keys - upstream.keys) == [] and
|
175
|
+
(upstream.keys - downstream.keys)
|
176
|
+
)
|
177
|
+
abort('Your Puppetfile did not produce the same upstream and downstream repos, this is not yet supported')
|
178
|
+
else
|
179
|
+
|
180
|
+
upstream.each do |us_name, us_repo|
|
181
|
+
# compare to see if the source of revisions are the same
|
182
|
+
ds_repo = downstream[us_name]
|
183
|
+
if ds_repo[:git] == us_repo[:git] and ds_repo[:ref] == us_repo[:ref]
|
184
|
+
print_verbose("\nSources of #{us_name} are the same, nothing to compare.")
|
185
|
+
else
|
186
|
+
Dir.chdir(File.join(path, us_name)) do
|
187
|
+
if us_repo[:git] =~ /(git|https?):\/\/(.+)\/(.+)?\/(.+)/
|
188
|
+
remote_name = $3
|
189
|
+
remotes = system_cmd('git remote')
|
190
|
+
if remotes.include?(remote_name)
|
191
|
+
puts "Did not have to add remote #{remote_name} to #{us_repo[:name]}, it was already there"
|
192
|
+
else
|
193
|
+
puts "Adding remote #{remote_name} #{us_repo[:git]}"
|
194
|
+
system_cmd("git remote add #{remote_name} #{us_repo[:git]}")
|
195
|
+
end
|
196
|
+
system_cmd("git fetch #{remote_name}")
|
197
|
+
if us_repo[:ref] =~ /^origin\/(\S+)$/
|
198
|
+
compare_ref = "#{remote_name}/#{$1}"
|
199
|
+
else
|
200
|
+
compare_ref = "#{remote_name}/#{us_repo[:ref]}"
|
201
|
+
end
|
202
|
+
|
203
|
+
# set up parameters for git log call
|
204
|
+
ignore_merges = options[:ignore_merges] ? '--no-merges' : ''
|
205
|
+
show_diffs = options[:show_diffs] ? '-u' : ''
|
206
|
+
oneline = options[:oneline] ? '--oneline' : ''
|
207
|
+
# show the results, this assumes that HEAD is up-to-date (which it should be)
|
208
|
+
|
209
|
+
if options[:downstream_only] and options[:upstream_only]
|
210
|
+
abort('Cannot specify both downstream_only and upstream_only')
|
211
|
+
end
|
212
|
+
puts "########## Results for #{us_name} ##########"
|
213
|
+
unless options[:upstream_only]
|
214
|
+
puts " ######## Commits only in downstream ########"
|
215
|
+
results = system_cmd("git log --left-only HEAD...#{compare_ref} #{ignore_merges} #{show_diffs} #{oneline}", true)
|
216
|
+
puts " ######## End Downstream results ########"
|
217
|
+
end
|
218
|
+
unless options[:downstream_only]
|
219
|
+
puts " ######## Commits only in upstream ########"
|
220
|
+
results = system_cmd("git log --right-only HEAD...#{compare_ref} #{ignore_merges} #{show_diffs} #{oneline}", true)
|
221
|
+
puts " ######## End upstream ########"
|
222
|
+
end
|
223
|
+
puts "########## End of Results for #{us_name} ##########"
|
224
|
+
else
|
225
|
+
abort("Unrecognizable upstream url #{us_repo[:git]}")
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
desc 'generate_puppetfile', 'generates a static version of the Puppetfile'
|
234
|
+
method_option :out_file,
|
235
|
+
:desc => 'output file where static puppetfile should be written to'
|
236
|
+
def generate_puppetfile
|
237
|
+
eval(File.read(File.expand_path(options[:puppetfile])))
|
238
|
+
if options[:out_file]
|
239
|
+
File.open(options[:out_file], 'w') do |fh|
|
240
|
+
print_puppet_file(fh)
|
241
|
+
end
|
242
|
+
else
|
243
|
+
print_puppet_file(STDOUT)
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
private
|
248
|
+
|
249
|
+
def print_puppet_file(stream)
|
250
|
+
each_module do |repo|
|
251
|
+
repo.delete(:name)
|
252
|
+
out_str = repo.delete(:full_name)
|
253
|
+
repo.each do |k,v|
|
254
|
+
out_str << ", :#{k} => #{v}"
|
255
|
+
end
|
256
|
+
stream.puts(out_str)
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
# builds out a certain type of repo
|
261
|
+
def build_puppetfile_hash(name, perform_installation=false)
|
262
|
+
repo_hash = {}
|
263
|
+
# set environment variable to determine what version of modules to install
|
264
|
+
# this assumes that the environment variable repos_to_use has been coded in
|
265
|
+
# your Puppetfile to allow installation of different versions of modules
|
266
|
+
ENV['repos_to_use'] = name
|
267
|
+
# parse Puppetfile and install modules in our tmp directory.
|
268
|
+
eval(File.read(File.expand_path(options[:puppetfile])))
|
269
|
+
# install modules if desired
|
270
|
+
install! if perform_installation
|
271
|
+
|
272
|
+
# iterate through all git modules
|
273
|
+
each_module_of_type(:git) do |git_repo|
|
274
|
+
abort("Module git_repo[:name] was defined multiple times in same Puppetfile") if repo_hash[git_repo[:name]]
|
275
|
+
repo_hash[git_repo[:name]] = git_repo
|
276
|
+
end
|
277
|
+
# clear out the modules once finished
|
278
|
+
clear_modules
|
279
|
+
repo_hash
|
280
|
+
end
|
281
|
+
|
282
|
+
end
|
283
|
+
end
|
284
|
+
end
|
285
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'rubygems/package'
|
3
|
+
require 'zlib'
|
4
|
+
require 'open-uri'
|
5
|
+
require 'librarian/puppet/simple/util'
|
6
|
+
require 'librarian/puppet/simple/iterator'
|
7
|
+
|
8
|
+
# This is an extremely simple file that can consume
|
9
|
+
# a Puppet file with git references
|
10
|
+
#
|
11
|
+
# It does absolutely no dependency resolution by design.
|
12
|
+
#
|
13
|
+
module Librarian
|
14
|
+
module Puppet
|
15
|
+
module Simple
|
16
|
+
module Installer
|
17
|
+
|
18
|
+
include Librarian::Puppet::Simple::Util
|
19
|
+
include Librarian::Puppet::Simple::Iterator
|
20
|
+
|
21
|
+
# installs modules using the each_module method from our
|
22
|
+
# iterator mixin
|
23
|
+
def install!
|
24
|
+
each_module do |repo|
|
25
|
+
|
26
|
+
print_verbose "\n##### processing module #{repo[:name]}..."
|
27
|
+
|
28
|
+
module_dir = File.join(module_path, repo[:name])
|
29
|
+
|
30
|
+
unless File.exists?(module_dir)
|
31
|
+
case
|
32
|
+
when repo[:git]
|
33
|
+
install_git module_path, repo[:name], repo[:git], repo[:ref]
|
34
|
+
when repo[:tarball]
|
35
|
+
install_tarball module_path, repo[:name], repo[:tarball]
|
36
|
+
else
|
37
|
+
abort('only the :git and :tarball provider are currently supported')
|
38
|
+
end
|
39
|
+
else
|
40
|
+
print_verbose "\nModule #{repo[:name]} already installed in #{module_path}"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
# installs sources that are git repos
|
48
|
+
def install_git(module_path, module_name, repo, ref = nil)
|
49
|
+
module_dir = File.join(module_path, module_name)
|
50
|
+
|
51
|
+
Dir.chdir(module_path) do
|
52
|
+
print_verbose "cloning #{repo}"
|
53
|
+
system_cmd("git clone #{repo} #{module_name}")
|
54
|
+
Dir.chdir(module_dir) do
|
55
|
+
system_cmd('git branch -r')
|
56
|
+
system_cmd("git checkout -f #{ref}") if ref
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def install_tarball(module_path, module_name, remote_tarball)
|
62
|
+
Dir.mktmpdir do |tmp|
|
63
|
+
temp_file = File.join(tmp,"downloaded_module.tar.gz")
|
64
|
+
File.open(temp_file, "w+b") do |saved_file|
|
65
|
+
print_verbose "Downloading #{remote_tarball}..."
|
66
|
+
open(remote_tarball, 'rb') do |read_file|
|
67
|
+
saved_file.write(read_file.read)
|
68
|
+
end
|
69
|
+
saved_file.rewind
|
70
|
+
|
71
|
+
target_directory = File.join(module_path, module_name)
|
72
|
+
print_verbose "Extracting #{remote_tarball} to #{target_directory}..."
|
73
|
+
unzipped_target = ungzip(saved_file)
|
74
|
+
tarfile_full_name = untar(unzipped_target, module_path)
|
75
|
+
FileUtils.mv File.join(module_path, tarfile_full_name), target_directory
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# un-gzips the given IO, returning the
|
81
|
+
# decompressed version as a StringIO
|
82
|
+
def ungzip(tarfile)
|
83
|
+
z = Zlib::GzipReader.new(tarfile)
|
84
|
+
unzipped = StringIO.new(z.read)
|
85
|
+
z.close
|
86
|
+
unzipped
|
87
|
+
end
|
88
|
+
|
89
|
+
# untars the given IO into the specified
|
90
|
+
# directory
|
91
|
+
def untar(io, destination)
|
92
|
+
tarfile_full_name = nil
|
93
|
+
Gem::Package::TarReader.new io do |tar|
|
94
|
+
tar.each do |tarfile|
|
95
|
+
tarfile_full_name ||= tarfile.full_name
|
96
|
+
destination_file = File.join destination, tarfile.full_name
|
97
|
+
if tarfile.directory?
|
98
|
+
FileUtils.mkdir_p destination_file
|
99
|
+
else
|
100
|
+
destination_directory = File.dirname(destination_file)
|
101
|
+
FileUtils.mkdir_p destination_directory unless File.directory?(destination_directory)
|
102
|
+
File.open destination_file, "wb" do |f|
|
103
|
+
f.write tarfile.read
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
tarfile_full_name
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'librarian/puppet/simple/util'
|
2
|
+
|
3
|
+
module Librarian
|
4
|
+
module Puppet
|
5
|
+
module Simple
|
6
|
+
module Iterator
|
7
|
+
|
8
|
+
# evaluate a module and add it our @modules instance variable
|
9
|
+
def mod(name, options = {})
|
10
|
+
@modules ||= {}
|
11
|
+
full_name = name
|
12
|
+
module_name = name.split('/', 2).last
|
13
|
+
|
14
|
+
case
|
15
|
+
when options[:git]
|
16
|
+
@modules[:git] ||= {}
|
17
|
+
@modules[:git][module_name] = options.merge(:name => module_name, :full_name => full_name)
|
18
|
+
when options[:tarball]
|
19
|
+
@modules[:tarball] ||= {}
|
20
|
+
@modules[:tarball][module_name] = options.merge(:name => module_name, :full_name => full_name)
|
21
|
+
else
|
22
|
+
@modules[:forge] ||= {}
|
23
|
+
@modules[:forge][module_name] = options.merge(:name => module_name, :full_name => full_name)
|
24
|
+
#abort('only the :git and :tarball providers are currently supported')
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def modules
|
29
|
+
@modules
|
30
|
+
end
|
31
|
+
|
32
|
+
def clear_modules
|
33
|
+
@modules = nil
|
34
|
+
end
|
35
|
+
|
36
|
+
# iterate through all modules
|
37
|
+
def each_module(&block)
|
38
|
+
(@modules || {}).each do |type, repos|
|
39
|
+
(repos || {}).values.each do |repo|
|
40
|
+
yield repo
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# loop over each module of a certain type
|
46
|
+
def each_module_of_type(type, &block)
|
47
|
+
abort("undefined type #{type}") unless [:git, :tarball].include?(type)
|
48
|
+
((@modules || {})[type] || {}).values.each do |repo|
|
49
|
+
yield repo
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
#
|
2
|
+
# this module contains all of the base helper methods
|
3
|
+
# used by the other actions
|
4
|
+
#
|
5
|
+
module Librarian
|
6
|
+
module Puppet
|
7
|
+
module Simple
|
8
|
+
module Util
|
9
|
+
|
10
|
+
def forge(repo)
|
11
|
+
# this does nothing atm
|
12
|
+
end
|
13
|
+
# figure out what directory we are working out og
|
14
|
+
def base_dir
|
15
|
+
@base_dir ||= Dir.pwd
|
16
|
+
end
|
17
|
+
|
18
|
+
# figure out what the modulepath is
|
19
|
+
def module_path(dir=base_dir)
|
20
|
+
unless @module_path
|
21
|
+
if @custom_module_path
|
22
|
+
@module_path = File.expand_path @custom_module_path
|
23
|
+
else
|
24
|
+
@module_path = File.join(dir, 'modules')
|
25
|
+
end
|
26
|
+
Dir.mkdir(@module_path) unless File.exists?(@module_path)
|
27
|
+
end
|
28
|
+
@module_path
|
29
|
+
end
|
30
|
+
|
31
|
+
# run a command on the system
|
32
|
+
def system_cmd (cmd, print_output=false)
|
33
|
+
print_verbose "Running cmd: #{cmd}"
|
34
|
+
output = `#{cmd}`.split("\n")
|
35
|
+
if print_output
|
36
|
+
puts output
|
37
|
+
else
|
38
|
+
print_verbose output
|
39
|
+
end
|
40
|
+
raise(StandardError, "Cmd #{cmd} failed") unless $?.success?
|
41
|
+
output
|
42
|
+
end
|
43
|
+
|
44
|
+
def print_verbose(text)
|
45
|
+
puts text if @verbose
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
$:.push File.expand_path("../lib", __FILE__)
|
2
|
+
|
3
|
+
require 'librarian/puppet/simple/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = 'librarian-puppet-simple-force'
|
7
|
+
s.version = Librarian::Puppet::Simple::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ['Jon McCreery']
|
10
|
+
s.email = ['jonathan.mccreery@nytimes.com']
|
11
|
+
s.homepage = 'https://github.com/jonmccreery/librarian-puppet-simple-force'
|
12
|
+
s.summary = 'Bundler for your Puppet modules, with force'
|
13
|
+
s.description = 'Simplify deployment of your Puppet infrastructure by
|
14
|
+
automatically pulling in modules from the forge and git repositories with
|
15
|
+
a single command.'
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split($/)
|
18
|
+
s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
19
|
+
s.test_files = s.files.grep(%r{^(test|spec|features)/})
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
|
22
|
+
s.add_dependency "thor", "~> 0.15"
|
23
|
+
|
24
|
+
s.add_development_dependency "rspec", "~> 2.13"
|
25
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
mod 'puppetlabs/ntp',
|
2
|
+
:git => 'git://github.com/puppetlabs/puppetlabs-ntp.git',
|
3
|
+
:ref => '99bae40f225db0dd052efbf1d4078a21f0333331'
|
4
|
+
|
5
|
+
mod 'apache',
|
6
|
+
:tarball => 'https://forge.puppetlabs.com/puppetlabs/apache/0.6.0.tar.gz'
|
7
|
+
|
8
|
+
mod 'ghoneycutt/testlps',
|
9
|
+
:git => 'git://github.com/ghoneycutt/testlps.git'
|
10
|
+
|
11
|
+
mod 'ghoneycutt/dnsclient',
|
12
|
+
:git => 'git://github.com/ghoneycutt/puppet-module-dnsclient.git',
|
13
|
+
:ref => 'v3.0.4'
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'tmpdir'
|
4
|
+
|
5
|
+
describe "Functional - Clean" do
|
6
|
+
it "displays install help message" do
|
7
|
+
output, status = execute_captured("bin/librarian-puppet help clean")
|
8
|
+
output.should_not include("ERROR")
|
9
|
+
output.should_not include("Could not find command")
|
10
|
+
status.should == 0
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "when running 'librarian-puppet clean'" do
|
14
|
+
temp_directory = nil
|
15
|
+
|
16
|
+
before :each do
|
17
|
+
temp_directory = Dir.mktmpdir
|
18
|
+
Dir.entries(temp_directory).should =~ ['.', '..']
|
19
|
+
FileUtils.touch File.join(temp_directory, 'trashfile')
|
20
|
+
Dir.entries(temp_directory).should =~ ['.', '..', 'trashfile']
|
21
|
+
end
|
22
|
+
|
23
|
+
after :each do
|
24
|
+
FileUtils.rm_rf temp_directory if File.exist?(temp_directory)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "with --path it cleans the directory" do
|
28
|
+
output, status = execute_captured("bin/librarian-puppet clean --path=#{temp_directory}")
|
29
|
+
|
30
|
+
status.should == 0
|
31
|
+
# Using File.exist? to be compatible with Ruby 1.8.7
|
32
|
+
File.exist?(temp_directory).should be_false
|
33
|
+
end
|
34
|
+
|
35
|
+
it "with --verbose it shows progress messages" do
|
36
|
+
output, status = execute_captured("bin/librarian-puppet clean --verbose --path=#{temp_directory}")
|
37
|
+
|
38
|
+
status.should == 0
|
39
|
+
output.should include("Target Directory: #{temp_directory}")
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'tmpdir'
|
4
|
+
|
5
|
+
describe "Functional - Install" do
|
6
|
+
before :all do
|
7
|
+
warning_message = "ATTENTION: these tests download information from github.com and forge.puppetlabs.com"
|
8
|
+
puts '*' * warning_message.length
|
9
|
+
puts warning_message
|
10
|
+
puts '*' * warning_message.length
|
11
|
+
end
|
12
|
+
|
13
|
+
it "displays install help message" do
|
14
|
+
output, status = execute_captured("bin/librarian-puppet help install")
|
15
|
+
output.should_not include("ERROR")
|
16
|
+
output.should_not include("Could not find command")
|
17
|
+
status.should == 0
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "when running 'librarian-puppet install'" do
|
21
|
+
temp_directory = nil
|
22
|
+
|
23
|
+
before :each do
|
24
|
+
temp_directory = Dir.mktmpdir
|
25
|
+
Dir.entries(temp_directory).should =~ ['.', '..']
|
26
|
+
FileUtils.touch File.join(temp_directory, 'trashfile')
|
27
|
+
Dir.entries(temp_directory).should =~ ['.', '..', 'trashfile']
|
28
|
+
end
|
29
|
+
|
30
|
+
after :each do
|
31
|
+
FileUtils.rm_rf temp_directory
|
32
|
+
end
|
33
|
+
|
34
|
+
it "install the modules in a temp directory" do
|
35
|
+
output, status = execute_captured("bin/librarian-puppet install --path=#{temp_directory} --puppetfile=spec/fixtures/Puppetfile")
|
36
|
+
|
37
|
+
status.should == 0
|
38
|
+
Dir.entries(temp_directory).should =~ %w|. .. apache ntp trashfile dnsclient testlps|
|
39
|
+
end
|
40
|
+
|
41
|
+
it "with --clean it cleans the directory before installing the modules in a temp directory" do
|
42
|
+
output, status = execute_captured("bin/librarian-puppet install --clean --path=#{temp_directory} --puppetfile=spec/fixtures/Puppetfile")
|
43
|
+
|
44
|
+
status.should == 0
|
45
|
+
Dir.entries(temp_directory).should =~ %w|. .. apache ntp dnsclient testlps|
|
46
|
+
end
|
47
|
+
|
48
|
+
it "with --verbose it outputs progress messages" do
|
49
|
+
output, status = execute_captured("bin/librarian-puppet install --verbose --path=#{temp_directory} --puppetfile=spec/fixtures/Puppetfile")
|
50
|
+
|
51
|
+
status.should == 0
|
52
|
+
output.should include('##### processing module apache')
|
53
|
+
end
|
54
|
+
|
55
|
+
describe 'when modules are already installed' do
|
56
|
+
temp_directory = nil
|
57
|
+
|
58
|
+
before :each do
|
59
|
+
temp_directory = Dir.mktmpdir
|
60
|
+
Dir.entries(temp_directory).should =~ ['.', '..']
|
61
|
+
FileUtils.touch File.join(temp_directory, 'apache')
|
62
|
+
Dir.entries(temp_directory).should =~ ['.', '..', 'apache']
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'without clean it should only install ntp' do
|
66
|
+
output, status = execute_captured("bin/librarian-puppet install --verbose --path=#{temp_directory} --puppetfile=spec/fixtures/Puppetfile")
|
67
|
+
status.should == 0
|
68
|
+
output.should include('Module apache already installed')
|
69
|
+
Dir.entries(temp_directory).should =~ %w|. .. apache ntp dnsclient testlps|
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# This file was generated by the `rspec --init` command. Conventionally, all
|
2
|
+
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
3
|
+
# Require this file using `require "spec_helper"` to ensure that it is only
|
4
|
+
# loaded once.
|
5
|
+
#
|
6
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
7
|
+
require 'open3'
|
8
|
+
|
9
|
+
RSpec.configure do |config|
|
10
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
11
|
+
config.run_all_when_everything_filtered = true
|
12
|
+
config.filter_run :focus
|
13
|
+
|
14
|
+
# Run specs in random order to surface order dependencies. If you find an
|
15
|
+
# order dependency and want to debug it, you can fix the order by providing
|
16
|
+
# the seed, which is printed after each run.
|
17
|
+
# --seed 1234
|
18
|
+
config.order = 'random'
|
19
|
+
|
20
|
+
def execute_captured(command)
|
21
|
+
stdin, stdout, stderr = Open3.popen3(command)
|
22
|
+
condensed = stdout.readlines.join + stderr.readlines.join
|
23
|
+
[condensed, $?.exitstatus]
|
24
|
+
end
|
25
|
+
end
|
metadata
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: librarian-puppet-simple-force
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.5
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jon McCreery
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-05-31 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: thor
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.15'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.15'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rspec
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '2.13'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '2.13'
|
41
|
+
description: |-
|
42
|
+
Simplify deployment of your Puppet infrastructure by
|
43
|
+
automatically pulling in modules from the forge and git repositories with
|
44
|
+
a single command.
|
45
|
+
email:
|
46
|
+
- jonathan.mccreery@nytimes.com
|
47
|
+
executables:
|
48
|
+
- librarian-puppet
|
49
|
+
extensions: []
|
50
|
+
extra_rdoc_files: []
|
51
|
+
files:
|
52
|
+
- .gitignore
|
53
|
+
- Gemfile
|
54
|
+
- LICENSE
|
55
|
+
- README.md
|
56
|
+
- bin/librarian-puppet
|
57
|
+
- lib/librarian/puppet/simple.rb
|
58
|
+
- lib/librarian/puppet/simple/cli.rb
|
59
|
+
- lib/librarian/puppet/simple/installer.rb
|
60
|
+
- lib/librarian/puppet/simple/iterator.rb
|
61
|
+
- lib/librarian/puppet/simple/util.rb
|
62
|
+
- lib/librarian/puppet/simple/version.rb
|
63
|
+
- librarian-puppet-simple-force.gemspec
|
64
|
+
- spec/fixtures/Puppetfile
|
65
|
+
- spec/functional/clean_spec.rb
|
66
|
+
- spec/functional/install_spec.rb
|
67
|
+
- spec/spec_helper.rb
|
68
|
+
homepage: https://github.com/jonmccreery/librarian-puppet-simple-force
|
69
|
+
licenses: []
|
70
|
+
metadata: {}
|
71
|
+
post_install_message:
|
72
|
+
rdoc_options: []
|
73
|
+
require_paths:
|
74
|
+
- lib
|
75
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
76
|
+
requirements:
|
77
|
+
- - '>='
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: '0'
|
80
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
81
|
+
requirements:
|
82
|
+
- - '>='
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: '0'
|
85
|
+
requirements: []
|
86
|
+
rubyforge_project:
|
87
|
+
rubygems_version: 2.0.14.1
|
88
|
+
signing_key:
|
89
|
+
specification_version: 4
|
90
|
+
summary: Bundler for your Puppet modules, with force
|
91
|
+
test_files:
|
92
|
+
- spec/fixtures/Puppetfile
|
93
|
+
- spec/functional/clean_spec.rb
|
94
|
+
- spec/functional/install_spec.rb
|
95
|
+
- spec/spec_helper.rb
|