berkshelf-hg 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ NGE5NWU0NzFjODg5NjA0NjZmZjBkNzY2Nzc0OTY5ZWJmZjQxNDQ0Yw==
5
+ data.tar.gz: !binary |-
6
+ MWZjNGRkMTAyZTgxNTZiMmYyNmQwMGYyN2E4YTYyMmMyMzZiNzk4MQ==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ NWI2MjViMmY2YjM2ZDNiYjE2MWU3NGFjODZiNTgxMTVkYmU2ZGUzZDc3Zjk2
10
+ NTY1OTNiNGYzNjQwODVmN2Y2ZWM0ZTNiMTU0OWNiNTQ5YWUzYTQ2N2E5YzYz
11
+ ZmY2MWFmMzFkNTZkMTYxMjI1NGZmNDNkZWZiMWVmMGNjYzhjMjc=
12
+ data.tar.gz: !binary |-
13
+ ZDZiNmMyOWFhNmQ5NzgyZTBlN2IyOTMwYzdhYjUyYmQ4Mjk3OTI1MWI5Nzgx
14
+ ODExM2RmZThmOTI0ODUxODc2MjdlYWZmN2JmN2RiNWVkYWFjZGRlOThmMzQ0
15
+ N2YzMzYwZmE0ZGIwODRlYTdhZDNjZjJjMWIyYjcwY2NlYWNhNjY=
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .rspec
6
+ .yardoc
7
+ Gemfile.lock
8
+ InstalledFiles
9
+ _yardoc
10
+ coverage
11
+ doc/
12
+ lib/bundler/man
13
+ pkg
14
+ rdoc
15
+ spec/reports
16
+ test/tmp
17
+ test/version_tmp
18
+ tmp
@@ -0,0 +1,8 @@
1
+ rvm:
2
+ - 1.9.3
3
+ - 2.0.0
4
+ - 2.1
5
+
6
+ bundler_args: --jobs 7
7
+
8
+ script: bundle exec rake travis:ci
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,201 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ APPENDIX: How to apply the Apache License to your work.
179
+
180
+ To apply the Apache License to your work, attach the following
181
+ boilerplate notice, with the fields enclosed by brackets "[]"
182
+ replaced with your own identifying information. (Don't include
183
+ the brackets!) The text should be enclosed in the appropriate
184
+ comment syntax for the file format. We also recommend that a
185
+ file or class name and description of purpose be included on the
186
+ same "printed page" as the copyright notice for easier
187
+ identification within third-party archives.
188
+
189
+ Copyright [yyyy] [name of copyright owner]
190
+
191
+ Licensed under the Apache License, Version 2.0 (the "License");
192
+ you may not use this file except in compliance with the License.
193
+ You may obtain a copy of the License at
194
+
195
+ http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+ Unless required by applicable law or agreed to in writing, software
198
+ distributed under the License is distributed on an "AS IS" BASIS,
199
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+ See the License for the specific language governing permissions and
201
+ limitations under the License.
@@ -0,0 +1,63 @@
1
+ Berkshelf Hg
2
+ ============
3
+ [![Gem Version](https://badge.fury.io/rb/berkshelf-hg.png)](http://badge.fury.io/rb/berkshelf-hg)
4
+ [![Build Status](https://travis-ci.org/berkshelf/berkshelf-hg.png?branch=master)](https://travis-ci.org/berkshelf/berkshelf-hg)
5
+
6
+ Berkshelf Hg (or Berkshelf Mercurial) is a Berkshelf extension that adds support for downloading cookbooks from Mercurial locations.
7
+
8
+ Installation
9
+ ------------
10
+ Add this line to your application's Gemfile:
11
+
12
+ gem 'berkshelf-hg'
13
+
14
+ And then execute:
15
+
16
+ $ bundle
17
+
18
+ Or install it yourself as:
19
+
20
+ $ gem install berkshelf-hg
21
+
22
+ Usage
23
+ -----
24
+ Activate the extension in your `Berksfile`:
25
+
26
+ ```ruby
27
+ source 'https://api.berkshelf.com'
28
+ extension 'hg'
29
+ ```
30
+
31
+ Use the exposed `:hg` key to define your sources:
32
+
33
+ ```ruby
34
+ cookbook 'bacon', hg: 'https://bitbucket.org/meats/bacon'
35
+ ```
36
+
37
+ You may also specify a `branch` or `tag`:
38
+
39
+ ```ruby
40
+ cookbook 'bacon', hg: 'https://bitbucket.org/meats/bacon', branch: 'crispy'
41
+ ```
42
+
43
+ License & Authors
44
+ -----------------
45
+ - Author: Seth Vargo (sethvargo@gmail.com)
46
+ - Author: Manuel Ryan (ryan@shamu.ch)
47
+
48
+ ```text
49
+ Copyright 2014 Seth Vargo
50
+ Copyright 2013-2014 Manual Ryan
51
+
52
+ Licensed under the Apache License, Version 2.0 (the "License");
53
+ you may not use this file except in compliance with the License.
54
+ You may obtain a copy of the License at
55
+
56
+ http://www.apache.org/licenses/LICENSE-2.0
57
+
58
+ Unless required by applicable law or agreed to in writing, software
59
+ distributed under the License is distributed on an "AS IS" BASIS,
60
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
61
+ See the License for the specific language governing permissions and
62
+ limitations under the License.
63
+ ```
@@ -0,0 +1,12 @@
1
+ require 'bundler/gem_tasks'
2
+
3
+ require 'rspec/core/rake_task'
4
+ RSpec::Core::RakeTask.new(:unit)
5
+
6
+ require 'cucumber/rake/task'
7
+ Cucumber::Rake::Task.new(:integration)
8
+
9
+ namespace :travis do
10
+ desc 'Run the tests on Travis'
11
+ task :ci => [:unit, :integration]
12
+ end
@@ -0,0 +1,37 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'berkshelf/hg/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'berkshelf-hg'
8
+ spec.version = Berkshelf::Hg::VERSION
9
+ spec.authors = [
10
+ 'Seth Vargo',
11
+ 'Manuel Ryan',
12
+ ]
13
+ spec.email = [
14
+ 'sethvargo@gmail.com',
15
+ 'ryan@shamu.ch',
16
+ ]
17
+ spec.summary = 'Mercurial (hg) support for Berkshelf'
18
+ spec.description = 'A Berkshelf plugin that adds support for downloading ' \
19
+ 'Chef cookbooks from Mercurial (hg) locations.'
20
+ spec.homepage = 'https://github.com/berkshelf/berkshelf-hg'
21
+ spec.license = 'Apache 2.0'
22
+
23
+ spec.files = `git ls-files`.split($/)
24
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
25
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
26
+ spec.require_paths = ['lib']
27
+
28
+ # Runtime dependencies
29
+ spec.add_dependency 'berkshelf', '~> 3.1'
30
+
31
+ # Development dependencies
32
+ spec.add_development_dependency 'aruba', '~> 0.5'
33
+ spec.add_development_dependency 'rspec', '~> 2.14'
34
+
35
+ spec.add_development_dependency 'bundler'
36
+ spec.add_development_dependency 'rake'
37
+ end
@@ -0,0 +1,39 @@
1
+ Feature: Installing from a mercurial location
2
+ Scenario: In the default scenario
3
+ * a remote mercurial cookbook named "fake"
4
+ * I write to "Berksfile" with:
5
+ """
6
+ source 'https://api.berkshelf.com'
7
+ extension 'hg'
8
+
9
+ cookbook 'fake', hg: "file://localhost#{Dir.pwd}/hg-cookbooks/fake"
10
+ """
11
+ * I successfully run `berks install`
12
+ * the output should contain "Using fake (1.0.0)"
13
+
14
+ Scenario: When a branch is given
15
+ * a remote mercurial cookbook named "fake" with a branch named "development"
16
+ * I write to "Berksfile" with:
17
+ """
18
+ source 'https://api.berkshelf.com'
19
+ extension 'hg'
20
+
21
+ cookbook 'fake', hg: "file://localhost#{Dir.pwd}/hg-cookbooks/fake", branch: 'development'
22
+ """
23
+ * I successfully run `berks install`
24
+ * the output should contain "Using fake (2.3.4)"
25
+
26
+ Scenario: When a relative path is given
27
+ * a remote mercurial repo with two cookbooks named "fakeA" and "fakeB"
28
+ * I write to "Berksfile" with:
29
+ """
30
+ source 'https://api.berkshelf.com'
31
+ extension 'hg'
32
+
33
+ cookbook 'fakeA', hg: "file://localhost#{Dir.pwd}/hg-cookbooks", rel: "site-cookbooks/fakeA"
34
+ cookbook 'fakeB', hg: "file://localhost#{Dir.pwd}/hg-cookbooks", rel: "site-cookbooks/fakeB"
35
+ """
36
+
37
+ * I successfully run `berks install`
38
+ * the output should contain "Using fakeA (1.0.1)"
39
+ * the output should contain "Using fakeB (1.0.1)"
@@ -0,0 +1,58 @@
1
+ Given /^a remote mercurial cookbook named "(\w+)"$/ do |name|
2
+ path = File.join(tmp_path, 'hg-cookbooks', name)
3
+ FileUtils.mkdir_p(path)
4
+
5
+ Dir.chdir(path) do
6
+ hg('init')
7
+ write_metadata(name, '1.0.0')
8
+ hg('add')
9
+ hg_commit('Initial commit')
10
+ end
11
+ end
12
+
13
+
14
+
15
+ Given /^a remote mercurial cookbook named "(\w+)" with a branch named "(\w+)"$/ do |name, branch|
16
+ path = File.join(tmp_path, 'hg-cookbooks', name)
17
+ steps %Q|Given a remote mercurial cookbook named "#{name}"|
18
+
19
+ Dir.chdir(path) do
20
+ hg("branch #{branch}")
21
+ write_metadata(name, '2.3.4')
22
+ hg('add')
23
+ hg_commit('More changes')
24
+ end
25
+ end
26
+
27
+
28
+ Given(/^a remote mercurial repo with two cookbooks named "(.*?)" and "(.*?)"$/) do |name1, name2|
29
+ project_path = File.join(tmp_path, 'hg-cookbooks')
30
+ [name1,name2].each do |name|
31
+ cookbook_path = File.join(project_path,'site-cookbooks',name)
32
+ FileUtils.mkdir_p(cookbook_path)
33
+ write_metadata(name, '1.0.1',cookbook_path)
34
+ end
35
+ Dir.chdir(project_path) do
36
+ hg("init")
37
+ hg('add')
38
+ hg_commit('adding_cookbooks')
39
+ end
40
+
41
+ end
42
+
43
+ def write_metadata(name,version,path="./")
44
+ File.open(File.join(path,"metadata.rb"), "w") do |f|
45
+ f.write <<-EOH
46
+ name '#{name}'
47
+ version '#{version}'
48
+ EOH
49
+ end
50
+ end
51
+
52
+ def hg(command)
53
+ %x|hg #{command}|
54
+ end
55
+
56
+ def hg_commit(message)
57
+ hg %|--config ui.username=Berkshelf commit --message "#{message}"|
58
+ end
@@ -0,0 +1,16 @@
1
+ require 'aruba/cucumber'
2
+ require 'aruba/in_process'
3
+ require 'berkshelf'
4
+
5
+ Before do
6
+ Aruba::InProcess.main_class = Berkshelf::Cli::Runner
7
+ Aruba.process = Aruba::InProcess
8
+
9
+ @aruba_timeout_seconds = 30
10
+
11
+ ENV['BERKSHELF_PATH'] = tmp_path
12
+ end
13
+
14
+ def tmp_path
15
+ File.expand_path('tmp/aruba')
16
+ end
@@ -0,0 +1,5 @@
1
+ require 'berkshelf/hg/version'
2
+
3
+ module Berkshelf
4
+ autoload :HgLocation, 'berkshelf/locations/hg'
5
+ end
@@ -0,0 +1,5 @@
1
+ module Berkshelf
2
+ module Hg
3
+ VERSION = '0.1.0'
4
+ end
5
+ end
@@ -0,0 +1,197 @@
1
+ require 'buff/shell_out'
2
+ require 'digest/sha1'
3
+ require 'pathname'
4
+ require 'berkshelf'
5
+
6
+ module Berkshelf
7
+ class HgLocation < BaseLocation
8
+ class HgError < BerkshelfError; status_code(500); end
9
+
10
+ class HgNotInstalled < HgError
11
+ def initialize
12
+ super 'You need to install Mercurial before you can download ' \
13
+ 'cookbooks from hg repositories. For more information, please ' \
14
+ 'see the Mercurial docs: http://mercurial.selenic.com/wiki/Download.'
15
+ end
16
+ end
17
+
18
+ class HgCommandError < HgError
19
+ def initialize(command, response, path = nil)
20
+ super "Hg error: command `hg #{command}` failed. If this error " \
21
+ "persists, try removing the cache directory at `#{path}'." \
22
+ "\nstdout:#{response.stdout}\nstderr:#{response.stderr}"
23
+ end
24
+ end
25
+
26
+ attr_reader :uri
27
+ attr_reader :branch
28
+ attr_reader :tag
29
+ attr_reader :ref
30
+
31
+ attr_reader :rel
32
+ attr_reader :revision
33
+
34
+ def initialize(dependency, options = {})
35
+ super
36
+
37
+ @uri = options[:hg]
38
+ @branch = options[:branch]
39
+ @tag = options[:tag]
40
+ @ref = options[:ref] || options[:branch] || options[:tag] || 'default'
41
+ @revision = options[:revision]
42
+ @rel = options[:rel]
43
+ end
44
+
45
+ def cached_cookbook
46
+ if installed?
47
+ @cached_cookbook ||= CachedCookbook.from_path(install_path)
48
+ else
49
+ nil
50
+ end
51
+ end
52
+
53
+ # Download the cookbook from the remote hg repository
54
+ #
55
+ # @return void
56
+ def install
57
+ if cached?
58
+ # Update and checkout the correct ref
59
+ Dir.chdir(cache_path) do
60
+ hg %|pull|
61
+ end
62
+ else
63
+ # Ensure the cache directory is present before doing anything
64
+ FileUtils.mkdir_p(cache_path)
65
+
66
+ Dir.chdir(cache_path) do
67
+ hg %|clone #{uri} .|
68
+ end
69
+ end
70
+
71
+ Dir.chdir(cache_path) do
72
+ hg %|update --clean --rev #{revision || ref}|
73
+ @revision ||= hg %|id -i|
74
+ end
75
+
76
+ # Gab the path where we should copy from (since it might be relative to
77
+ # the root).
78
+ copy_path = rel ? cache_path.join(rel) : cache_path
79
+
80
+ begin
81
+ # Validate the thing we are copying is a Chef cookbook
82
+ validate_cached!(copy_path)
83
+
84
+ # Remove the current cookbook at this location (this is required or else
85
+ # FileUtils will copy into a subdirectory in the next step)
86
+ FileUtils.rm_rf(install_path)
87
+
88
+ # Create the containing parent directory
89
+ FileUtils.mkdir_p(install_path.parent)
90
+
91
+ # Copy whatever is in the current cache over to the store
92
+ FileUtils.cp_r(copy_path, install_path)
93
+
94
+ ensure
95
+
96
+ # Remove the .hg directory to save storage space
97
+ # TODO this can have huge performance implications,
98
+ # make it a config option?
99
+ if (hg_path = install_path.join('.hg')).exist?
100
+ FileUtils.rm_r(hg_path)
101
+ end
102
+
103
+ FileUtils.rm_rf (copy_path)
104
+ end
105
+ end
106
+
107
+ def scm_location?
108
+ true
109
+ end
110
+
111
+ def ==(other)
112
+ other.is_a?(HgLocation) &&
113
+ other.uri == uri &&
114
+ other.branch == branch &&
115
+ other.tag == tag &&
116
+ other.ref == ref &&
117
+ other.rel == rel
118
+ end
119
+
120
+ def to_s
121
+ info = tag || branch || ref[0...7]
122
+
123
+ if rel
124
+ "#{uri} (at #{info}/#{rel})"
125
+ else
126
+ "#{uri} (at #{info})"
127
+ end
128
+ end
129
+
130
+ def to_lock
131
+ out = " hg: #{uri}\n"
132
+ out << " revision: #{revision}\n"
133
+ out << " branch: #{branch}\n" if branch
134
+ out << " tag: #{tag}\n" if tag
135
+ out << " rel: #{rel}\n" if rel
136
+ out
137
+ end
138
+
139
+ # Determine if this revision is installed.
140
+ #
141
+ # @return [Boolean]
142
+ def installed?
143
+ revision && install_path.exist?
144
+ end
145
+
146
+ private
147
+
148
+ # Perform a mercurial command.
149
+ #
150
+ # @param [String] command
151
+ # the command to run
152
+ # @param [Boolean] error
153
+ # whether to raise error if the command fails
154
+ #
155
+ # @raise [String]
156
+ # the +$stdout+ from the command
157
+ def hg(command, error = true)
158
+ unless Berkshelf.which('hg') || Berkshelf.which('hg.exe')
159
+ raise HgNotInstalled.new
160
+ end
161
+
162
+ Berkshelf.log.debug("Running:hg #{command}")
163
+ response = Buff::ShellOut.shell_out(%|hg #{command}|)
164
+ Berkshelf.log.debug("response:hg #{response.stdout}")
165
+
166
+ if error && !response.success?
167
+ raise HgCommandError.new(command, response, cache_path)
168
+ end
169
+
170
+ response.stdout.strip
171
+ end
172
+
173
+ # Determine if this hg repo has already been downloaded.
174
+ #
175
+ # @return [Boolean]
176
+ def cached?
177
+ cache_path.exist?
178
+ end
179
+
180
+ # The path where this cookbook would live in the store, if it were
181
+ # installed.
182
+ #
183
+ # @return [Pathname, nil]
184
+ def install_path
185
+ Berkshelf.cookbook_store.storage_path
186
+ .join("#{dependency.name}-#{revision}")
187
+ end
188
+
189
+ # The path where this hg repository is cached.
190
+ #
191
+ # @return [Pathname]
192
+ def cache_path
193
+ Pathname.new(Berkshelf.berkshelf_path)
194
+ .join('.cache', 'hg', Digest::SHA1.hexdigest(uri))
195
+ end
196
+ end
197
+ end
@@ -0,0 +1,13 @@
1
+ require 'berkshelf/hg'
2
+
3
+ RSpec.configure do |config|
4
+ config.treat_symbols_as_metadata_keys_with_true_values = true
5
+ config.run_all_when_everything_filtered = true
6
+ config.filter_run :focus
7
+
8
+ # Run specs in random order to surface order dependencies. If you find an
9
+ # order dependency and want to debug it, you can fix the order by providing
10
+ # the seed, which is printed after each run.
11
+ # --seed 1234
12
+ config.order = 'random'
13
+ end
@@ -0,0 +1,204 @@
1
+ require 'spec_helper'
2
+
3
+ module Berkshelf
4
+ describe HgLocation do
5
+ let(:dependency) { double(name: 'bacon') }
6
+
7
+ subject do
8
+ described_class.new(dependency, hg: 'https://repo.com', branch: 'ham',
9
+ tag: 'v1.2.3', ref: 'abc123', revision: 'defjkl123456', rel: 'hi')
10
+ end
11
+
12
+ describe '.initialize' do
13
+ it 'sets the uri' do
14
+ instance = described_class.new(dependency, hg: 'https://repo.com')
15
+ expect(instance.uri).to eq('https://repo.com')
16
+ end
17
+
18
+ it 'sets the branch' do
19
+ instance = described_class.new(dependency,
20
+ hg: 'https://repo.com', branch: 'magic_new_feature')
21
+ expect(instance.branch).to eq('magic_new_feature')
22
+ end
23
+
24
+ it 'sets the tag' do
25
+ instance = described_class.new(dependency,
26
+ hg: 'https://repo.com', tag: 'v1.2.3')
27
+ expect(instance.tag).to eq('v1.2.3')
28
+ end
29
+
30
+ context 'ref' do
31
+ it 'uses the :ref option with priority' do
32
+ instance = described_class.new(dependency,
33
+ hg: 'https://repo.com', ref: 'abc123', branch: 'magic_new_feature')
34
+ expect(instance.ref).to eq('abc123')
35
+ end
36
+
37
+ it 'uses the :branch option with priority' do
38
+ instance = described_class.new(dependency,
39
+ hg: 'https://repo.com', branch: 'magic_new_feature', tag: 'v1.2.3')
40
+ expect(instance.ref).to eq('magic_new_feature')
41
+ end
42
+
43
+ it 'uses the :tag option' do
44
+ instance = described_class.new(dependency,
45
+ hg: 'https://repo.com', tag: 'v1.2.3')
46
+ expect(instance.ref).to eq('v1.2.3')
47
+ end
48
+
49
+ it 'uses "default" when none is given' do
50
+ instance = described_class.new(dependency, hg: 'https://repo.com')
51
+ expect(instance.ref).to eq('default')
52
+ end
53
+ end
54
+
55
+ it 'sets the revision' do
56
+ instance = described_class.new(dependency,
57
+ hg: 'https://repo.com', revision: 'abcde12345')
58
+ expect(instance.revision).to eq('abcde12345')
59
+ end
60
+
61
+ it 'sets the rel' do
62
+ instance = described_class.new(dependency,
63
+ hg: 'https://repo.com', rel: 'internal/path')
64
+ expect(instance.rel).to eq('internal/path')
65
+ end
66
+ end
67
+
68
+ describe '#install' do
69
+ before do
70
+ CachedCookbook.stub(:from_store_path)
71
+ FileUtils.stub(:cp_r)
72
+ subject.stub(:validate_cached!)
73
+ subject.stub(:validate_cookbook!)
74
+ subject.stub(:hg)
75
+ end
76
+
77
+ context 'when the repository is cached' do
78
+ it 'pulls a new version' do
79
+ Dir.stub(:chdir) { |args, &b| b.call } # Force eval the chdir block
80
+ subject.stub(:cached?).and_return(true)
81
+ expect(subject).to receive(:hg).with('pull')
82
+ subject.install
83
+ end
84
+ end
85
+
86
+ context 'when the revision is not cached' do
87
+ it 'clones the repository' do
88
+ subject.stub(:cached?).and_return(false)
89
+ expect(subject).to receive(:hg).with('update --clean --rev defjkl123456')
90
+ subject.install
91
+ end
92
+ end
93
+ end
94
+
95
+ describe '#scm_location?' do
96
+ it 'returns true' do
97
+ instance = described_class.new(dependency, hg: 'https://repo.com')
98
+ expect(instance).to be_scm_location
99
+ end
100
+ end
101
+
102
+ describe '#==' do
103
+ let(:other) { subject.dup }
104
+
105
+ it 'returns true when everything matches' do
106
+ expect(subject).to eq(other)
107
+ end
108
+
109
+ it 'returns false when the other location is not an HgLocation' do
110
+ other.stub(:is_a?).and_return(false)
111
+ expect(subject).to_not eq(other)
112
+ end
113
+
114
+ it 'returns false when the uri is different' do
115
+ other.stub(:uri).and_return('different')
116
+ expect(subject).to_not eq(other)
117
+ end
118
+
119
+ it 'returns false when the branch is different' do
120
+ other.stub(:branch).and_return('different')
121
+ expect(subject).to_not eq(other)
122
+ end
123
+
124
+ it 'returns false when the tag is different' do
125
+ other.stub(:tag).and_return('different')
126
+ expect(subject).to_not eq(other)
127
+ end
128
+
129
+ it 'returns false when the ref is different' do
130
+ other.stub(:ref).and_return('different')
131
+ expect(subject).to_not eq(other)
132
+ end
133
+
134
+ it 'returns false when the rel is different' do
135
+ other.stub(:rel).and_return('different')
136
+ expect(subject).to_not eq(other)
137
+ end
138
+ end
139
+
140
+ describe '#to_s' do
141
+ it 'prefers the tag' do
142
+ expect(subject.to_s).to eq('https://repo.com (at v1.2.3/hi)')
143
+ end
144
+
145
+ it 'prefers the branch' do
146
+ subject.stub(:tag).and_return(nil)
147
+ expect(subject.to_s).to eq('https://repo.com (at ham/hi)')
148
+ end
149
+
150
+ it 'falls back to the ref' do
151
+ subject.stub(:tag).and_return(nil)
152
+ subject.stub(:branch).and_return(nil)
153
+ expect(subject.to_s).to eq('https://repo.com (at abc123/hi)')
154
+ end
155
+
156
+ it 'does not use the rel if missing' do
157
+ subject.stub(:rel).and_return(nil)
158
+ expect(subject.to_s).to eq('https://repo.com (at v1.2.3)')
159
+ end
160
+ end
161
+
162
+ describe '#to_lock' do
163
+ it 'includes all the information' do
164
+ expect(subject.to_lock).to eq <<-EOH.gsub(/^ {8}/, '')
165
+ hg: https://repo.com
166
+ revision: defjkl123456
167
+ branch: ham
168
+ tag: v1.2.3
169
+ rel: hi
170
+ EOH
171
+ end
172
+
173
+ it 'does not include the branch if missing' do
174
+ subject.stub(:branch).and_return(nil)
175
+ expect(subject.to_lock).to_not include('branch')
176
+ end
177
+
178
+ it 'does not include the tag if missing' do
179
+ subject.stub(:tag).and_return(nil)
180
+ expect(subject.to_lock).to_not include('tag')
181
+ end
182
+
183
+ it 'does not include the rel if missing' do
184
+ subject.stub(:rel).and_return(nil)
185
+ expect(subject.to_lock).to_not include('rel')
186
+ end
187
+ end
188
+
189
+ describe '#hg' do
190
+ before { described_class.send(:public, :hg) }
191
+
192
+ it 'raises an error if Mercurial is not installed' do
193
+ Berkshelf.stub(:which).and_return(false)
194
+ expect { subject.hg('foo') }.to raise_error(HgLocation::HgNotInstalled)
195
+ end
196
+
197
+ it 'raises an error if the command fails' do
198
+ subject.stub(:`)
199
+ $?.stub(:success?).and_return(false)
200
+ expect { subject.hg('foo') }.to raise_error(HgLocation::HgCommandError)
201
+ end
202
+ end
203
+ end
204
+ end
metadata ADDED
@@ -0,0 +1,137 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: berkshelf-hg
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Seth Vargo
8
+ - Manuel Ryan
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2014-07-07 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: berkshelf
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ~>
19
+ - !ruby/object:Gem::Version
20
+ version: '3.1'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ~>
26
+ - !ruby/object:Gem::Version
27
+ version: '3.1'
28
+ - !ruby/object:Gem::Dependency
29
+ name: aruba
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ~>
33
+ - !ruby/object:Gem::Version
34
+ version: '0.5'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ~>
40
+ - !ruby/object:Gem::Version
41
+ version: '0.5'
42
+ - !ruby/object:Gem::Dependency
43
+ name: rspec
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ~>
47
+ - !ruby/object:Gem::Version
48
+ version: '2.14'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ~>
54
+ - !ruby/object:Gem::Version
55
+ version: '2.14'
56
+ - !ruby/object:Gem::Dependency
57
+ name: bundler
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ! '>='
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ - !ruby/object:Gem::Dependency
71
+ name: rake
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ! '>='
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ description: A Berkshelf plugin that adds support for downloading Chef cookbooks from
85
+ Mercurial (hg) locations.
86
+ email:
87
+ - sethvargo@gmail.com
88
+ - ryan@shamu.ch
89
+ executables: []
90
+ extensions: []
91
+ extra_rdoc_files: []
92
+ files:
93
+ - .gitignore
94
+ - .travis.yml
95
+ - Gemfile
96
+ - LICENSE
97
+ - README.md
98
+ - Rakefile
99
+ - berkshelf-hg.gemspec
100
+ - features/hg.feature
101
+ - features/step_definitions/remote_steps.rb
102
+ - features/support/env.rb
103
+ - lib/berkshelf/hg.rb
104
+ - lib/berkshelf/hg/version.rb
105
+ - lib/berkshelf/locations/hg.rb
106
+ - spec/spec_helper.rb
107
+ - spec/unit/locations/hg_spec.rb
108
+ homepage: https://github.com/berkshelf/berkshelf-hg
109
+ licenses:
110
+ - Apache 2.0
111
+ metadata: {}
112
+ post_install_message:
113
+ rdoc_options: []
114
+ require_paths:
115
+ - lib
116
+ required_ruby_version: !ruby/object:Gem::Requirement
117
+ requirements:
118
+ - - ! '>='
119
+ - !ruby/object:Gem::Version
120
+ version: '0'
121
+ required_rubygems_version: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - ! '>='
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ requirements: []
127
+ rubyforge_project:
128
+ rubygems_version: 2.2.2
129
+ signing_key:
130
+ specification_version: 4
131
+ summary: Mercurial (hg) support for Berkshelf
132
+ test_files:
133
+ - features/hg.feature
134
+ - features/step_definitions/remote_steps.rb
135
+ - features/support/env.rb
136
+ - spec/spec_helper.rb
137
+ - spec/unit/locations/hg_spec.rb