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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 75026863f3ac7d0354ae193fca6bf1aa349d162f
4
- data.tar.gz: a884f962a1a102373b9feabb1b5b00100187f7be
3
+ metadata.gz: fe531a8a2654076d566b236313b3eeef9c1d6d8b
4
+ data.tar.gz: c5560108ebd912946fdf1f7a55649f85705f71f3
5
5
  SHA512:
6
- metadata.gz: 46dcd9ee69329376da45c88d0d7959471fa40b7f0454772a05a9e4ab628786b1118c79a9a7f9f7b257a0740d9f57c779f286ef02bbf9ee0e99bc06d98b8c3b69
7
- data.tar.gz: 5ac2b0283b9bf41c34360e946a26fb4bc85c4788412dde6638de32dad97b4378fa5fda37741e9173a611602b8f0c3359e5f190521be5456623134eb14ea77876
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
@@ -31,5 +31,5 @@ group :guard do
31
31
  end
32
32
 
33
33
  group :test do
34
- gem 'berkshelf-api', "~> 1.2"
34
+ gem 'berkshelf-api', "~> 1.3"
35
35
  end
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
- **WARNING:** It is advised at this time that you [use Berkshelf 3](https://github.com/berkshelf/berkshelf/wiki/Howto:-Use-the-bleeding-edge). Berkshelf 2 is no longer being actively developed and has a number of significant issues related to dependency resolution that Berkshelf 3 fixes.
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
- ### Gem Installation
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.0, and JRuby 1.6+.
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', '~> 2.6'
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
- "version": "1.0.0",
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
- target = JSON.pretty_generate(JSON.parse(data).sort_by_key)
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)
@@ -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.
@@ -26,7 +26,6 @@ module Berkshelf
26
26
  DIRNAME_REGEXP = /^(.+)-(.+)$/.freeze
27
27
 
28
28
  extend Forwardable
29
-
30
29
  def_delegator :metadata, :description
31
30
  def_delegator :metadata, :maintainer
32
31
  def_delegator :metadata, :maintainer_email
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 "show [COOKBOOK]", "Display name, author, copyright, and dependency information about a cookbook"
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
- desc 'version', 'Display version and copyright information'
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 information about a cookbook in the Berkshelf shelf'
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.show(cookbook)
33
+ Berkshelf.formatter.info(cookbook)
34
34
  Berkshelf.formatter.msg("\n")
35
35
  end
36
36
  end
@@ -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
@@ -24,6 +24,7 @@ module Berkshelf
24
24
 
25
25
  # Object methods
26
26
  formatter_method :fetch
27
+ formatter_method :info
27
28
  formatter_method :install
28
29
  formatter_method :list
29
30
  formatter_method :outdated
@@ -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 info message using {Berkshelf.ui}
108
+ # Output Cookbook path using {Berkshelf.ui}
102
109
  #
103
110
  # @param [CachedCookbook] cookbook
104
111
  def show(cookbook)
105
- Berkshelf.ui.info(cookbook.pretty_print)
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 info entry to delayed output
132
+ # Output Cookbook path entry to delayed output
125
133
  #
126
134
  # @param [CachedCookbook] cookbook
127
135
  def show(cookbook)
128
- cookbooks[cookbook.cookbook_name] = cookbook.pretty_hash
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
@@ -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.
@@ -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
@@ -1,3 +1,3 @@
1
1
  module Berkshelf
2
- VERSION = '3.0.1'
2
+ VERSION = '3.1.0'
3
3
  end
@@ -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, 'berkshelf/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.1
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 00:00:00.000000000 Z
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: '2.6'
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: '2.6'
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: