berkshelf 3.0.1 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.travis.yml +1 -1
- data/CHANGELOG.md +12 -0
- data/Gemfile +1 -1
- data/README.md +13 -3
- data/berkshelf.gemspec +1 -1
- data/features/commands/info.feature +99 -0
- data/features/commands/show.feature +2 -18
- data/features/commands/viz.feature +65 -0
- data/features/json_formatter.feature +1 -5
- data/features/step_definitions/json_steps.rb +2 -1
- data/lib/berkshelf/berksfile.rb +15 -0
- data/lib/berkshelf/cached_cookbook.rb +0 -1
- data/lib/berkshelf/cli.rb +35 -2
- data/lib/berkshelf/commands/shelf.rb +2 -2
- data/lib/berkshelf/errors.rb +28 -1
- data/lib/berkshelf/formatters/base.rb +1 -0
- data/lib/berkshelf/formatters/human.rb +10 -2
- data/lib/berkshelf/formatters/json.rb +11 -2
- data/lib/berkshelf/lockfile.rb +7 -0
- data/lib/berkshelf/resolver.rb +2 -2
- data/lib/berkshelf/version.rb +1 -1
- data/lib/berkshelf/visualizer.rb +103 -0
- data/lib/berkshelf.rb +2 -1
- data/spec/unit/berkshelf/visualizer_spec.rb +30 -0
- metadata +11 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fe531a8a2654076d566b236313b3eeef9c1d6d8b
|
4
|
+
data.tar.gz: c5560108ebd912946fdf1f7a55649f85705f71f3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bb3799a95ad74f30e1996c3a69c045038e9e0d64d695eff4d0f00c7ac074a1b5bdee0515c2072337a1dfbf21d7c4c884c5adcdc414d4b30c7417cb04276a873a
|
7
|
+
data.tar.gz: b746da2921496bee4d25b1ef2cebd088ab755e5860370e2df8c8df3ed5a3606833b261a457ebe595ffd7b49252665f284b558cef109f9276050dbb1aaf2519bc
|
data/.travis.yml
CHANGED
@@ -18,7 +18,7 @@ branches:
|
|
18
18
|
env: USE_SYSTEM_GECODE=1
|
19
19
|
bundler_args: --without guard --jobs 7
|
20
20
|
before_install:
|
21
|
-
- sudo apt-get install -qq libarchive12 libarchive-dev libgecode-dev
|
21
|
+
- sudo apt-get install -qq libarchive12 libarchive-dev libgecode-dev graphviz
|
22
22
|
before_script:
|
23
23
|
- echo "StrictHostKeyChecking no" > ~/.ssh/config
|
24
24
|
- git config --global user.email "ci@berkshelf.com"
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,15 @@
|
|
1
|
+
# 3.1.0
|
2
|
+
|
3
|
+
* Enhancements
|
4
|
+
* Added `berks viz` command which will output a visualized dependency graph
|
5
|
+
* Added `berks info` command which outputs what `berks show` used to output
|
6
|
+
* Changed `berks show` command to output the filepath where the cookbook is found
|
7
|
+
* Improve error output when a solution couldn't be found
|
8
|
+
|
9
|
+
* Bug Fixes
|
10
|
+
* Various documentation updates
|
11
|
+
* Update description of version command
|
12
|
+
|
1
13
|
# 3.0.1
|
2
14
|
|
3
15
|
* Bug Fixes
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -9,9 +9,19 @@ Manage a Cookbook or an Application's Cookbook dependencies
|
|
9
9
|
|
10
10
|
## Installation
|
11
11
|
|
12
|
-
|
12
|
+
Berkshelf is now included as part of the [Chef-DK](http://getchef.com/downloads/chef-dk). This is fastest, easiest, and the recommended installation method for getting up and running with Berkshelf.
|
13
13
|
|
14
|
-
|
14
|
+
Add the Chef-DK binaries directory to your path once you've installed the Chef-DK.
|
15
|
+
|
16
|
+
$ export PATH=/opt/chefdk/embedded/bin:$PATH
|
17
|
+
$ which berks
|
18
|
+
/opt/chefdk/embedded/bin/berks
|
19
|
+
|
20
|
+
> note: You may need to uninstall the Berkshelf gem especially if you are using a Ruby version manager you may need to uninstall all Berkshelf gems from each Ruby installation.
|
21
|
+
|
22
|
+
### From Rubygems
|
23
|
+
|
24
|
+
If you are a developer or you prefer to install from Rubygems, we've got you covered.
|
15
25
|
|
16
26
|
Add Berkshelf to your repository's `Gemfile`:
|
17
27
|
|
@@ -29,7 +39,7 @@ See [berkshelf.com](http://berkshelf.com) for up-to-date usage instructions.
|
|
29
39
|
|
30
40
|
## Supported Platforms
|
31
41
|
|
32
|
-
Berkshelf is tested on Ruby 1.9.3, 2.0
|
42
|
+
Berkshelf is tested on Ruby 1.9.3, 2.0, and 2.1.
|
33
43
|
|
34
44
|
Ruby 1.9 mode is required on all interpreters.
|
35
45
|
|
data/berkshelf.gemspec
CHANGED
@@ -41,7 +41,7 @@ Gem::Specification.new do |s|
|
|
41
41
|
s.add_dependency 'ridley', '~> 3.0'
|
42
42
|
s.add_dependency 'solve', '~> 1.1'
|
43
43
|
s.add_dependency 'thor', '~> 0.18'
|
44
|
-
s.add_dependency 'octokit', '~>
|
44
|
+
s.add_dependency 'octokit', '~> 3.0'
|
45
45
|
s.add_dependency 'celluloid', '~> 0.16.0.pre'
|
46
46
|
s.add_dependency 'celluloid-io', '~> 0.16.0.pre'
|
47
47
|
|
@@ -0,0 +1,99 @@
|
|
1
|
+
Feature: berks info
|
2
|
+
Scenario: With no options
|
3
|
+
Given the cookbook store has the cookbooks:
|
4
|
+
| fake | 1.0.0 |
|
5
|
+
And I have a Berksfile pointing at the local Berkshelf API with:
|
6
|
+
"""
|
7
|
+
cookbook 'fake', '1.0.0'
|
8
|
+
"""
|
9
|
+
And I write to "Berksfile.lock" with:
|
10
|
+
"""
|
11
|
+
DEPENDENCIES
|
12
|
+
fake (= 1.0.0)
|
13
|
+
|
14
|
+
GRAPH
|
15
|
+
fake (1.0.0)
|
16
|
+
"""
|
17
|
+
When I successfully run `berks info fake`
|
18
|
+
Then the output should contain:
|
19
|
+
"""
|
20
|
+
Name: fake
|
21
|
+
Version: 1.0.0
|
22
|
+
Description: A fabulous new cookbook
|
23
|
+
Author: YOUR_COMPANY_NAME
|
24
|
+
Email: YOUR_EMAIL
|
25
|
+
License: none
|
26
|
+
"""
|
27
|
+
|
28
|
+
Scenario: When the parameter is a transitive dependency
|
29
|
+
Given the cookbook store has the cookbooks:
|
30
|
+
| dep | 1.0.0 |
|
31
|
+
And the cookbook store contains a cookbook "fake" "1.0.0" with dependencies:
|
32
|
+
| dep | ~> 1.0.0 |
|
33
|
+
And I have a Berksfile pointing at the local Berkshelf API with:
|
34
|
+
"""
|
35
|
+
cookbook 'fake', '1.0.0'
|
36
|
+
"""
|
37
|
+
And I write to "Berksfile.lock" with:
|
38
|
+
"""
|
39
|
+
DEPENDENCIES
|
40
|
+
fake (= 1.0.0)
|
41
|
+
|
42
|
+
GRAPH
|
43
|
+
dep (1.0.0)
|
44
|
+
fake (1.0.0)
|
45
|
+
dep (~> 1.0.0)
|
46
|
+
"""
|
47
|
+
And I successfully run `berks install`
|
48
|
+
When I successfully run `berks info dep`
|
49
|
+
Then the output should contain:
|
50
|
+
"""
|
51
|
+
Name: dep
|
52
|
+
Version: 1.0.0
|
53
|
+
Description: A fabulous new cookbook
|
54
|
+
Author: YOUR_COMPANY_NAME
|
55
|
+
Email: YOUR_EMAIL
|
56
|
+
License: none
|
57
|
+
"""
|
58
|
+
|
59
|
+
Scenario: When the cookbook is not in the Berksfile
|
60
|
+
Given I have a Berksfile pointing at the local Berkshelf API
|
61
|
+
When I run `berks info fake`
|
62
|
+
Then the output should contain:
|
63
|
+
"""
|
64
|
+
Dependency 'fake' was not found. Please make sure it is in your Berksfile, and then run `berks install` to download and install the missing dependencies.
|
65
|
+
"""
|
66
|
+
And the exit status should be "DependencyNotFound"
|
67
|
+
|
68
|
+
Scenario: When there is no lockfile present
|
69
|
+
And I have a Berksfile pointing at the local Berkshelf API with:
|
70
|
+
"""
|
71
|
+
cookbook 'fake', '1.0.0'
|
72
|
+
"""
|
73
|
+
When I run `berks info fake`
|
74
|
+
Then the output should contain:
|
75
|
+
"""
|
76
|
+
Dependency 'fake' was not found. Please make sure it is in your Berksfile, and then run `berks install` to download and install the missing dependencies.
|
77
|
+
"""
|
78
|
+
And the exit status should be "DependencyNotFound"
|
79
|
+
|
80
|
+
Scenario: When the cookbook is not installed
|
81
|
+
Given the cookbook store is empty
|
82
|
+
And I have a Berksfile pointing at the local Berkshelf API with:
|
83
|
+
"""
|
84
|
+
cookbook 'fake', '1.0.0'
|
85
|
+
"""
|
86
|
+
And I write to "Berksfile.lock" with:
|
87
|
+
"""
|
88
|
+
DEPENDENCIES
|
89
|
+
fake (= 1.0.0)
|
90
|
+
|
91
|
+
GRAPH
|
92
|
+
fake (1.0.0)
|
93
|
+
"""
|
94
|
+
When I run `berks info fake`
|
95
|
+
Then the output should contain:
|
96
|
+
"""
|
97
|
+
Cookbook 'fake' (1.0.0) not found in the cookbook store!
|
98
|
+
"""
|
99
|
+
And the exit status should be "CookbookNotFound"
|
@@ -15,15 +15,7 @@ Feature: berks show
|
|
15
15
|
fake (1.0.0)
|
16
16
|
"""
|
17
17
|
When I successfully run `berks show fake`
|
18
|
-
Then the output should contain
|
19
|
-
"""
|
20
|
-
Name: fake
|
21
|
-
Version: 1.0.0
|
22
|
-
Description: A fabulous new cookbook
|
23
|
-
Author: YOUR_COMPANY_NAME
|
24
|
-
Email: YOUR_EMAIL
|
25
|
-
License: none
|
26
|
-
"""
|
18
|
+
Then the output should contain "cookbooks/fake-1.0.0"
|
27
19
|
|
28
20
|
Scenario: When the parameter is a transitive dependency
|
29
21
|
Given the cookbook store has the cookbooks:
|
@@ -46,15 +38,7 @@ Feature: berks show
|
|
46
38
|
"""
|
47
39
|
And I successfully run `berks install`
|
48
40
|
When I successfully run `berks show dep`
|
49
|
-
Then the output should contain
|
50
|
-
"""
|
51
|
-
Name: dep
|
52
|
-
Version: 1.0.0
|
53
|
-
Description: A fabulous new cookbook
|
54
|
-
Author: YOUR_COMPANY_NAME
|
55
|
-
Email: YOUR_EMAIL
|
56
|
-
License: none
|
57
|
-
"""
|
41
|
+
Then the output should contain "cookbooks/dep-1.0.0"
|
58
42
|
|
59
43
|
Scenario: When the cookbook is not in the Berksfile
|
60
44
|
Given I have a Berksfile pointing at the local Berkshelf API
|
@@ -0,0 +1,65 @@
|
|
1
|
+
Feature: berks viz
|
2
|
+
Scenario: With no options
|
3
|
+
* I have a Berksfile pointing at the local Berkshelf API with:
|
4
|
+
"""
|
5
|
+
cookbook 'fake', '1.0.0'
|
6
|
+
"""
|
7
|
+
* I write to "Berksfile.lock" with:
|
8
|
+
"""
|
9
|
+
DEPENDENCIES
|
10
|
+
fake (= 1.0.0)
|
11
|
+
|
12
|
+
GRAPH
|
13
|
+
fake (1.0.0)
|
14
|
+
"""
|
15
|
+
* I successfully run `berks viz`
|
16
|
+
* a file named "graph.png" should exist
|
17
|
+
|
18
|
+
Scenario: When there are transitive dependencies
|
19
|
+
* I have a Berksfile pointing at the local Berkshelf API with:
|
20
|
+
"""
|
21
|
+
cookbook 'fake', '1.0.0'
|
22
|
+
"""
|
23
|
+
* I write to "Berksfile.lock" with:
|
24
|
+
"""
|
25
|
+
DEPENDENCIES
|
26
|
+
fake (= 1.0.0)
|
27
|
+
|
28
|
+
GRAPH
|
29
|
+
dep (1.0.0)
|
30
|
+
fake (1.0.0)
|
31
|
+
dep (~> 1.0.0)
|
32
|
+
"""
|
33
|
+
* I successfully run `berks viz`
|
34
|
+
* a file named "graph.png" should exist
|
35
|
+
|
36
|
+
Scenario: When a custom output is given
|
37
|
+
* I have a Berksfile pointing at the local Berkshelf API with:
|
38
|
+
"""
|
39
|
+
cookbook 'fake', '1.0.0'
|
40
|
+
"""
|
41
|
+
* I write to "Berksfile.lock" with:
|
42
|
+
"""
|
43
|
+
DEPENDENCIES
|
44
|
+
fake (= 1.0.0)
|
45
|
+
|
46
|
+
GRAPH
|
47
|
+
dep (1.0.0)
|
48
|
+
fake (1.0.0)
|
49
|
+
dep (~> 1.0.0)
|
50
|
+
"""
|
51
|
+
* I successfully run `berks viz --outfile ponies.png`
|
52
|
+
* a file named "graph.png" should not exist
|
53
|
+
* a file named "ponies.png" should exist
|
54
|
+
|
55
|
+
Scenario: When there is no lockfile present
|
56
|
+
* I have a Berksfile pointing at the local Berkshelf API with:
|
57
|
+
"""
|
58
|
+
cookbook 'fake', '1.0.0'
|
59
|
+
"""
|
60
|
+
* I run `berks viz`
|
61
|
+
* the output should contain:
|
62
|
+
"""
|
63
|
+
Lockfile not found! Run `berks install` to create the lockfile.
|
64
|
+
"""
|
65
|
+
* the exit status should be "LockfileNotFound"
|
@@ -81,11 +81,7 @@ Feature: --format json
|
|
81
81
|
"cookbooks": [
|
82
82
|
{
|
83
83
|
"name": "fake",
|
84
|
-
"
|
85
|
-
"description": "A fabulous new cookbook",
|
86
|
-
"author": "YOUR_COMPANY_NAME",
|
87
|
-
"email": "YOUR_EMAIL",
|
88
|
-
"license": "none"
|
84
|
+
"path": "<%= Berkshelf.cookbook_store.storage_path.join('fake-1.0.0') %>"
|
89
85
|
}
|
90
86
|
],
|
91
87
|
"errors": [],
|
@@ -15,7 +15,8 @@ class Hash
|
|
15
15
|
end
|
16
16
|
|
17
17
|
Then /^the output should contain JSON:$/ do |data|
|
18
|
-
|
18
|
+
parsed = ERB.new(data).result
|
19
|
+
target = JSON.pretty_generate(JSON.parse(parsed).sort_by_key)
|
19
20
|
actual = JSON.pretty_generate(JSON.parse(all_output).sort_by_key)
|
20
21
|
|
21
22
|
expect(actual).to eq(target)
|
data/lib/berkshelf/berksfile.rb
CHANGED
@@ -627,6 +627,21 @@ module Berkshelf
|
|
627
627
|
destination
|
628
628
|
end
|
629
629
|
|
630
|
+
# Visualize the current Berksfile as a "graph" using DOT.
|
631
|
+
#
|
632
|
+
# @param [String] outfile
|
633
|
+
# the name/path to outfile the file
|
634
|
+
#
|
635
|
+
# @return [String] path
|
636
|
+
# the path where the image was written
|
637
|
+
def viz(outfile = nil)
|
638
|
+
outfile = File.join(Dir.pwd, outfile || 'graph.png')
|
639
|
+
|
640
|
+
validate_lockfile_present!
|
641
|
+
validate_lockfile_trusted!
|
642
|
+
Visualizer.from_lockfile(lockfile).to_png(outfile)
|
643
|
+
end
|
644
|
+
|
630
645
|
# Get the lockfile corresponding to this Berksfile. This is necessary because
|
631
646
|
# the user can specify a different path to the Berksfile. So assuming the lockfile
|
632
647
|
# is named "Berksfile.lock" is a poor assumption.
|
data/lib/berkshelf/cli.rb
CHANGED
@@ -307,7 +307,20 @@ module Berkshelf
|
|
307
307
|
desc: "Path to a Berksfile to operate off of.",
|
308
308
|
aliases: "-b",
|
309
309
|
banner: "PATH"
|
310
|
-
desc "
|
310
|
+
desc "info [COOKBOOK]", "Display name, author, copyright, and dependency information about a cookbook"
|
311
|
+
def info(name)
|
312
|
+
berksfile = Berksfile.from_options(options)
|
313
|
+
cookbook = berksfile.retrieve_locked(name)
|
314
|
+
Berkshelf.formatter.info(cookbook)
|
315
|
+
end
|
316
|
+
|
317
|
+
method_option :berksfile,
|
318
|
+
type: :string,
|
319
|
+
default: nil,
|
320
|
+
desc: "Path to a Berksfile to operate off of.",
|
321
|
+
aliases: "-b",
|
322
|
+
banner: "PATH"
|
323
|
+
desc "show [COOKBOOK]", "Display the path to a cookbook on disk"
|
311
324
|
def show(name)
|
312
325
|
berksfile = Berksfile.from_options(options)
|
313
326
|
cookbook = berksfile.retrieve_locked(name)
|
@@ -381,7 +394,27 @@ module Berkshelf
|
|
381
394
|
berksfile.vendor(path)
|
382
395
|
end
|
383
396
|
|
384
|
-
|
397
|
+
method_option :berksfile,
|
398
|
+
type: :string,
|
399
|
+
default: nil,
|
400
|
+
desc: 'Path to a Berksfile to operate off of.',
|
401
|
+
aliases: '-b',
|
402
|
+
banner: 'PATH'
|
403
|
+
method_option :outfile,
|
404
|
+
type: :string,
|
405
|
+
default: 'graph.png',
|
406
|
+
desc: 'The name of the output file',
|
407
|
+
aliases: '-o',
|
408
|
+
banner: 'NAME'
|
409
|
+
desc "viz", "Visualize the dependency graph"
|
410
|
+
def viz
|
411
|
+
berksfile = Berksfile.from_options(options)
|
412
|
+
path = berksfile.viz(options[:outfile])
|
413
|
+
|
414
|
+
Berkshelf.ui.info(path)
|
415
|
+
end
|
416
|
+
|
417
|
+
desc 'version', 'Display version'
|
385
418
|
def version
|
386
419
|
Berkshelf.formatter.version
|
387
420
|
end
|
@@ -19,7 +19,7 @@ module Berkshelf
|
|
19
19
|
end
|
20
20
|
|
21
21
|
method_option :version, aliases: '-v', type: :string, desc: 'Version to show'
|
22
|
-
desc 'show', 'Display
|
22
|
+
desc 'show', 'Display showrmation about a cookbook in the Berkshelf shelf'
|
23
23
|
def show(name)
|
24
24
|
cookbooks = find(name, options[:version])
|
25
25
|
|
@@ -30,7 +30,7 @@ module Berkshelf
|
|
30
30
|
end
|
31
31
|
|
32
32
|
cookbooks.each do |cookbook|
|
33
|
-
Berkshelf.formatter.
|
33
|
+
Berkshelf.formatter.info(cookbook)
|
34
34
|
Berkshelf.formatter.msg("\n")
|
35
35
|
end
|
36
36
|
end
|
data/lib/berkshelf/errors.rb
CHANGED
@@ -69,11 +69,13 @@ module Berkshelf
|
|
69
69
|
attr_reader :demands
|
70
70
|
|
71
71
|
# @param [Array<Dependency>] demands
|
72
|
-
def initialize(demands)
|
72
|
+
def initialize(demands, original_exception)
|
73
73
|
@demands = demands
|
74
|
+
@original_exception = original_exception
|
74
75
|
end
|
75
76
|
|
76
77
|
def to_s
|
78
|
+
@original_exception.to_s +
|
77
79
|
"Unable to find a solution for demands: #{demands.join(', ')}"
|
78
80
|
end
|
79
81
|
end
|
@@ -452,4 +454,29 @@ module Berkshelf
|
|
452
454
|
" source 'https://api.berkshelf.com'"
|
453
455
|
end
|
454
456
|
end
|
457
|
+
|
458
|
+
class GraphvizNotInstalled < BerkshelfError
|
459
|
+
status_code(147)
|
460
|
+
|
461
|
+
def to_s
|
462
|
+
"Graphviz is not installed! In order to generate a dependency graph, " \
|
463
|
+
"you must install Graphviz. Please visit the Graphviz homepage at " \
|
464
|
+
"http://www.graphviz.org/ or consult your package manager for more " \
|
465
|
+
"information on how to install Graphviz."
|
466
|
+
end
|
467
|
+
end
|
468
|
+
|
469
|
+
class GraphvizCommandFailed < BerkshelfError
|
470
|
+
status_code(148)
|
471
|
+
|
472
|
+
def initialize(command, output)
|
473
|
+
@command = command
|
474
|
+
@output = output
|
475
|
+
end
|
476
|
+
|
477
|
+
def to_s
|
478
|
+
"The Graphviz command `#{@command}` failed to execute properly. Here " \
|
479
|
+
"is the standard error from the command:\n\n#{@output}"
|
480
|
+
end
|
481
|
+
end
|
455
482
|
end
|
@@ -77,6 +77,13 @@ module Berkshelf
|
|
77
77
|
Berkshelf.ui.info "Cookbook(s) packaged to #{destination}"
|
78
78
|
end
|
79
79
|
|
80
|
+
# Output the important information about a cookbook using {Berkshelf.ui}.
|
81
|
+
#
|
82
|
+
# @param [CachedCookbook] cookbook
|
83
|
+
def info(cookbook)
|
84
|
+
Berkshelf.ui.info(cookbook.pretty_print)
|
85
|
+
end
|
86
|
+
|
80
87
|
# Output a list of cookbooks using {Berkshelf.ui}
|
81
88
|
#
|
82
89
|
# @param [Array<Dependency>] list
|
@@ -98,11 +105,12 @@ module Berkshelf
|
|
98
105
|
end
|
99
106
|
end
|
100
107
|
|
101
|
-
# Output Cookbook
|
108
|
+
# Output Cookbook path using {Berkshelf.ui}
|
102
109
|
#
|
103
110
|
# @param [CachedCookbook] cookbook
|
104
111
|
def show(cookbook)
|
105
|
-
|
112
|
+
path = File.expand_path(cookbook.path)
|
113
|
+
Berkshelf.ui.info(path)
|
106
114
|
end
|
107
115
|
|
108
116
|
# Output Cookbook vendor info message using {Berkshelf.ui}
|
@@ -101,6 +101,14 @@ module Berkshelf
|
|
101
101
|
end
|
102
102
|
end
|
103
103
|
|
104
|
+
# Output Cookbook info entry to delayed output.
|
105
|
+
#
|
106
|
+
# @param [CachedCookbook] cookbook
|
107
|
+
def info(cookbook)
|
108
|
+
path = File.expand_path(cookbook.path)
|
109
|
+
cookbooks[cookbook.cookbook_name] = { path: path }
|
110
|
+
end
|
111
|
+
|
104
112
|
# Output a package message using
|
105
113
|
#
|
106
114
|
# @param [String] destination
|
@@ -121,11 +129,12 @@ module Berkshelf
|
|
121
129
|
end
|
122
130
|
end
|
123
131
|
|
124
|
-
# Output Cookbook
|
132
|
+
# Output Cookbook path entry to delayed output
|
125
133
|
#
|
126
134
|
# @param [CachedCookbook] cookbook
|
127
135
|
def show(cookbook)
|
128
|
-
|
136
|
+
path = File.expand_path(cookbook.path)
|
137
|
+
cookbooks[cookbook.cookbook_name] = { path: path }
|
129
138
|
end
|
130
139
|
|
131
140
|
# Ouput Cookbook search results to delayed output
|
data/lib/berkshelf/lockfile.rb
CHANGED
@@ -579,6 +579,8 @@ module Berkshelf
|
|
579
579
|
|
580
580
|
# The class representing an internal graph.
|
581
581
|
class Graph
|
582
|
+
include Enumerable
|
583
|
+
|
582
584
|
# Create a new Lockfile graph.
|
583
585
|
#
|
584
586
|
# Some clarifying terminology:
|
@@ -593,6 +595,11 @@ module Berkshelf
|
|
593
595
|
@graph = {}
|
594
596
|
end
|
595
597
|
|
598
|
+
# @yield [Hash<String]
|
599
|
+
def each(&block)
|
600
|
+
@graph.values.each(&block)
|
601
|
+
end
|
602
|
+
|
596
603
|
# The list of locks for this graph. Dependencies are retrieved from the
|
597
604
|
# lockfile, then the Berksfile, and finally a new dependency object is
|
598
605
|
# created if none of those exist.
|
data/lib/berkshelf/resolver.rb
CHANGED
@@ -79,8 +79,8 @@ module Berkshelf
|
|
79
79
|
|
80
80
|
dependency
|
81
81
|
end
|
82
|
-
rescue Solve::Errors::NoSolutionError
|
83
|
-
raise NoSolutionError.new(demands)
|
82
|
+
rescue Solve::Errors::NoSolutionError => e
|
83
|
+
raise NoSolutionError.new(demands, e)
|
84
84
|
end
|
85
85
|
|
86
86
|
# Retrieve the given demand from the resolver
|
data/lib/berkshelf/version.rb
CHANGED
@@ -0,0 +1,103 @@
|
|
1
|
+
require 'buff/shell_out'
|
2
|
+
require 'set'
|
3
|
+
require 'tempfile'
|
4
|
+
|
5
|
+
module Berkshelf
|
6
|
+
class Visualizer
|
7
|
+
class << self
|
8
|
+
def from_lockfile(lockfile)
|
9
|
+
new.tap do |instance|
|
10
|
+
lockfile.graph.each do |item|
|
11
|
+
instance.node(item.name)
|
12
|
+
|
13
|
+
item.dependencies.each do |name, version|
|
14
|
+
instance.edge(item.name, name)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
include Buff::ShellOut
|
22
|
+
|
23
|
+
def initialize
|
24
|
+
@nodes = {}
|
25
|
+
end
|
26
|
+
|
27
|
+
def node(object)
|
28
|
+
@nodes[object] ||= Set.new
|
29
|
+
self
|
30
|
+
end
|
31
|
+
|
32
|
+
def nodes
|
33
|
+
@nodes.keys
|
34
|
+
end
|
35
|
+
|
36
|
+
def each_node(&block)
|
37
|
+
nodes.each(&block)
|
38
|
+
end
|
39
|
+
|
40
|
+
def edge(a, b)
|
41
|
+
node(a)
|
42
|
+
node(b)
|
43
|
+
|
44
|
+
@nodes[a].add(b)
|
45
|
+
end
|
46
|
+
|
47
|
+
def adjacencies(object)
|
48
|
+
@nodes[object] || Set.new
|
49
|
+
end
|
50
|
+
|
51
|
+
# Convert the current graph to a DOT. This is an intermediate step in
|
52
|
+
# generating a PNG.
|
53
|
+
#
|
54
|
+
# @return [String]
|
55
|
+
def to_dot
|
56
|
+
out = %|digraph Solve__Graph {\n|
|
57
|
+
|
58
|
+
nodes.each do |node|
|
59
|
+
out << %| "#{node}" [ fontsize = 10, label = "#{node}" ]\n|
|
60
|
+
end
|
61
|
+
|
62
|
+
nodes.each do |node|
|
63
|
+
adjacencies(node).each do |edge|
|
64
|
+
out << %| "#{node}" -> "#{edge}" [ fontsize = 10 ]\n|
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
out << %|}|
|
69
|
+
out
|
70
|
+
end
|
71
|
+
|
72
|
+
# Save the graph visually as a PNG.
|
73
|
+
#
|
74
|
+
# @param [String] outfile
|
75
|
+
# the name/path of the file to output
|
76
|
+
#
|
77
|
+
# @return [String]
|
78
|
+
# the path where the file was written
|
79
|
+
def to_png(outfile = 'graph.png')
|
80
|
+
tempfile = Tempfile.new('dotdotfile')
|
81
|
+
tempfile.write(to_dot)
|
82
|
+
tempfile.rewind
|
83
|
+
|
84
|
+
unless Berkshelf.which('dot')
|
85
|
+
raise GraphvizNotInstalled.new
|
86
|
+
end
|
87
|
+
|
88
|
+
command = "dot -T png #{tempfile.path} -o #{outfile}"
|
89
|
+
response = shell_out(command)
|
90
|
+
|
91
|
+
unless response.success?
|
92
|
+
raise GraphvizCommandFailed.new(command, response.stderr)
|
93
|
+
end
|
94
|
+
|
95
|
+
File.expand_path(outfile)
|
96
|
+
ensure
|
97
|
+
if tempfile && File.exist?(tempfile.path)
|
98
|
+
tempfile.close
|
99
|
+
tempfile.unlink
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
data/lib/berkshelf.rb
CHANGED
@@ -25,7 +25,8 @@ module Berkshelf
|
|
25
25
|
autoload :Logging, 'berkshelf/mixin/logging'
|
26
26
|
end
|
27
27
|
|
28
|
-
autoload :Uploader,
|
28
|
+
autoload :Uploader, 'berkshelf/uploader'
|
29
|
+
autoload :Visualizer, 'berkshelf/visualizer'
|
29
30
|
|
30
31
|
autoload :BaseFormatter, 'berkshelf/formatters/base'
|
31
32
|
autoload :HumanFormatter, 'berkshelf/formatters/human'
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Berkshelf
|
4
|
+
describe Visualizer do
|
5
|
+
describe '#to_png' do
|
6
|
+
context 'when graphviz is not installed' do
|
7
|
+
before do
|
8
|
+
Berkshelf.stub(:which)
|
9
|
+
.with('dot')
|
10
|
+
.and_return(nil)
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'raises a GraphvizNotInstalled exception' do
|
14
|
+
expect { subject.to_png }.to raise_error(GraphvizNotInstalled)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
context 'when the graphviz command fails' do
|
19
|
+
before do
|
20
|
+
response = double(success?: false, stderr: 'Something happened!')
|
21
|
+
subject.stub(:shell_out).and_return(response)
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'raises a GraphvizCommandFailed exception' do
|
25
|
+
expect { subject.to_png }.to raise_error(GraphvizCommandFailed)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: berkshelf
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.0
|
4
|
+
version: 3.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jamie Winsor
|
@@ -12,7 +12,7 @@ authors:
|
|
12
12
|
autorequire:
|
13
13
|
bindir: bin
|
14
14
|
cert_chain: []
|
15
|
-
date: 2014-04-
|
15
|
+
date: 2014-04-19 00:00:00.000000000 Z
|
16
16
|
dependencies:
|
17
17
|
- !ruby/object:Gem::Dependency
|
18
18
|
name: addressable
|
@@ -174,14 +174,14 @@ dependencies:
|
|
174
174
|
requirements:
|
175
175
|
- - "~>"
|
176
176
|
- !ruby/object:Gem::Version
|
177
|
-
version: '
|
177
|
+
version: '3.0'
|
178
178
|
type: :runtime
|
179
179
|
prerelease: false
|
180
180
|
version_requirements: !ruby/object:Gem::Requirement
|
181
181
|
requirements:
|
182
182
|
- - "~>"
|
183
183
|
- !ruby/object:Gem::Version
|
184
|
-
version: '
|
184
|
+
version: '3.0'
|
185
185
|
- !ruby/object:Gem::Dependency
|
186
186
|
name: celluloid
|
187
187
|
requirement: !ruby/object:Gem::Requirement
|
@@ -364,6 +364,7 @@ files:
|
|
364
364
|
- features/commands/apply.feature
|
365
365
|
- features/commands/contingent.feature
|
366
366
|
- features/commands/cookbook.feature
|
367
|
+
- features/commands/info.feature
|
367
368
|
- features/commands/init.feature
|
368
369
|
- features/commands/install.feature
|
369
370
|
- features/commands/list.feature
|
@@ -377,6 +378,7 @@ files:
|
|
377
378
|
- features/commands/update.feature
|
378
379
|
- features/commands/upload.feature
|
379
380
|
- features/commands/vendor.feature
|
381
|
+
- features/commands/viz.feature
|
380
382
|
- features/community_site.feature
|
381
383
|
- features/config.feature
|
382
384
|
- features/help.feature
|
@@ -458,6 +460,7 @@ files:
|
|
458
460
|
- lib/berkshelf/ui.rb
|
459
461
|
- lib/berkshelf/uploader.rb
|
460
462
|
- lib/berkshelf/version.rb
|
463
|
+
- lib/berkshelf/visualizer.rb
|
461
464
|
- spec/config/berkshelf.pem
|
462
465
|
- spec/config/knife.rb
|
463
466
|
- spec/config/validator.pem
|
@@ -519,6 +522,7 @@ files:
|
|
519
522
|
- spec/unit/berkshelf/source_uri_spec.rb
|
520
523
|
- spec/unit/berkshelf/ui_spec.rb
|
521
524
|
- spec/unit/berkshelf/uploader_spec.rb
|
525
|
+
- spec/unit/berkshelf/visualizer_spec.rb
|
522
526
|
- spec/unit/berkshelf_spec.rb
|
523
527
|
homepage: http://berkshelf.com
|
524
528
|
licenses:
|
@@ -549,6 +553,7 @@ test_files:
|
|
549
553
|
- features/commands/apply.feature
|
550
554
|
- features/commands/contingent.feature
|
551
555
|
- features/commands/cookbook.feature
|
556
|
+
- features/commands/info.feature
|
552
557
|
- features/commands/init.feature
|
553
558
|
- features/commands/install.feature
|
554
559
|
- features/commands/list.feature
|
@@ -562,6 +567,7 @@ test_files:
|
|
562
567
|
- features/commands/update.feature
|
563
568
|
- features/commands/upload.feature
|
564
569
|
- features/commands/vendor.feature
|
570
|
+
- features/commands/viz.feature
|
565
571
|
- features/community_site.feature
|
566
572
|
- features/config.feature
|
567
573
|
- features/help.feature
|
@@ -641,5 +647,6 @@ test_files:
|
|
641
647
|
- spec/unit/berkshelf/source_uri_spec.rb
|
642
648
|
- spec/unit/berkshelf/ui_spec.rb
|
643
649
|
- spec/unit/berkshelf/uploader_spec.rb
|
650
|
+
- spec/unit/berkshelf/visualizer_spec.rb
|
644
651
|
- spec/unit/berkshelf_spec.rb
|
645
652
|
has_rdoc:
|