berks-monolith 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +12 -0
- data/.travis.yml +6 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +22 -0
- data/README.md +63 -0
- data/Rakefile +8 -0
- data/berks-monolith.gemspec +29 -0
- data/bin/berks-monolith +6 -0
- data/lib/monolith.rb +12 -0
- data/lib/monolith/berksfile.rb +69 -0
- data/lib/monolith/commands.rb +71 -0
- data/lib/monolith/formatter.rb +50 -0
- data/lib/monolith/gitexclude.rb +54 -0
- data/lib/monolith/locations/base.rb +37 -0
- data/lib/monolith/locations/default.rb +24 -0
- data/lib/monolith/locations/git.rb +60 -0
- data/lib/monolith/locations/github.rb +6 -0
- data/lib/monolith/locations/path.rb +23 -0
- data/lib/monolith/version.rb +3 -0
- data/test/.gitignore +1 -0
- data/test/helpers.rb +62 -0
- data/test/test_command_clean.rb +30 -0
- data/test/test_command_install.rb +25 -0
- data/test/test_command_update.rb +32 -0
- data/test/test_gitlocation.rb +48 -0
- metadata +154 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 6e00e4691862cc03e4cca97a0722ad297e535391
|
4
|
+
data.tar.gz: 4183cdf8be169fc1b52c22f83e9f0fb4c8d49115
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: caf6a7a55dd3b38d1e6fde05e7df7efddd6f6c8aa247af5b835aad685d455db71015cda82e1d2d9046cf84ae24d3b8340941be58973afff3a1f095dd9eb79496
|
7
|
+
data.tar.gz: 82ff7940b2e02d68125bc479c40a2c27f06af2d712bc00b4d367d6a49588e8f8be28da8d40e7eaca5b9429901785a067baeffe174535adc0af8d05cd6f968fce
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Mark Harrison
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
[![Stories in Ready](https://badge.waffle.io/mivok/berks-monolith.png?label=ready&title=Ready)](https://waffle.io/mivok/berks-monolith)
|
2
|
+
[![Build Status](https://travis-ci.org/mivok/berks-monolith.svg?branch=master)](https://travis-ci.org/mivok/berks-monolith)
|
3
|
+
|
4
|
+
# berks-monolith
|
5
|
+
|
6
|
+
Berks-monolith is a companion command to berkshelf that takes all cookbooks
|
7
|
+
mentioned in a Berksfile and places development friendly versions of them
|
8
|
+
under a single directory. Usually, this means you will end up with git clones
|
9
|
+
for all cookbooks with git repositories in the Berksfile, and static copies of
|
10
|
+
cookbooks that don't have identifiable VCS repositories.
|
11
|
+
|
12
|
+
## Use cases
|
13
|
+
|
14
|
+
* You have a Berksfile with many git based sources, and want a quick way to
|
15
|
+
clone them all under a single directory.
|
16
|
+
* You have a mostly monolithic repository, but make use of berkshelf to manage
|
17
|
+
dependencies and use external cookbook sources, and you'd like to have
|
18
|
+
everything in one place to be able to search.
|
19
|
+
* You are transitioning between a monolithic repository workflow and a
|
20
|
+
independent software artefacts workflow, and have a mix of artefacts in a
|
21
|
+
Berksfile as well as cookbooks in a monolithic repository, and you want all
|
22
|
+
cookbooks in one place.
|
23
|
+
|
24
|
+
## Why not just use X?
|
25
|
+
|
26
|
+
The `berks vendor` command comes close to what monolith does, grabbing all
|
27
|
+
cookbooks mentioned in a Berksfile and putting copies of them under a single
|
28
|
+
directory. However, berks vendor is intended for production rather than
|
29
|
+
development use, and explicitly strips any VCS directories, chef ignored
|
30
|
+
files, and metadata.rb files.
|
31
|
+
|
32
|
+
The `berks install` command collects all cookbooks into
|
33
|
+
`~/.berkshelf/cookbooks`, but again VCS information is stripped out, and this
|
34
|
+
contains all cookbooks, not just those associated with a specific Berksfile.
|
35
|
+
|
36
|
+
## Usage
|
37
|
+
|
38
|
+
### berks-monolith install
|
39
|
+
|
40
|
+
Clones/copies all cookbooks mentioned in the berksfile. By default they go
|
41
|
+
into the 'cookbooks' directory. You can specify an alternate path if you wish
|
42
|
+
by specifying it on the command line: `berks-monolith install vendor`.
|
43
|
+
|
44
|
+
Exactly what you get depends on what the source of the cookbook is in the
|
45
|
+
berksfile:
|
46
|
+
|
47
|
+
* Normal community cookbooks (e.g. if you just specify `cookbook 'foo'` with
|
48
|
+
no other options) are just copied in place from the berkshelf directory.
|
49
|
+
* Git cookbooks will result in a clone of the repository pointing to the
|
50
|
+
original source repository.
|
51
|
+
* Path cookbooks will be skipped completely. This means you don't have to
|
52
|
+
worry if you have existing local cookbooks in a monolithic repository in
|
53
|
+
your Berksfile. They won't be copied again.
|
54
|
+
|
55
|
+
### berks-monolith update
|
56
|
+
|
57
|
+
Updates the cloned copies of cookbooks if possible. In practice this means
|
58
|
+
'run git pull' for all git clones.
|
59
|
+
|
60
|
+
### berks-monolith clean
|
61
|
+
|
62
|
+
Removes all cookbooks that were installed with `berks-monolith install`.
|
63
|
+
Anything else in the cookbooks directory is left alone.
|
data/Rakefile
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'monolith/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "berks-monolith"
|
8
|
+
spec.version = Monolith::VERSION
|
9
|
+
spec.authors = ["Mark Harrison"]
|
10
|
+
spec.email = ["mark@mivok.net"]
|
11
|
+
spec.summary = %q{Berkshelf monolithic repository tools}
|
12
|
+
spec.description = %q{Tools for working with cookbooks as if they were inside a monolithic repository}
|
13
|
+
spec.homepage = "http://github.com/mivok/berks-monolith"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.required_ruby_version = '>= 1.9.2'
|
22
|
+
|
23
|
+
spec.add_dependency 'berkshelf', '~> 3.0', '>= 3.0.0'
|
24
|
+
|
25
|
+
spec.add_development_dependency 'bundler', '~> 1.5'
|
26
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
27
|
+
spec.add_development_dependency 'minitest', '~> 5.0'
|
28
|
+
spec.add_development_dependency 'pry', '~> 0.10'
|
29
|
+
end
|
data/bin/berks-monolith
ADDED
data/lib/monolith.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require_relative 'monolith/commands'
|
2
|
+
|
3
|
+
require_relative 'monolith/locations/git'
|
4
|
+
require_relative 'monolith/locations/github'
|
5
|
+
require_relative 'monolith/locations/path'
|
6
|
+
require_relative 'monolith/locations/default'
|
7
|
+
|
8
|
+
module Monolith
|
9
|
+
def self.formatter
|
10
|
+
@formatter ||= Monolith::Formatter.new
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'berkshelf'
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
module Monolith
|
5
|
+
class Berksfile
|
6
|
+
attr_reader :berksfile
|
7
|
+
|
8
|
+
def initialize(options)
|
9
|
+
Berkshelf.ui.mute! if Monolith.formatter.quiet
|
10
|
+
begin
|
11
|
+
@berksfile = Berkshelf::Berksfile.from_options(options)
|
12
|
+
rescue Berkshelf::BerksfileNotFound => e
|
13
|
+
Monolith.formatter.error(e)
|
14
|
+
exit(e.status_code)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# Runs berks install. This is needed before we install cookbooks ourselves
|
19
|
+
# to make sure berkshelf has a local copy of them for us to clone from or
|
20
|
+
# copy. However, it's not needed for other commands, so it separated out
|
21
|
+
# here.
|
22
|
+
def install
|
23
|
+
@berksfile.install
|
24
|
+
end
|
25
|
+
|
26
|
+
# Retrieve all cookbooks listed in the berksfile.
|
27
|
+
#
|
28
|
+
# Can take a block to do something with each cookbook.
|
29
|
+
def cookbooks(path)
|
30
|
+
FileUtils.mkdir_p(path)
|
31
|
+
cached_cookbooks = @berksfile.cookbooks
|
32
|
+
if block_given?
|
33
|
+
cached_cookbooks.each do |cookbook|
|
34
|
+
destination = File.join(File.expand_path(path),
|
35
|
+
cookbook.cookbook_name)
|
36
|
+
dep = berksfile.get_dependency(cookbook.cookbook_name)
|
37
|
+
if dep
|
38
|
+
yield cookbook, dep, destination
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
cached_cookbooks
|
43
|
+
end
|
44
|
+
|
45
|
+
def monolith_action(action, cookbook, dep, destination)
|
46
|
+
obj = monolith_obj(cookbook, dep, destination)
|
47
|
+
if obj.nil?
|
48
|
+
Monolith.formatter.unsupported_location(cookbook, dep)
|
49
|
+
else
|
50
|
+
obj.send(action)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Feteches the appropriate monolith location object for a given cookbook
|
55
|
+
# dependency. I.e. Monolith::FooLocation.
|
56
|
+
def monolith_obj(cookbook, dep, destination)
|
57
|
+
if dep.location.nil?
|
58
|
+
Monolith::DefaultLocation.new(cookbook, dep, destination)
|
59
|
+
else
|
60
|
+
klass = dep.location.class.name.split('::')[-1]
|
61
|
+
Monolith.formatter.debug("Location class for " \
|
62
|
+
"#{cookbook.cookbook_name} is #{klass}")
|
63
|
+
if Monolith.const_defined?(klass)
|
64
|
+
Monolith.const_get(klass).new(cookbook, dep, destination)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require 'monolith/berksfile'
|
3
|
+
require 'monolith/formatter'
|
4
|
+
require 'monolith/gitexclude'
|
5
|
+
|
6
|
+
module Monolith
|
7
|
+
class Command < Thor
|
8
|
+
namespace ''
|
9
|
+
|
10
|
+
class_option :quiet,
|
11
|
+
:type => :boolean,
|
12
|
+
:desc => "Don't print out any informational messages",
|
13
|
+
:aliases => '-q',
|
14
|
+
:default => false
|
15
|
+
|
16
|
+
class_option :debug,
|
17
|
+
:type => :boolean,
|
18
|
+
:desc => 'Print additional debug messages',
|
19
|
+
:aliases => '-d',
|
20
|
+
:default => false
|
21
|
+
|
22
|
+
class_option :berksfile,
|
23
|
+
:desc => 'Location of the Berksfile to use',
|
24
|
+
:aliases => '-b'
|
25
|
+
|
26
|
+
class_option :git_exclude,
|
27
|
+
:type => :boolean,
|
28
|
+
:desc => 'Add installed cookbooks to git exclude file',
|
29
|
+
:default => true
|
30
|
+
|
31
|
+
def initialize(*args)
|
32
|
+
super(*args)
|
33
|
+
|
34
|
+
Monolith.formatter.quiet = @options[:quiet]
|
35
|
+
Monolith.formatter.debug = @options[:debug]
|
36
|
+
end
|
37
|
+
|
38
|
+
desc 'install [PATH]', 'Clone all cookbooks into the cookbooks directory'
|
39
|
+
def install(path = File.join(Dir.pwd, "cookbooks"))
|
40
|
+
berksfile = Monolith::Berksfile.new(options.dup)
|
41
|
+
berksfile.install # We need to run berks install first
|
42
|
+
gitpath = File.expand_path('../.git', berksfile.berksfile.filepath)
|
43
|
+
gitexclude = GitExclude.new(gitpath, options)
|
44
|
+
berksfile.cookbooks(path) do |cookbook, dep, destination|
|
45
|
+
berksfile.monolith_action(:install, cookbook, dep, destination)
|
46
|
+
gitexclude.add(destination)
|
47
|
+
end
|
48
|
+
gitexclude.update
|
49
|
+
end
|
50
|
+
|
51
|
+
desc 'update [PATH]', 'Update all cloned cookbooks'
|
52
|
+
def update(path = File.join(Dir.pwd, "cookbooks"))
|
53
|
+
berksfile = Monolith::Berksfile.new(options.dup)
|
54
|
+
berksfile.cookbooks(path) do |cookbook, dep, destination|
|
55
|
+
berksfile.monolith_action(:update, cookbook, dep, destination)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
desc 'clean [PATH]', 'Delete all cloned cookbooks'
|
60
|
+
def clean(path = File.join(Dir.pwd, "cookbooks"))
|
61
|
+
berksfile = Monolith::Berksfile.new(options.dup)
|
62
|
+
gitpath = File.expand_path('../.git', berksfile.berksfile.filepath)
|
63
|
+
gitexclude = GitExclude.new(gitpath, options)
|
64
|
+
berksfile.cookbooks(path) do |cookbook, dep, destination|
|
65
|
+
berksfile.monolith_action(:clean, cookbook, dep, destination)
|
66
|
+
gitexclude.remove(destination)
|
67
|
+
end
|
68
|
+
gitexclude.update
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Monolith
|
2
|
+
class Formatter
|
3
|
+
attr_accessor :quiet
|
4
|
+
attr_accessor :debug
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@quiet = false
|
8
|
+
@debug = false
|
9
|
+
@base_path = Pathname.new(Dir.pwd)
|
10
|
+
end
|
11
|
+
|
12
|
+
def install(cookbook, destination)
|
13
|
+
msg "Installing #{cookbook.cookbook_name} to #{rel_dir(destination)}"
|
14
|
+
end
|
15
|
+
|
16
|
+
def update(cookbook, destination)
|
17
|
+
msg "Updating #{cookbook.cookbook_name} at #{rel_dir(destination)}"
|
18
|
+
end
|
19
|
+
|
20
|
+
def clean(cookbook, destination)
|
21
|
+
msg "Removing #{cookbook.cookbook_name} from #{rel_dir(destination)}"
|
22
|
+
end
|
23
|
+
|
24
|
+
def skip(cookbook, reason)
|
25
|
+
msg "Skipping #{cookbook.cookbook_name} (#{reason})"
|
26
|
+
end
|
27
|
+
|
28
|
+
def unsupported_location(cookbook, dep)
|
29
|
+
loctype = dep.location.class.name.split('::')[-1]
|
30
|
+
msg "Unsupported location type #{loctype} for cookbook " \
|
31
|
+
"#{cookbook.cookbook_name}. Skipping."
|
32
|
+
end
|
33
|
+
|
34
|
+
def debug(msg)
|
35
|
+
puts "DEBUG: #{msg}" if @debug
|
36
|
+
end
|
37
|
+
|
38
|
+
def msg(msg)
|
39
|
+
puts msg unless @quiet
|
40
|
+
end
|
41
|
+
|
42
|
+
def error(msg)
|
43
|
+
STDERR.puts msg
|
44
|
+
end
|
45
|
+
|
46
|
+
def rel_dir(dir)
|
47
|
+
return Pathname.new(dir).relative_path_from(@base_path)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Monolith
|
2
|
+
class GitExclude
|
3
|
+
def initialize(git_dir, options)
|
4
|
+
@lines_to_add = []
|
5
|
+
@lines_to_remove = []
|
6
|
+
@git_dir = Pathname.new(git_dir)
|
7
|
+
@filename = @git_dir.join('info', 'exclude')
|
8
|
+
@enabled = options[:git_exclude]
|
9
|
+
end
|
10
|
+
|
11
|
+
def relative_path(path)
|
12
|
+
Pathname.new(path).relative_path_from(@git_dir.parent).to_s
|
13
|
+
end
|
14
|
+
|
15
|
+
def add(line)
|
16
|
+
@lines_to_add << relative_path(line)
|
17
|
+
end
|
18
|
+
|
19
|
+
def remove(line)
|
20
|
+
@lines_to_remove << relative_path(line)
|
21
|
+
end
|
22
|
+
|
23
|
+
def update
|
24
|
+
return unless @enabled
|
25
|
+
|
26
|
+
# We don't want to do anything if we're not actually in a git repo
|
27
|
+
return unless File.directory?(@git_dir)
|
28
|
+
|
29
|
+
if File.exist?(@filename)
|
30
|
+
data = File.read(@filename).split("\n")
|
31
|
+
else
|
32
|
+
data = []
|
33
|
+
end
|
34
|
+
# Don't go creating a file if there's nothing to add and we're already
|
35
|
+
# empty
|
36
|
+
return if data.empty? and @lines_to_add.empty?
|
37
|
+
|
38
|
+
# Now add/remove lines - additions first
|
39
|
+
data.concat(@lines_to_add.reject { |l| data.include?(l) })
|
40
|
+
data.reject! { |l| @lines_to_remove.include?(l) }
|
41
|
+
|
42
|
+
# And write out the new file
|
43
|
+
File.open(@filename, "w") do |file|
|
44
|
+
data.each do |l|
|
45
|
+
file.puts(l)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Reset the list of lines to add/remove
|
50
|
+
@lines_to_add = []
|
51
|
+
@lines_to_remove = []
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Monolith
|
2
|
+
class BaseLocation
|
3
|
+
def initialize(cookbook, dep, destination)
|
4
|
+
@dep = dep
|
5
|
+
@location = dep.location
|
6
|
+
@cookbook = cookbook
|
7
|
+
@destination = destination
|
8
|
+
end
|
9
|
+
|
10
|
+
# Install the cookbook in the development environment. If possible, the
|
11
|
+
# installed cookbook should look exactly as it would when used for
|
12
|
+
# development (e.g. a git checkout with all git metadata, no compiled
|
13
|
+
# artefacts).
|
14
|
+
def install
|
15
|
+
nil
|
16
|
+
end
|
17
|
+
|
18
|
+
# Update the cookbook in the development environment to the latest
|
19
|
+
# version. E.g. if git is used, run git pull.
|
20
|
+
def update
|
21
|
+
nil
|
22
|
+
end
|
23
|
+
|
24
|
+
# Remove a previously installed cookbook. If a cookbook was never
|
25
|
+
# installed in the first place (either because install wasn't run, or
|
26
|
+
# because of the location type), then this should do nothing.
|
27
|
+
def clean
|
28
|
+
if File.exist?(@destination)
|
29
|
+
Monolith.formatter.clean(@cookbook, @destination)
|
30
|
+
FileUtils.rm_rf(@destination)
|
31
|
+
else
|
32
|
+
rel_dest = Monolith.formatter.rel_dir(@destination)
|
33
|
+
Monolith.formatter.skip(@cookbook, "#{rel_dest} doesn't exist")
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# Default location aka community/supermarket cookbook
|
2
|
+
module Monolith
|
3
|
+
class DefaultLocation < BaseLocation
|
4
|
+
def install
|
5
|
+
# For now we just copy any community cookbooks. It would be nice to be
|
6
|
+
# able to grab them from the source URL, but that isn't readily
|
7
|
+
# accessible, and then you have to guess how to check it out.
|
8
|
+
if File.directory?(@destination)
|
9
|
+
rel_dest = Monolith.formatter.rel_dir(@destination)
|
10
|
+
Monolith.formatter.skip(@cookbook, "#{rel_dest} already exists")
|
11
|
+
else
|
12
|
+
Monolith.formatter.install(@cookbook, @destination)
|
13
|
+
FileUtils.cp_r(@cookbook.path, @destination)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def update
|
18
|
+
# There isn't anything to do for updating a community cookbook except
|
19
|
+
# blowing it away and recreating it. For the moment I'm opting not to do
|
20
|
+
# that (it may be able ot be an option later)
|
21
|
+
Monolith.formatter.skip(@cookbook, "Not updating community cookbook")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'berkshelf/mixin/git'
|
2
|
+
require_relative 'base'
|
3
|
+
|
4
|
+
module Monolith
|
5
|
+
class GitLocation < BaseLocation
|
6
|
+
include Berkshelf::Mixin::Git
|
7
|
+
|
8
|
+
def install
|
9
|
+
unless File.directory?(@destination)
|
10
|
+
Monolith.formatter.install(@cookbook, @destination)
|
11
|
+
# Clone from the cache. We've already done an install by this point, so
|
12
|
+
# berkshelf already made sure the cache exists and is up to date.
|
13
|
+
git %|clone "#{cache_path}" "#{@destination}"|
|
14
|
+
|
15
|
+
# Make sure the origin is correct and doesn't point to the cached
|
16
|
+
# version.
|
17
|
+
cached_origin_url = origin_url(cache_path)
|
18
|
+
set_origin_url(@destination, cached_origin_url)
|
19
|
+
|
20
|
+
# Not sure if I want to do this - should probably be an option
|
21
|
+
#git %|reset --hard #{@revision}|
|
22
|
+
else
|
23
|
+
rel_dest = Monolith.formatter.rel_dir(@destination)
|
24
|
+
Monolith.formatter.skip(@cookbook, "#{rel_dest} already exists")
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def update
|
29
|
+
if File.directory?(@destination)
|
30
|
+
Monolith.formatter.update(@cookbook, @destination)
|
31
|
+
Dir.chdir(@destination) do
|
32
|
+
git %|pull|
|
33
|
+
end
|
34
|
+
else
|
35
|
+
rel_dest = Monolith.formatter.rel_dir(@destination)
|
36
|
+
Monolith.formatter.skip(@cookbook, "#{rel_dest} doesn't exist")
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
# Taken from Berkshelf::GitLocation
|
43
|
+
def cache_path
|
44
|
+
Pathname.new(Berkshelf.berkshelf_path)
|
45
|
+
.join('.cache', 'git', Digest::SHA1.hexdigest(@location.uri))
|
46
|
+
end
|
47
|
+
|
48
|
+
def origin_url(repo_dir)
|
49
|
+
Dir.chdir(repo_dir) do
|
50
|
+
git %|config --local --get remote.origin.url|
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def set_origin_url(repo_dir, url)
|
55
|
+
Dir.chdir(repo_dir) do
|
56
|
+
git %|remote set-url origin "#{url}"|
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# If a Berksfile mentions a cookbook with a path location, then we can
|
2
|
+
# assume it's already available locally in a form suitable for
|
3
|
+
# development. An example of this is if you have a (mostly) monolithic
|
4
|
+
# chef repository and want to refer to cookbooks in this repository in
|
5
|
+
# your Berksfile.
|
6
|
+
module Monolith
|
7
|
+
class PathLocation < BaseLocation
|
8
|
+
def install
|
9
|
+
Monolith.formatter.debug("Skipping cookbook #{@cookbook.cookbook_name}" \
|
10
|
+
"with path location")
|
11
|
+
end
|
12
|
+
|
13
|
+
def update
|
14
|
+
Monolith.formatter.debug("Skipping cookbook #{@cookbook.cookbook_name}" \
|
15
|
+
"with path location")
|
16
|
+
end
|
17
|
+
|
18
|
+
def clean
|
19
|
+
Monolith.formatter.debug("Skipping cookbook #{@cookbook.cookbook_name}" \
|
20
|
+
"with path location")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/test/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
tmp
|
data/test/helpers.rb
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'pathname'
|
3
|
+
|
4
|
+
module Monolith
|
5
|
+
module TestHelpers
|
6
|
+
def tmp_path
|
7
|
+
Pathname.new(File.expand_path("../tmp", __FILE__))
|
8
|
+
end
|
9
|
+
|
10
|
+
def clean_tmp_path
|
11
|
+
FileUtils.rm_rf(tmp_path)
|
12
|
+
FileUtils.mkdir_p(tmp_path)
|
13
|
+
end
|
14
|
+
|
15
|
+
def make_git_repo(name)
|
16
|
+
# Makes an example git repo with a single file in and one commit
|
17
|
+
repo_path = tmp_path.join("git", name)
|
18
|
+
FileUtils.mkdir_p(repo_path)
|
19
|
+
Dir.chdir(repo_path) do
|
20
|
+
%x|git init|
|
21
|
+
File.open('metadata.rb', 'w') do |f|
|
22
|
+
f.puts "name '#{name}'"
|
23
|
+
end
|
24
|
+
%x|git add metadata.rb|
|
25
|
+
%x|git config --local user.name Me|
|
26
|
+
%x|git config --local user.email me@example.com|
|
27
|
+
%x|git commit -m "Test commit"|
|
28
|
+
%x|git remote add origin "git@git.example.com:#{name}"|
|
29
|
+
end
|
30
|
+
repo_path
|
31
|
+
end
|
32
|
+
|
33
|
+
def make_change_git(name)
|
34
|
+
repo_path = tmp_path.join("git", name)
|
35
|
+
Dir.chdir(repo_path) do
|
36
|
+
File.open('test.txt', 'w') do |f|
|
37
|
+
f.puts 'Testing'
|
38
|
+
end
|
39
|
+
%x|git add test.txt|
|
40
|
+
%x|git commit --author "Me <me@example.com>" -m "Update"|
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def make_berksfile(types)
|
45
|
+
File.open(tmp_path.join('Berksfile'), 'w') do |berksfile|
|
46
|
+
berksfile.puts "source 'https://supermarket.chef.io/'"
|
47
|
+
types.each do |type|
|
48
|
+
if type == :git
|
49
|
+
repo_path = make_git_repo('test_git')
|
50
|
+
berksfile.puts("cookbook 'test_git', :git => '#{repo_path}'")
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
if block_given?
|
56
|
+
Dir.chdir(tmp_path) do
|
57
|
+
yield
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require_relative 'helpers'
|
3
|
+
|
4
|
+
# Fix 'Celluloid::Error Thread pool is not running' error.
|
5
|
+
# See https://github.com/celluloid/celluloid/pull/162
|
6
|
+
require 'celluloid/test'
|
7
|
+
Celluloid.init
|
8
|
+
|
9
|
+
require 'monolith'
|
10
|
+
|
11
|
+
class TestCommandInstall < MiniTest::Test
|
12
|
+
include Monolith::TestHelpers
|
13
|
+
|
14
|
+
def setup
|
15
|
+
clean_tmp_path
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_clean_command
|
19
|
+
make_berksfile([:git]) do
|
20
|
+
# We need to install it first
|
21
|
+
Monolith::Command.start(['install', '-q'])
|
22
|
+
make_change_git('test_git')
|
23
|
+
# Verify the 'before' state
|
24
|
+
assert File.exist?("cookbooks/test_git")
|
25
|
+
# Perform the clean
|
26
|
+
Monolith::Command.start(['clean', '-q'])
|
27
|
+
refute File.exist?("cookbooks/test_git")
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require_relative 'helpers'
|
3
|
+
|
4
|
+
# Fix 'Celluloid::Error Thread pool is not running' error.
|
5
|
+
# See https://github.com/celluloid/celluloid/pull/162
|
6
|
+
require 'celluloid/test'
|
7
|
+
Celluloid.init
|
8
|
+
|
9
|
+
require 'monolith'
|
10
|
+
|
11
|
+
class TestCommandInstall < MiniTest::Test
|
12
|
+
include Monolith::TestHelpers
|
13
|
+
|
14
|
+
def setup
|
15
|
+
clean_tmp_path
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_install_command
|
19
|
+
make_berksfile([:git]) do
|
20
|
+
Monolith::Command.start(['install', '-q'])
|
21
|
+
assert File.exist?("cookbooks/test_git")
|
22
|
+
assert File.exist?("cookbooks/test_git/.git")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require_relative 'helpers'
|
3
|
+
|
4
|
+
# Fix 'Celluloid::Error Thread pool is not running' error.
|
5
|
+
# See https://github.com/celluloid/celluloid/pull/162
|
6
|
+
require 'celluloid/test'
|
7
|
+
Celluloid.init
|
8
|
+
|
9
|
+
require 'monolith'
|
10
|
+
|
11
|
+
class TestCommandInstall < MiniTest::Test
|
12
|
+
include Monolith::TestHelpers
|
13
|
+
|
14
|
+
def setup
|
15
|
+
clean_tmp_path
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_update_command
|
19
|
+
make_berksfile([:git]) do
|
20
|
+
# We need to install it first
|
21
|
+
Monolith::Command.start(['install', '-q'])
|
22
|
+
make_change_git('test_git')
|
23
|
+
# Verify the 'before' state
|
24
|
+
refute File.exist?("cookbooks/test_git/test.txt")
|
25
|
+
# Perform the update
|
26
|
+
Monolith::Command.start(['update', '-q'])
|
27
|
+
assert File.exist?("cookbooks/test_git")
|
28
|
+
assert File.exist?("cookbooks/test_git/.git")
|
29
|
+
assert File.exist?("cookbooks/test_git/test.txt")
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
require 'berkshelf'
|
5
|
+
require 'monolith/locations/git'
|
6
|
+
|
7
|
+
class TestGitLocation < MiniTest::Test
|
8
|
+
|
9
|
+
def setup
|
10
|
+
# Path variables
|
11
|
+
@test_cookbook = "test_cookbook"
|
12
|
+
@test_base = File.expand_path('../tmp', __FILE__)
|
13
|
+
@mock_cache = File.join(@test_base, 'cache', @test_cookbook)
|
14
|
+
@mock_destination = File.join(@test_base, 'cloned', @test_cookbook)
|
15
|
+
@mock_origin = 'user@example.com:some/repo'
|
16
|
+
# Set up a repo to clone from rather than using the real berkshelf cache
|
17
|
+
# dir.
|
18
|
+
FileUtils.rm_rf(@test_base)
|
19
|
+
FileUtils.mkdir_p(@mock_cache)
|
20
|
+
Dir.chdir(@mock_cache) do
|
21
|
+
%x|git init|
|
22
|
+
%x|git remote add origin #{@mock_origin}|
|
23
|
+
end
|
24
|
+
# Don't print informational messages while testing
|
25
|
+
Monolith.formatter.quiet = true
|
26
|
+
end
|
27
|
+
|
28
|
+
def teardown
|
29
|
+
FileUtils.rm_rf(@test_base)
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_install
|
33
|
+
# Actually do the install
|
34
|
+
@mock_cookbook = Minitest::Mock.new
|
35
|
+
@mock_cookbook.expect :cookbook_name, @test_cookbook
|
36
|
+
@mock_dep = Minitest::Mock.new
|
37
|
+
@mock_dep.expect :location, nil
|
38
|
+
location = Monolith::GitLocation.new(@mock_cookbook, @mock_dep,
|
39
|
+
@mock_destination)
|
40
|
+
location.stub(:cache_path, @mock_cache) do
|
41
|
+
location.install
|
42
|
+
end
|
43
|
+
|
44
|
+
assert File.directory?(@mock_destination)
|
45
|
+
assert File.directory?(File.join(@mock_destination, '.git'))
|
46
|
+
assert_equal @mock_origin, location.send(:origin_url, @mock_destination)
|
47
|
+
end
|
48
|
+
end
|
metadata
ADDED
@@ -0,0 +1,154 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: berks-monolith
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Mark Harrison
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-01-02 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: berkshelf
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '3.0'
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 3.0.0
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - "~>"
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '3.0'
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 3.0.0
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: bundler
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '1.5'
|
40
|
+
type: :development
|
41
|
+
prerelease: false
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - "~>"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '1.5'
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: rake
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - "~>"
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '10.0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - "~>"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '10.0'
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: minitest
|
63
|
+
requirement: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - "~>"
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '5.0'
|
68
|
+
type: :development
|
69
|
+
prerelease: false
|
70
|
+
version_requirements: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - "~>"
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '5.0'
|
75
|
+
- !ruby/object:Gem::Dependency
|
76
|
+
name: pry
|
77
|
+
requirement: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - "~>"
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '0.10'
|
82
|
+
type: :development
|
83
|
+
prerelease: false
|
84
|
+
version_requirements: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - "~>"
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '0.10'
|
89
|
+
description: Tools for working with cookbooks as if they were inside a monolithic
|
90
|
+
repository
|
91
|
+
email:
|
92
|
+
- mark@mivok.net
|
93
|
+
executables:
|
94
|
+
- berks-monolith
|
95
|
+
extensions: []
|
96
|
+
extra_rdoc_files: []
|
97
|
+
files:
|
98
|
+
- ".gitignore"
|
99
|
+
- ".travis.yml"
|
100
|
+
- Gemfile
|
101
|
+
- LICENSE.txt
|
102
|
+
- README.md
|
103
|
+
- Rakefile
|
104
|
+
- berks-monolith.gemspec
|
105
|
+
- bin/berks-monolith
|
106
|
+
- lib/monolith.rb
|
107
|
+
- lib/monolith/berksfile.rb
|
108
|
+
- lib/monolith/commands.rb
|
109
|
+
- lib/monolith/formatter.rb
|
110
|
+
- lib/monolith/gitexclude.rb
|
111
|
+
- lib/monolith/locations/base.rb
|
112
|
+
- lib/monolith/locations/default.rb
|
113
|
+
- lib/monolith/locations/git.rb
|
114
|
+
- lib/monolith/locations/github.rb
|
115
|
+
- lib/monolith/locations/path.rb
|
116
|
+
- lib/monolith/version.rb
|
117
|
+
- test/.gitignore
|
118
|
+
- test/helpers.rb
|
119
|
+
- test/test_command_clean.rb
|
120
|
+
- test/test_command_install.rb
|
121
|
+
- test/test_command_update.rb
|
122
|
+
- test/test_gitlocation.rb
|
123
|
+
homepage: http://github.com/mivok/berks-monolith
|
124
|
+
licenses:
|
125
|
+
- MIT
|
126
|
+
metadata: {}
|
127
|
+
post_install_message:
|
128
|
+
rdoc_options: []
|
129
|
+
require_paths:
|
130
|
+
- lib
|
131
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
132
|
+
requirements:
|
133
|
+
- - ">="
|
134
|
+
- !ruby/object:Gem::Version
|
135
|
+
version: 1.9.2
|
136
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
137
|
+
requirements:
|
138
|
+
- - ">="
|
139
|
+
- !ruby/object:Gem::Version
|
140
|
+
version: '0'
|
141
|
+
requirements: []
|
142
|
+
rubyforge_project:
|
143
|
+
rubygems_version: 2.4.1
|
144
|
+
signing_key:
|
145
|
+
specification_version: 4
|
146
|
+
summary: Berkshelf monolithic repository tools
|
147
|
+
test_files:
|
148
|
+
- test/.gitignore
|
149
|
+
- test/helpers.rb
|
150
|
+
- test/test_command_clean.rb
|
151
|
+
- test/test_command_install.rb
|
152
|
+
- test/test_command_update.rb
|
153
|
+
- test/test_gitlocation.rb
|
154
|
+
has_rdoc:
|