cpp_dependency_graph 0.4.0 → 0.4.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 +4 -4
- data/bin/console +0 -0
- data/cpp_dependency_graph.gemspec +1 -1
- data/exe/cpp_dependency_graph +0 -0
- data/lib/cpp_dependency_graph/bidirectional_hash.rb +1 -0
- data/lib/cpp_dependency_graph/component_dependency_graph.rb +1 -0
- data/lib/cpp_dependency_graph/dir_tree.rb +4 -1
- data/lib/cpp_dependency_graph/directory_parser.rb +13 -0
- data/lib/cpp_dependency_graph/file_dependency_graph.rb +1 -0
- data/lib/cpp_dependency_graph/graph_to_dot_visualiser.rb +10 -10
- data/lib/cpp_dependency_graph/include_component_dependency_graph.rb +1 -3
- data/lib/cpp_dependency_graph/include_file_dependency_graph.rb +2 -9
- data/lib/cpp_dependency_graph/include_to_component_resolver.rb +2 -0
- data/lib/cpp_dependency_graph/project.rb +25 -4
- data/lib/cpp_dependency_graph/source_component.rb +3 -2
- data/lib/cpp_dependency_graph/source_file.rb +1 -0
- data/lib/cpp_dependency_graph/version.rb +1 -1
- metadata +8 -7
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: bab309d43e6015c06bf3836941534efe150bd78759d81f0e4ff538b4f33a054f
|
|
4
|
+
data.tar.gz: 46b1aadfe5915a147b9c89090c4cc7d047cdad269d9ec70a11c12567b56e8eb0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4ef9120a1d26f432cfc26e9906412391fa03aadbd34ebc5a110e3dfc674e22a6258f9f453044428da590d8ea51c873307345f09116b847c384ecc3f5787dddd0
|
|
7
|
+
data.tar.gz: 99995d31dce112db4b38fd9a4e71c4cb4d012829d727a260a396d0dd1def7008af60d0fcd3febe717c224582dd499c36c4ccfec5574c7166629daa72564dd8b2
|
data/bin/console
CHANGED
|
File without changes
|
|
@@ -29,8 +29,8 @@ Gem::Specification.new do |s|
|
|
|
29
29
|
s.rubygems_version = '3.1.2'
|
|
30
30
|
|
|
31
31
|
s.add_runtime_dependency 'docopt', '~> 0.6'
|
|
32
|
-
s.add_runtime_dependency 'ruby-graphviz', '~> 1.2'
|
|
33
32
|
s.add_runtime_dependency 'json', '~> 2.3.0'
|
|
33
|
+
s.add_runtime_dependency 'ruby-graphviz', '~> 1.2'
|
|
34
34
|
|
|
35
35
|
s.add_development_dependency 'bundler', '~> 2.1'
|
|
36
36
|
s.add_development_dependency 'debase', '~> 0.2'
|
data/exe/cpp_dependency_graph
CHANGED
|
File without changes
|
|
@@ -11,7 +11,7 @@ class DirTree
|
|
|
11
11
|
attr_reader :tree
|
|
12
12
|
|
|
13
13
|
def initialize(path)
|
|
14
|
-
@tree
|
|
14
|
+
@tree = File.directory?(path) ? parse_dirs(path) : {}
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
private
|
|
@@ -22,9 +22,12 @@ class DirTree
|
|
|
22
22
|
# TODO: Use Dir.map.compact|filter instead here
|
|
23
23
|
Dir.foreach(path) do |entry|
|
|
24
24
|
next if ['..', '.'].include?(entry)
|
|
25
|
+
|
|
25
26
|
full_path = File.join(path, entry)
|
|
26
27
|
next unless File.directory?(full_path)
|
|
28
|
+
|
|
27
29
|
next unless source_files_present?(full_path)
|
|
30
|
+
|
|
28
31
|
data[:children] << parse_dirs(full_path, entry)
|
|
29
32
|
end
|
|
30
33
|
data
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Utility methods for parsing directories
|
|
4
|
+
module DirectoryParser
|
|
5
|
+
def fetch_all_dirs(root_dir)
|
|
6
|
+
Find.find(root_dir).select { |e| File.directory?(e) && e != root_dir }
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def glob_files(path, extensions)
|
|
10
|
+
path = File.join(path, File::SEPARATOR, '**', File::SEPARATOR, '*' + extensions)
|
|
11
|
+
Dir.glob(path).select { |entry| File.file?(entry) }.compact
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -6,9 +6,9 @@ require 'ruby-graphviz'
|
|
|
6
6
|
class GraphToDotVisualiser
|
|
7
7
|
def generate(deps, file)
|
|
8
8
|
@g = GraphViz.new('dependency_graph')
|
|
9
|
-
|
|
10
|
-
connect_nodes(deps
|
|
11
|
-
@g.output(:
|
|
9
|
+
create_nodes(deps)
|
|
10
|
+
connect_nodes(deps)
|
|
11
|
+
@g.output(dot: file)
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
private
|
|
@@ -17,20 +17,20 @@ class GraphToDotVisualiser
|
|
|
17
17
|
node_names = deps.flat_map do |_, links|
|
|
18
18
|
links.map { |link| [link.source, link.target] }.flatten
|
|
19
19
|
end.uniq
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
node_names.each do |name|
|
|
21
|
+
add_node(name)
|
|
22
|
+
end
|
|
22
23
|
end
|
|
23
24
|
|
|
24
|
-
def
|
|
25
|
-
|
|
26
|
-
node
|
|
25
|
+
def add_node(name)
|
|
26
|
+
@g.add_node(name, shape: 'box3d')
|
|
27
27
|
end
|
|
28
28
|
|
|
29
|
-
def connect_nodes(deps
|
|
29
|
+
def connect_nodes(deps)
|
|
30
30
|
deps.each do |source, links|
|
|
31
31
|
links.each do |link|
|
|
32
32
|
if link.cyclic?
|
|
33
|
-
@g.add_edges(source, link.target, :
|
|
33
|
+
@g.add_edges(source, link.target, color: 'red')
|
|
34
34
|
else
|
|
35
35
|
@g.add_edges(source, link.target)
|
|
36
36
|
end
|
|
@@ -11,9 +11,7 @@ class IncludeComponentDependencyGraph
|
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
def all_links
|
|
14
|
-
|
|
15
|
-
all_source_files = components.values.flat_map(&:source_files)
|
|
16
|
-
all_source_files.map do |file|
|
|
14
|
+
@project.source_files.map do |file|
|
|
17
15
|
links = file.includes.map { |inc| Link.new(file.basename, inc, false) }
|
|
18
16
|
[file.basename, links]
|
|
19
17
|
end.to_h
|
|
@@ -10,22 +10,15 @@ class IncludeFileDependencyGraph
|
|
|
10
10
|
@project = project
|
|
11
11
|
end
|
|
12
12
|
|
|
13
|
-
def all_links
|
|
14
|
-
# TODO: Implement
|
|
15
|
-
{}
|
|
16
|
-
end
|
|
17
|
-
|
|
18
13
|
def all_cyclic_links
|
|
19
14
|
# TODO: Implement
|
|
20
15
|
end
|
|
21
16
|
|
|
22
17
|
def links(file_name)
|
|
23
|
-
|
|
24
|
-
all_source_files = components.values.flat_map(&:source_files)
|
|
25
|
-
files = all_source_files.select do |file|
|
|
18
|
+
files = @project.source_files.select do |_, file|
|
|
26
19
|
file.includes.include?(file_name)
|
|
27
20
|
end
|
|
28
|
-
files.map do |file|
|
|
21
|
+
files.map do |_, file|
|
|
29
22
|
links = [Link.new(file.basename, file_name, false)]
|
|
30
23
|
[file.basename, links]
|
|
31
24
|
end.to_h
|
|
@@ -19,6 +19,7 @@ class IncludeToComponentResolver
|
|
|
19
19
|
|
|
20
20
|
def component_for_include(include)
|
|
21
21
|
return '' unless source_files.key?(include)
|
|
22
|
+
|
|
22
23
|
@component_include_map_cache[include] = component_for_include_private(include) unless @component_include_map_cache.key?(include)
|
|
23
24
|
@component_include_map_cache[include]
|
|
24
25
|
end
|
|
@@ -35,6 +36,7 @@ class IncludeToComponentResolver
|
|
|
35
36
|
header_file = source_files[include]
|
|
36
37
|
implementation_files = implementation_files(header_file)
|
|
37
38
|
return header_file.parent_component if implementation_files.empty?
|
|
39
|
+
|
|
38
40
|
implementation_files[0].parent_component
|
|
39
41
|
end
|
|
40
42
|
|
|
@@ -2,11 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
require 'find'
|
|
4
4
|
|
|
5
|
+
require_relative 'directory_parser'
|
|
5
6
|
require_relative 'include_to_component_resolver'
|
|
6
7
|
require_relative 'source_component'
|
|
7
8
|
|
|
8
9
|
# Parses all components of a project
|
|
9
10
|
class Project
|
|
11
|
+
include DirectoryParser
|
|
12
|
+
|
|
10
13
|
def initialize(path)
|
|
11
14
|
@path = path
|
|
12
15
|
@include_resolver = IncludeToComponentResolver.new(source_components)
|
|
@@ -18,9 +21,18 @@ class Project
|
|
|
18
21
|
|
|
19
22
|
def source_component(name)
|
|
20
23
|
return SourceComponent.new('NULL') unless source_components.key?(name)
|
|
24
|
+
|
|
21
25
|
source_components[name]
|
|
22
26
|
end
|
|
23
27
|
|
|
28
|
+
def project_component
|
|
29
|
+
@project_component ||= build_project_component
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def source_files
|
|
33
|
+
@source_files ||= build_source_files
|
|
34
|
+
end
|
|
35
|
+
|
|
24
36
|
def dependencies(component)
|
|
25
37
|
# TODO: This is repeating the same work twice! component_for_include is called when calling external_includes
|
|
26
38
|
external_includes(component).map { |include| @include_resolver.component_for_include(include) }.reject(&:empty?).uniq
|
|
@@ -32,6 +44,19 @@ class Project
|
|
|
32
44
|
|
|
33
45
|
private
|
|
34
46
|
|
|
47
|
+
def build_source_files
|
|
48
|
+
# TODO: Breaking Demeter's law here
|
|
49
|
+
files = project_component.values.flat_map(&:source_files)
|
|
50
|
+
files.map do |file|
|
|
51
|
+
[file.path, file]
|
|
52
|
+
end.to_h
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def build_project_component
|
|
56
|
+
c = SourceComponent.new(@path)
|
|
57
|
+
{ c.name => c }
|
|
58
|
+
end
|
|
59
|
+
|
|
35
60
|
def build_source_components
|
|
36
61
|
# TODO: Dealing with source components with same dir name?
|
|
37
62
|
dirs = fetch_all_dirs(@path)
|
|
@@ -41,8 +66,4 @@ class Project
|
|
|
41
66
|
end.to_h
|
|
42
67
|
components.delete_if { |_, v| v.source_files.size.zero? }
|
|
43
68
|
end
|
|
44
|
-
|
|
45
|
-
def fetch_all_dirs(source_dir)
|
|
46
|
-
Find.find(source_dir).select { |e| File.directory?(e) }
|
|
47
|
-
end
|
|
48
69
|
end
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative 'config'
|
|
4
|
+
require_relative 'directory_parser'
|
|
4
5
|
require_relative 'source_file'
|
|
5
6
|
|
|
6
7
|
# Abstracts a source directory containing source files
|
|
7
8
|
class SourceComponent
|
|
8
9
|
include Config
|
|
10
|
+
include DirectoryParser
|
|
9
11
|
|
|
10
12
|
attr_reader :path
|
|
11
13
|
|
|
@@ -32,7 +34,6 @@ class SourceComponent
|
|
|
32
34
|
private
|
|
33
35
|
|
|
34
36
|
def parse_source_files(extensions)
|
|
35
|
-
|
|
36
|
-
Dir.glob(path).map { |e| SourceFile.new(e) if File.file?(e) }.compact
|
|
37
|
+
glob_files(@path, extensions).map { |e| SourceFile.new(e) }.compact
|
|
37
38
|
end
|
|
38
39
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: cpp_dependency_graph
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.4.
|
|
4
|
+
version: 0.4.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Shreyas Balakrishna
|
|
@@ -25,33 +25,33 @@ dependencies:
|
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
26
|
version: '0.6'
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
28
|
-
name:
|
|
28
|
+
name: json
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
30
30
|
requirements:
|
|
31
31
|
- - "~>"
|
|
32
32
|
- !ruby/object:Gem::Version
|
|
33
|
-
version:
|
|
33
|
+
version: 2.3.0
|
|
34
34
|
type: :runtime
|
|
35
35
|
prerelease: false
|
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
37
|
requirements:
|
|
38
38
|
- - "~>"
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
|
-
version:
|
|
40
|
+
version: 2.3.0
|
|
41
41
|
- !ruby/object:Gem::Dependency
|
|
42
|
-
name:
|
|
42
|
+
name: ruby-graphviz
|
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
|
44
44
|
requirements:
|
|
45
45
|
- - "~>"
|
|
46
46
|
- !ruby/object:Gem::Version
|
|
47
|
-
version: 2
|
|
47
|
+
version: '1.2'
|
|
48
48
|
type: :runtime
|
|
49
49
|
prerelease: false
|
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
|
51
51
|
requirements:
|
|
52
52
|
- - "~>"
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
|
-
version: 2
|
|
54
|
+
version: '1.2'
|
|
55
55
|
- !ruby/object:Gem::Dependency
|
|
56
56
|
name: bundler
|
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -231,6 +231,7 @@ files:
|
|
|
231
231
|
- lib/cpp_dependency_graph/cycle_detector.rb
|
|
232
232
|
- lib/cpp_dependency_graph/cyclic_link.rb
|
|
233
233
|
- lib/cpp_dependency_graph/dir_tree.rb
|
|
234
|
+
- lib/cpp_dependency_graph/directory_parser.rb
|
|
234
235
|
- lib/cpp_dependency_graph/file_dependency_graph.rb
|
|
235
236
|
- lib/cpp_dependency_graph/graph_to_dot_visualiser.rb
|
|
236
237
|
- lib/cpp_dependency_graph/graph_to_graphml_visualiser.rb
|