brew_dg 0.0.1
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 +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/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
|