brew_dg 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/LICENSE +20 -0
- data/README.md +108 -0
- data/bin/brew_dg +9 -0
- data/lib/brew_dg/cli.rb +50 -0
- data/lib/brew_dg/dependency_manifest.rb +38 -0
- data/lib/brew_dg/graph.rb +50 -0
- data/lib/brew_dg/graph_installation.rb +29 -0
- data/lib/brew_dg/library.rb +74 -0
- data/lib/brew_dg/option_parser.rb +60 -0
- data/lib/brew_dg/package.rb +19 -0
- data/lib/brew_dg/queryable_dependencies.rb +41 -0
- data/lib/brew_dg.rb +5 -0
- data/spec/integration/homebrew_output_spec.rb +57 -0
- data/spec/unit/dependency_manifest_spec.rb +64 -0
- data/spec/unit/graph_installation_spec.rb +62 -0
- data/spec/unit/queryable_dependencies_spec.rb +46 -0
- metadata +121 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
NWNmM2Q2MmY1MDQwZDE1YWM0NTk5ZWZiYzEwZDBkZDgwNGQ1ODZkNA==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
MGY1MjRjYzY2MWJiMzE3YWM3ODgxZjA0OTE1NmVjYjI4YWRlNDIyNQ==
|
7
|
+
!binary "U0hBNTEy":
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
NTllYmE2OGJhZGM0MWJlYWI1NTcxMzkzNmJmZmNiYzllZmQ0N2Q2N2QxMjNm
|
10
|
+
NGQ3MjkyZTYxNjNmNzNlZTZiODA4MGVmNGIxNjQxNjM5ZjI4NzgyMjg5NjBj
|
11
|
+
OGU3Njc1MmZlYjJkOGVmNDMzMGM0ZWMxMzUxYWMxNDJmMjg0MjE=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
ZDA1YmE0NDdhNTYwMTJiYTQxNDAxOGNhMzViNWNhODE3YmI2NDI5Zjk2MzE5
|
14
|
+
NTE2NTg5ZGVlNGVmZTZiM2YyOWQ0MjlkODk0NmQ4ZGE4MWY2NWM4OTYyYmMy
|
15
|
+
NjUyMTc5OWRiMmZmZWMyZWNlZmVlMTNjZmQ1ZDY5YWJjMzRlNzI=
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2013 Brian Cobb
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
6
|
+
this software and associated documentation files (the "Software"), to deal in
|
7
|
+
the Software without restriction, including without limitation the rights to
|
8
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
9
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
10
|
+
subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
17
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
18
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
19
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
20
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
# BrewDG
|
2
|
+
|
3
|
+
Homebrew Dependency Graphs.
|
4
|
+
|
5
|
+
BrewDG allows you to visualize your homebrew package dependencies. It can also take a list of packages, and give you those packages, with each package preceeded by its dependencies (and its dependencies will be preceeded by _its_ dependencies, and so forth).
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
`gem install brew_dg`
|
10
|
+
|
11
|
+
**N.B.**: this is not the sort of tool that should be distributed as a gem. See [Gary Bernhardt's comment](https://github.com/garybernhardt/selecta#installation) on this in the `selecta` README. Alas, while `brew_dg` has a couple of bulky dependencies, it'll remain a gem.
|
12
|
+
|
13
|
+
## Examples
|
14
|
+
|
15
|
+
`brew_dg` is pretty slow since it's issuing and parsing the output of `brew` commands. Which is to say, you may want to have a beverage to sip while using it, particularly on a large number of packages.
|
16
|
+
|
17
|
+
1. List packages plus their recommended dependencies. This is what compelled me to write `brew_dg`.
|
18
|
+
|
19
|
+
```
|
20
|
+
$ brew_dg git postgresql sqlite redis
|
21
|
+
> git readline ossp-uuid postgresql sqlite redis
|
22
|
+
```
|
23
|
+
|
24
|
+
We've added two packages to the initial list: `ossp-uuid`, which is recommended for `postgresql`, and `readline`, which is recommended for `sqlite`. Note that `readline` is in fact _required_ for `postgresql`; perhaps in the future we will take that into ordering consideration.
|
25
|
+
|
26
|
+
2. List all of a package's dependencies, including Optional and Build dependencies.
|
27
|
+
|
28
|
+
```
|
29
|
+
$ brew_dg -a postgis
|
30
|
+
> readline ossp-uuid postgresql proj geos json-c libpng jpeg giflib libtiff \
|
31
|
+
lzlib libgeotiff sqlite freexl libxml2 pkg-config libspatialite cmake \
|
32
|
+
mysql gdal autoconf automake libtool gpp postgis
|
33
|
+
```
|
34
|
+
|
35
|
+
3. Visualize homebrew dependencies. See [Graph](#graph) for visual details. (Note that these visualizations require graphviz):
|
36
|
+
|
37
|
+
```
|
38
|
+
$ brew_dg -o library.png
|
39
|
+
$ open library.png
|
40
|
+
```
|
41
|
+
|
42
|
+
4. Visualize a package's recommended and required dependencies (as well as their dependencies)
|
43
|
+
|
44
|
+
```
|
45
|
+
$ brew_dg -o postgis.png postgis
|
46
|
+
$ open postgis.png
|
47
|
+
```
|
48
|
+
|
49
|
+
[![](http://f.cl.ly/items/0i041b0u1F0e3n153Z1z/postgis.png)](http://f.cl.ly/items/3g2m3y2e150X1w2d263s/postgis.png)
|
50
|
+
|
51
|
+
5. Visualize all of a package's dependencies, including Optional and Build dependencies
|
52
|
+
|
53
|
+
```
|
54
|
+
$ brew_dg -a -o postgis.png postgis
|
55
|
+
$ open postgis.png
|
56
|
+
```
|
57
|
+
|
58
|
+
## Installation
|
59
|
+
|
60
|
+
`gem install brew_dg`
|
61
|
+
|
62
|
+
## Synopsis
|
63
|
+
|
64
|
+
brew_dg [options] [package package ...]
|
65
|
+
|
66
|
+
## Description
|
67
|
+
|
68
|
+
Assuming for the moment that brew_dg is given no options, for each
|
69
|
+
package given, brew_dg will display that package, along with its
|
70
|
+
Required and Recommended dependencies. brew_dg orders the packages such
|
71
|
+
that a given package will not be installed until its Recommended and
|
72
|
+
Required dependencies have been installed.
|
73
|
+
|
74
|
+
If no options or pacakges are given, brew_dg displays any homebrew
|
75
|
+
packages you've installed, along with any uninstalled, Recommended
|
76
|
+
dependencies in an order such that a package will not be installed until
|
77
|
+
its dependencies have been installed.
|
78
|
+
|
79
|
+
The following options allow users to configure and tweak the details of the
|
80
|
+
preceeding description:
|
81
|
+
|
82
|
+
-a
|
83
|
+
Display all dependencies, including Optional and Build dependencies.
|
84
|
+
|
85
|
+
-o [file]
|
86
|
+
Draw graph, and write it to file. Directed edges are read as "depends
|
87
|
+
on." If given a directory $DIR, the file will be located at
|
88
|
+
$DIR/library.png. See Graph section for stylistic details.
|
89
|
+
|
90
|
+
-O [file]
|
91
|
+
Draw inverted graph, and write it to file. Directed edges are read as
|
92
|
+
"is a dependency of." If given a directory $DIR, the file will be
|
93
|
+
located at $DIR/library.png. See Graph section for stylistic details.
|
94
|
+
|
95
|
+
-t types
|
96
|
+
Display only dependencies of the comma-delimited types specified. e.g.
|
97
|
+
`-t Recommended,Optional'
|
98
|
+
|
99
|
+
## Graph
|
100
|
+
|
101
|
+
The graph uses edge and arrow styles to differentiate between dependency
|
102
|
+
types.
|
103
|
+
|
104
|
+
Required: A solid edge with a filled, triangular arrow.
|
105
|
+
Recommended: A solid edge with an empty, triangular arrow.
|
106
|
+
Optional: A dotted edge with a filled, triangular arrow.
|
107
|
+
Build: A dotted edge with a tee-shaped arrow.
|
108
|
+
|
data/bin/brew_dg
ADDED
data/lib/brew_dg/cli.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'brew_dg/library'
|
2
|
+
require 'brew_dg/option_parser'
|
3
|
+
|
4
|
+
module BrewDG
|
5
|
+
class CLI
|
6
|
+
|
7
|
+
def initialize(argv, stdout = STDOUT, stderr = STDERR, kernel = Kernel)
|
8
|
+
@argv = argv
|
9
|
+
@stdout = stdout
|
10
|
+
@stderr = stderr
|
11
|
+
@kernel = kernel
|
12
|
+
@configuration = OptionParser.new.parse(@argv).options
|
13
|
+
|
14
|
+
if @argv.any?
|
15
|
+
@packages = @argv
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
attr_reader :configuration
|
20
|
+
|
21
|
+
def execute!
|
22
|
+
options = {}
|
23
|
+
|
24
|
+
if configuration[:types]
|
25
|
+
options.update(relevant_dependency_types: configuration[:types])
|
26
|
+
end
|
27
|
+
|
28
|
+
if @packages
|
29
|
+
options.update(packages: @packages)
|
30
|
+
end
|
31
|
+
|
32
|
+
library = Library.new(options)
|
33
|
+
|
34
|
+
if configuration[:destination]
|
35
|
+
graph = library.graph
|
36
|
+
|
37
|
+
if configuration[:inverted]
|
38
|
+
visualization = graph.reversal.visualization
|
39
|
+
else
|
40
|
+
visualization = graph.visualization
|
41
|
+
end
|
42
|
+
|
43
|
+
visualization.output(png: configuration[:destination])
|
44
|
+
else
|
45
|
+
@stdout.puts library.installation_order.join(' ')
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'virtus'
|
2
|
+
|
3
|
+
module BrewDG
|
4
|
+
class DependencyManifest
|
5
|
+
include Virtus.value_object
|
6
|
+
|
7
|
+
DEPENDENCY_TYPES = %w(Build Required Recommended Optional)
|
8
|
+
|
9
|
+
def self.for_package(package)
|
10
|
+
%x(brew info #{package}).lines.map(&method(:from_output)).compact
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.from_output(line)
|
14
|
+
type_match = line.match(/^(\w+):/)
|
15
|
+
type = type_match && type_match.captures.first
|
16
|
+
|
17
|
+
if DEPENDENCY_TYPES.include?(type)
|
18
|
+
manifest_header = "#{type}: "
|
19
|
+
manifest_parts = line.split(manifest_header)
|
20
|
+
|
21
|
+
if manifest_parts.size == 2
|
22
|
+
manifest_body = manifest_parts.last
|
23
|
+
dependencies = manifest_body.split(', ').map(&:strip)
|
24
|
+
else
|
25
|
+
dependencies = []
|
26
|
+
end
|
27
|
+
|
28
|
+
new(type: type.downcase.intern, dependencies: dependencies)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
values do
|
33
|
+
attribute :type, Symbol
|
34
|
+
attribute :dependencies, Array, default: []
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'delegate'
|
2
|
+
require 'graphviz'
|
3
|
+
require 'plexus'
|
4
|
+
|
5
|
+
module BrewDG
|
6
|
+
class Graph < ::Plexus::Digraph
|
7
|
+
|
8
|
+
def visualization
|
9
|
+
visualization = GraphViz.new(:G)
|
10
|
+
|
11
|
+
isolated_vertices.each do |vertex|
|
12
|
+
visualization.add_nodes(vertex.to_s)
|
13
|
+
end
|
14
|
+
|
15
|
+
edges.reduce(visualization) do |visualization, edge|
|
16
|
+
manifest = edge.to_a.last
|
17
|
+
|
18
|
+
left, right = edge.to_a.first(2).map do |package|
|
19
|
+
visualization.add_nodes(package.to_s)
|
20
|
+
end
|
21
|
+
|
22
|
+
visualization.add_edges(left, right, edge_options(manifest))
|
23
|
+
visualization
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def isolated_vertices
|
28
|
+
vertices.select do |vertex|
|
29
|
+
in_degree(vertex).zero? && out_degree(vertex).zero?
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def edge_options(manifest)
|
36
|
+
if manifest
|
37
|
+
type = manifest.type
|
38
|
+
|
39
|
+
edge_options = {
|
40
|
+
recommended: { arrowhead: 'empty' },
|
41
|
+
optional: { style: 'dotted' },
|
42
|
+
build: { style: 'dotted', arrowhead: 'tee' }
|
43
|
+
}.fetch(type, {})
|
44
|
+
else
|
45
|
+
{}
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module BrewDG
|
2
|
+
class GraphInstallation
|
3
|
+
|
4
|
+
attr_reader :graph
|
5
|
+
|
6
|
+
def initialize(graph)
|
7
|
+
@graph = graph
|
8
|
+
end
|
9
|
+
|
10
|
+
def list
|
11
|
+
graph.vertices.map { |vertex| for_vertex(vertex) }.flatten.uniq
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def for_vertex(vertex)
|
17
|
+
if graph.neighborhood(vertex, :out).size.zero?
|
18
|
+
[vertex]
|
19
|
+
else
|
20
|
+
dependency_order = graph.neighborhood(vertex, :out).map do |dependency|
|
21
|
+
for_vertex(dependency)
|
22
|
+
end
|
23
|
+
|
24
|
+
dependency_order + [vertex]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'brew_dg/dependency_manifest'
|
2
|
+
require 'brew_dg/graph'
|
3
|
+
require 'brew_dg/graph_installation'
|
4
|
+
require 'brew_dg/package'
|
5
|
+
require 'brew_dg/queryable_dependencies'
|
6
|
+
|
7
|
+
module BrewDG
|
8
|
+
class Library
|
9
|
+
|
10
|
+
def initialize(options = {})
|
11
|
+
@package_cache = options.fetch(:package_cache, {})
|
12
|
+
@packages = options.fetch(:packages) do
|
13
|
+
%x(brew list).lines.map(&:strip)
|
14
|
+
end
|
15
|
+
@relevant_dependency_types = options.fetch(:relevant_dependency_types) do
|
16
|
+
[:required, :recommended]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def graph
|
21
|
+
@packages.reduce(Graph.new) do |graph, name|
|
22
|
+
subgraph = subgraph(name)
|
23
|
+
|
24
|
+
graph.add_edges!(*subgraph.edges)
|
25
|
+
graph.add_vertices!(*subgraph.vertices)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def installation_order
|
30
|
+
installation = GraphInstallation.new(graph)
|
31
|
+
installation.list.map(&:to_s)
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def subgraph(name)
|
37
|
+
package = package(name)
|
38
|
+
|
39
|
+
Graph.new.tap do |graph|
|
40
|
+
graph.add_vertex!(package)
|
41
|
+
|
42
|
+
manifests = @relevant_dependency_types.map do |type|
|
43
|
+
package.dependencies.of_type(type)
|
44
|
+
end
|
45
|
+
|
46
|
+
manifests.reduce(graph) do |manifest_graph, manifest|
|
47
|
+
manifest.dependencies.reduce(manifest_graph) do |subgraph, dependency|
|
48
|
+
subgraph.add_edge!(package, dependency, manifest)
|
49
|
+
subgraph.add_edges!(*subgraph(dependency.name).edges)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def package(name)
|
56
|
+
@package_cache.fetch(name) do
|
57
|
+
manifests = DependencyManifest.for_package(name)
|
58
|
+
|
59
|
+
manifests.map! do |manifest|
|
60
|
+
packages = manifest.dependencies.map(&method(:package))
|
61
|
+
|
62
|
+
DependencyManifest.new(type: manifest.type, dependencies: packages)
|
63
|
+
end
|
64
|
+
|
65
|
+
dependencies = QueryableDependencies.new(manifests)
|
66
|
+
|
67
|
+
Package.new(name: name, dependencies: dependencies).tap do |package|
|
68
|
+
@package_cache.store(name, package)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
|
3
|
+
module BrewDG
|
4
|
+
class OptionParser
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@options = {}
|
8
|
+
end
|
9
|
+
|
10
|
+
attr_reader :options
|
11
|
+
|
12
|
+
def parse(args)
|
13
|
+
tap { parser.parse!(Array(args)) }
|
14
|
+
end
|
15
|
+
|
16
|
+
def parser
|
17
|
+
all_types = [:required, :recommended, :optional, :build]
|
18
|
+
|
19
|
+
::OptionParser.new do |parser|
|
20
|
+
parser.on('-a') do |a|
|
21
|
+
update(:types, all_types) if a
|
22
|
+
end
|
23
|
+
|
24
|
+
parser.on('-t type1,type2', Array) do |types|
|
25
|
+
types = Array(types).map(&:strip).map(&:downcase).map(&:intern)
|
26
|
+
|
27
|
+
update(:types, types)
|
28
|
+
end
|
29
|
+
|
30
|
+
parser.on('-o [file]') do |file|
|
31
|
+
destination(file)
|
32
|
+
end
|
33
|
+
|
34
|
+
parser.on('-O [file]') do |file|
|
35
|
+
destination(file)
|
36
|
+
update(:inverted, true)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def update(key, val)
|
42
|
+
options.update(key => val) do |_, oldval, _|
|
43
|
+
oldval
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def destination(file)
|
48
|
+
if file
|
49
|
+
file = File.expand_path(file)
|
50
|
+
|
51
|
+
if File.directory?(file)
|
52
|
+
file = File.join(file, 'library.png')
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
update(:destination, file || STDOUT)
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'brew_dg/queryable_dependencies'
|
2
|
+
require 'virtus'
|
3
|
+
|
4
|
+
module BrewDG
|
5
|
+
class Package
|
6
|
+
include Virtus.value_object
|
7
|
+
|
8
|
+
values do
|
9
|
+
attribute :name, String
|
10
|
+
attribute :dependencies, QueryableDependencies
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_s
|
14
|
+
name
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'delegate'
|
2
|
+
|
3
|
+
module BrewDG
|
4
|
+
class QueryableDependencies < Delegator
|
5
|
+
|
6
|
+
def initialize(dependency_manifests = [])
|
7
|
+
super
|
8
|
+
@dependency_manifests = dependency_manifests
|
9
|
+
end
|
10
|
+
|
11
|
+
def build
|
12
|
+
of_type(:build)
|
13
|
+
end
|
14
|
+
|
15
|
+
def required
|
16
|
+
of_type(:required)
|
17
|
+
end
|
18
|
+
|
19
|
+
def recommended
|
20
|
+
of_type(:recommended)
|
21
|
+
end
|
22
|
+
|
23
|
+
def optional
|
24
|
+
of_type(:optional)
|
25
|
+
end
|
26
|
+
|
27
|
+
def of_type(type)
|
28
|
+
__getobj__.find { |d| d.type == type } ||
|
29
|
+
DependencyManifest.new(type: type)
|
30
|
+
end
|
31
|
+
|
32
|
+
def __getobj__
|
33
|
+
@dependency_manifests
|
34
|
+
end
|
35
|
+
|
36
|
+
def __setobj__(new_dependency_manifests)
|
37
|
+
@dependency_manifests = new_dependency_manifests
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
data/lib/brew_dg.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'brew_dg'
|
2
|
+
|
3
|
+
module BrewDG
|
4
|
+
describe DependencyManifest do
|
5
|
+
|
6
|
+
it "can determine a package's build dependencies" do
|
7
|
+
manifests = DependencyManifest.for_package('postgis')
|
8
|
+
|
9
|
+
known_build_dependencies = %w(automake libtool gpp)
|
10
|
+
build_manifest = manifests.find { |manifest| manifest.type == :build }
|
11
|
+
build_dependencies = build_manifest.dependencies
|
12
|
+
|
13
|
+
expect(Set.new(known_build_dependencies)).
|
14
|
+
to eql(Set.new(build_dependencies))
|
15
|
+
end
|
16
|
+
|
17
|
+
it "can determine a package's required dependencies" do
|
18
|
+
manifests = DependencyManifest.for_package('postgis')
|
19
|
+
|
20
|
+
known_required_dependencies = %w(postgresql proj geos json-c gdal)
|
21
|
+
required_manifest = manifests.find do |manifest|
|
22
|
+
manifest.type == :required
|
23
|
+
end
|
24
|
+
required_dependencies = required_manifest.dependencies
|
25
|
+
|
26
|
+
expect(Set.new(known_required_dependencies)).
|
27
|
+
to eql(Set.new(required_dependencies))
|
28
|
+
end
|
29
|
+
|
30
|
+
it "can determine a package's recommended dependencies" do
|
31
|
+
manifests = DependencyManifest.for_package('sqlite')
|
32
|
+
|
33
|
+
known_recommended_dependencies = %w(readline)
|
34
|
+
recommended_manifest = manifests.find do |manifest|
|
35
|
+
manifest.type == :recommended
|
36
|
+
end
|
37
|
+
recommended_dependencies = recommended_manifest.dependencies
|
38
|
+
|
39
|
+
expect(Set.new(known_recommended_dependencies)).
|
40
|
+
to eql(Set.new(recommended_dependencies))
|
41
|
+
end
|
42
|
+
|
43
|
+
it "can determine a package's optional dependencies" do
|
44
|
+
manifests = DependencyManifest.for_package('nginx')
|
45
|
+
|
46
|
+
known_optional_dependencies = %w(passenger)
|
47
|
+
optional_manifest = manifests.find do |manifest|
|
48
|
+
manifest.type == :optional
|
49
|
+
end
|
50
|
+
optional_dependencies = optional_manifest.dependencies
|
51
|
+
|
52
|
+
expect(Set.new(known_optional_dependencies)).
|
53
|
+
to eql(Set.new(optional_dependencies))
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'brew_dg/dependency_manifest'
|
2
|
+
|
3
|
+
module BrewDG
|
4
|
+
describe DependencyManifest do
|
5
|
+
|
6
|
+
it 'infers its type from the beginning of the line' do
|
7
|
+
manifest = "Required: json-c"
|
8
|
+
dependency_manifest = DependencyManifest.from_output(manifest)
|
9
|
+
|
10
|
+
expect(dependency_manifest.type).to eql(:required)
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'knows that dependencies are comma-delimited after the type' do
|
14
|
+
manifest = "Required: json-c, proj, geos"
|
15
|
+
dependency_manifest = DependencyManifest.from_output(manifest)
|
16
|
+
|
17
|
+
expect(dependency_manifest.dependencies).
|
18
|
+
to eql(%w(json-c proj geos))
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'strips newlines from dependencies' do
|
22
|
+
manifest = "Required: json-c, proj, geos\n"
|
23
|
+
dependency_manifest = DependencyManifest.from_output(manifest)
|
24
|
+
|
25
|
+
expect(dependency_manifest.dependencies).
|
26
|
+
to eql(%w(json-c proj geos))
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'does not care if there are dependencies on the line' do
|
30
|
+
manifest = "Required:"
|
31
|
+
dependency_manifest = DependencyManifest.from_output(manifest)
|
32
|
+
|
33
|
+
expect(dependency_manifest.dependencies).to eql([])
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'can determine if a line is a dependency' do
|
37
|
+
invalid_manifests = [
|
38
|
+
": json-c, proj, geos",
|
39
|
+
"Something: one, two, three",
|
40
|
+
"Nothing",
|
41
|
+
"Ha:",
|
42
|
+
""
|
43
|
+
]
|
44
|
+
|
45
|
+
valid_manifests = [
|
46
|
+
"Build:",
|
47
|
+
"Recommended:",
|
48
|
+
"Required:",
|
49
|
+
"Optional:",
|
50
|
+
"Optional: passenger",
|
51
|
+
"Build: libtool, gcc",
|
52
|
+
"Required: geos, proj",
|
53
|
+
"Recommended: ossp-uuid"
|
54
|
+
]
|
55
|
+
|
56
|
+
invalid_manifests.map! { |manifest| DependencyManifest.from_output(manifest) }
|
57
|
+
valid_manifests.map! { |manifest| DependencyManifest.from_output(manifest) }
|
58
|
+
|
59
|
+
expect(invalid_manifests.any?).to be_false
|
60
|
+
expect(valid_manifests.all?).to be_true
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'brew_dg/graph'
|
2
|
+
require 'brew_dg/graph_installation'
|
3
|
+
|
4
|
+
module BrewDG
|
5
|
+
describe GraphInstallation do
|
6
|
+
|
7
|
+
it 'is empty for an empty graph' do
|
8
|
+
graph = Graph.new
|
9
|
+
installation = GraphInstallation.new(graph)
|
10
|
+
|
11
|
+
expect(installation.list).to eql([])
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'is the single vertex for a one-vertex graph' do
|
15
|
+
graph = Graph.new.tap do |g|
|
16
|
+
g.add_vertex! 'a'
|
17
|
+
end
|
18
|
+
|
19
|
+
installation = GraphInstallation.new(graph)
|
20
|
+
|
21
|
+
expect(installation.list).to eql(['a'])
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'preserves vertex order' do
|
25
|
+
graph = Graph.new.tap do |g|
|
26
|
+
g.add_vertex! 'a'
|
27
|
+
g.add_vertex! 'b'
|
28
|
+
end
|
29
|
+
|
30
|
+
installation = GraphInstallation.new(graph)
|
31
|
+
|
32
|
+
expect(installation.list).to eql(['a', 'b'])
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'moves from neighborhood to neighborhood from the bottom up' do
|
36
|
+
graph = Graph.new.tap do |g|
|
37
|
+
g.add_vertices! 'a', 'b', 'c', 'd', 'e'
|
38
|
+
g.add_edge! 'a', 'b'
|
39
|
+
g.add_edge! 'b', 'c'
|
40
|
+
g.add_edge! 'b', 'e'
|
41
|
+
g.add_edge! 'e', 'd'
|
42
|
+
end
|
43
|
+
|
44
|
+
installation = GraphInstallation.new(graph)
|
45
|
+
|
46
|
+
expect(installation.list).to eql(['c', 'd', 'e', 'b', 'a']);
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'does not duplicate vertices' do
|
50
|
+
graph = Graph.new.tap do |g|
|
51
|
+
g.add_vertices! 'a', 'b', 'c'
|
52
|
+
g.add_edge! 'a', 'b'
|
53
|
+
g.add_edge! 'c', 'b'
|
54
|
+
end
|
55
|
+
|
56
|
+
installation = GraphInstallation.new(graph)
|
57
|
+
|
58
|
+
expect(installation.list).to eql(['b', 'a', 'c'])
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'brew_dg/dependency_manifest'
|
2
|
+
require 'brew_dg/queryable_dependencies'
|
3
|
+
|
4
|
+
module BrewDG
|
5
|
+
|
6
|
+
describe QueryableDependencies do
|
7
|
+
|
8
|
+
it 'knows which manifest is the build manifest' do
|
9
|
+
build = DependencyManifest.new(type: :build)
|
10
|
+
required = DependencyManifest.new(type: :required)
|
11
|
+
|
12
|
+
queryable = QueryableDependencies.new([build, required])
|
13
|
+
|
14
|
+
expect(queryable.build).to eql(build)
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'knows which manifest is the required manifest' do
|
18
|
+
build = DependencyManifest.new(type: :build)
|
19
|
+
required = DependencyManifest.new(type: :required)
|
20
|
+
|
21
|
+
queryable = QueryableDependencies.new([build, required])
|
22
|
+
|
23
|
+
expect(queryable.required).to eql(required)
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'knows which manifest is the recommended manifest' do
|
27
|
+
optional = DependencyManifest.new(type: :optional)
|
28
|
+
recommended = DependencyManifest.new(type: :recommended)
|
29
|
+
|
30
|
+
queryable = QueryableDependencies.new([optional, recommended])
|
31
|
+
|
32
|
+
expect(queryable.recommended).to eql(recommended)
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'knows which manifest is the optional manifest' do
|
36
|
+
optional = DependencyManifest.new(type: :optional)
|
37
|
+
recommended = DependencyManifest.new(type: :recommended)
|
38
|
+
|
39
|
+
queryable = QueryableDependencies.new([optional, recommended])
|
40
|
+
|
41
|
+
expect(queryable.optional).to eql(optional)
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
metadata
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: brew_dg
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Brian Cobb
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-11-02 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: virtus
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ! '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ! '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: plexus
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ! '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: ruby-graphviz
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ! '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ! '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
description:
|
70
|
+
email: bcobb@uwalumni.com
|
71
|
+
executables:
|
72
|
+
- brew_dg
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files:
|
75
|
+
- README.md
|
76
|
+
files:
|
77
|
+
- lib/brew_dg/cli.rb
|
78
|
+
- lib/brew_dg/dependency_manifest.rb
|
79
|
+
- lib/brew_dg/graph.rb
|
80
|
+
- lib/brew_dg/graph_installation.rb
|
81
|
+
- lib/brew_dg/library.rb
|
82
|
+
- lib/brew_dg/option_parser.rb
|
83
|
+
- lib/brew_dg/package.rb
|
84
|
+
- lib/brew_dg/queryable_dependencies.rb
|
85
|
+
- lib/brew_dg.rb
|
86
|
+
- README.md
|
87
|
+
- LICENSE
|
88
|
+
- spec/integration/homebrew_output_spec.rb
|
89
|
+
- spec/unit/dependency_manifest_spec.rb
|
90
|
+
- spec/unit/graph_installation_spec.rb
|
91
|
+
- spec/unit/queryable_dependencies_spec.rb
|
92
|
+
- bin/brew_dg
|
93
|
+
homepage: https://github.com/bcobb/brew_dg
|
94
|
+
licenses:
|
95
|
+
- MIT
|
96
|
+
metadata: {}
|
97
|
+
post_install_message:
|
98
|
+
rdoc_options: []
|
99
|
+
require_paths:
|
100
|
+
- lib
|
101
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
102
|
+
requirements:
|
103
|
+
- - ! '>='
|
104
|
+
- !ruby/object:Gem::Version
|
105
|
+
version: '0'
|
106
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ! '>='
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
requirements: []
|
112
|
+
rubyforge_project:
|
113
|
+
rubygems_version: 2.0.7
|
114
|
+
signing_key:
|
115
|
+
specification_version: 4
|
116
|
+
summary: Work with homebrew dependencies as graphs
|
117
|
+
test_files:
|
118
|
+
- spec/integration/homebrew_output_spec.rb
|
119
|
+
- spec/unit/dependency_manifest_spec.rb
|
120
|
+
- spec/unit/graph_installation_spec.rb
|
121
|
+
- spec/unit/queryable_dependencies_spec.rb
|