berkshelf 3.0.1 → 3.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|