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 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: