technologist 0.3.0 → 0.4.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 +4 -4
- data/lib/technologist/framework_detector.rb +8 -11
- data/lib/technologist/frameworks.yml +76 -25
- data/lib/technologist/git_repository.rb +29 -17
- data/lib/technologist/rules/directory_presence_rule.rb +1 -1
- data/lib/technologist/rules/file_content_rule.rb +4 -2
- data/lib/technologist/rules/file_presence_rule.rb +1 -1
- data/lib/technologist/rules/file_xml_content_rule.rb +13 -0
- data/lib/technologist/rules/gem_rule.rb +4 -4
- data/lib/technologist/rules/maven_plugin_rule.rb +12 -0
- data/lib/technologist/rules/rule.rb +6 -2
- data/lib/technologist/version.rb +1 -1
- data/lib/technologist/yaml_parser.rb +71 -0
- data/technologist.gemspec +1 -0
- metadata +19 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 28a3182ef7ef764fb494a4531ce1060151420944
|
4
|
+
data.tar.gz: c895b0a90fb072bc2b35545e335d88ed2549b422
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 39af217cc9fd4cd46e5d4681550603f14a7499b846df3d2f9174970b7835df4205f22da59502059a15d6f9149e4c6481ede1196cab595df979b1645bd16e273d
|
7
|
+
data.tar.gz: 641c27183e4f540c84ee6bc1c28ecad335bbe8d5817693542180ba865096692933cc9129ed9c6aea64ce280332382ea0fed71448649494908f4a68cda9a43d28
|
@@ -1,42 +1,39 @@
|
|
1
|
-
require '
|
1
|
+
require 'technologist/yaml_parser'
|
2
2
|
|
3
3
|
module Technologist
|
4
4
|
class FrameworkDetector
|
5
5
|
FRAMEWORK_RULES = File.expand_path('../frameworks.yml', __FILE__)
|
6
6
|
|
7
|
+
attr_reader :repository, :yaml_parser
|
8
|
+
|
7
9
|
def initialize(repository)
|
8
10
|
@repository = repository
|
11
|
+
@yaml_parser = YamlParser.new(FRAMEWORK_RULES)
|
9
12
|
end
|
10
13
|
|
11
14
|
def primary_frameworks
|
12
15
|
matched_frameworks.map do |technology|
|
13
16
|
# it's either the primary value defined in the yaml
|
14
17
|
# or the technology itself
|
15
|
-
rules[technology]['primary'] || technology
|
18
|
+
yaml_parser.rules[technology]['primary'] || technology
|
16
19
|
end.uniq
|
17
20
|
end
|
18
21
|
|
19
22
|
def secondary_frameworks
|
20
23
|
matched_frameworks.map do |technology|
|
21
24
|
# it's a secondary if a primary is defined in the yaml
|
22
|
-
rules[technology]['primary'] && technology
|
25
|
+
yaml_parser.rules[technology]['primary'] && technology
|
23
26
|
end.compact
|
24
27
|
end
|
25
28
|
|
26
29
|
private
|
27
30
|
|
28
|
-
attr_reader :repository
|
29
|
-
|
30
|
-
def rules
|
31
|
-
@rules ||= YAML.load_file(FRAMEWORK_RULES)
|
32
|
-
end
|
33
|
-
|
34
31
|
def matched_frameworks
|
35
32
|
@frameworks ||=
|
36
33
|
begin
|
37
|
-
rules.map do |technology, definition|
|
34
|
+
yaml_parser.rules.map do |technology, definition|
|
38
35
|
definition['rules'].map do |rule|
|
39
|
-
if rule.matches?(
|
36
|
+
if rule.matches?(repository)
|
40
37
|
technology
|
41
38
|
end
|
42
39
|
end
|
@@ -1,91 +1,142 @@
|
|
1
1
|
Rails:
|
2
2
|
rules:
|
3
|
-
-
|
4
|
-
-
|
5
|
-
|
3
|
+
- Gem
|
4
|
+
- Gem:
|
5
|
+
gem_name: 'jrails'
|
6
|
+
- FileContent:
|
7
|
+
file_name: 'boot.rb'
|
8
|
+
file_content_pattern: 'Rails.boot!'
|
6
9
|
|
7
10
|
Locomotive:
|
8
11
|
rules:
|
9
|
-
-
|
12
|
+
- Gem:
|
13
|
+
gem_name: 'locomotivecms_wagon'
|
10
14
|
primary: Rails
|
11
15
|
|
12
16
|
Magnolia:
|
13
17
|
rules:
|
14
|
-
-
|
18
|
+
- FileContent:
|
19
|
+
file_name: 'pom.xml'
|
20
|
+
file_content_pattern: '<magnoliaVersion>'
|
15
21
|
|
16
22
|
Sinatra:
|
17
23
|
rules:
|
18
|
-
-
|
19
|
-
|
24
|
+
- FileContent:
|
25
|
+
file_name: 'config.ru'
|
26
|
+
file_content_pattern: 'run Sinatra::Application'
|
27
|
+
- Gem
|
20
28
|
|
21
29
|
Dashing:
|
22
30
|
rules:
|
23
|
-
-
|
31
|
+
- Gem
|
24
32
|
primary: Sinatra
|
25
33
|
|
26
34
|
Middleman:
|
27
35
|
rules:
|
28
|
-
-
|
36
|
+
- Gem
|
29
37
|
|
30
38
|
Meteor:
|
31
39
|
rules:
|
32
|
-
-
|
40
|
+
- DirectoryPresence:
|
41
|
+
directory_name: '.meteor'
|
33
42
|
|
34
43
|
Spree:
|
35
44
|
rules:
|
36
|
-
-
|
37
|
-
-
|
45
|
+
- Gem
|
46
|
+
- FileContent:
|
47
|
+
file_name: 'boot.rb'
|
48
|
+
file_content_pattern: 'Spree.boot!'
|
38
49
|
primary: Rails
|
39
50
|
|
40
51
|
Wordpress:
|
41
52
|
rules:
|
42
|
-
-
|
53
|
+
- FilePresence:
|
54
|
+
file_name: 'wp-settings.php'
|
43
55
|
|
44
56
|
Volt:
|
45
57
|
rules:
|
46
|
-
-
|
58
|
+
- Gem
|
47
59
|
|
48
60
|
Ionic:
|
49
61
|
rules:
|
50
|
-
-
|
62
|
+
- FilePresence:
|
63
|
+
file_name: 'ionic.project'
|
51
64
|
|
52
65
|
Node:
|
53
66
|
rules:
|
54
|
-
-
|
67
|
+
- FileContent:
|
55
68
|
file_name: 'package.json'
|
56
|
-
file_content_pattern: '
|
69
|
+
file_content_pattern: '^\s*"node":'
|
57
70
|
|
58
71
|
Hoodie:
|
59
72
|
rules:
|
60
|
-
-
|
73
|
+
- FileContent:
|
61
74
|
file_name: 'package.json'
|
62
75
|
file_content_pattern: '"hoodie":\s*{'
|
63
76
|
primary: Node
|
64
77
|
|
65
78
|
PrestaShop:
|
66
79
|
rules:
|
67
|
-
-
|
80
|
+
- FileContent:
|
81
|
+
file_name: 'init.php'
|
82
|
+
file_content_pattern: 'PrestaShop'
|
68
83
|
|
69
84
|
Cordova:
|
70
85
|
rules:
|
71
|
-
-
|
86
|
+
- FileContent:
|
72
87
|
file_name: 'config.xml'
|
73
88
|
file_content_pattern: '\bxmlns:cdv="http://cordova.apache.org/ns/.+"'
|
74
89
|
|
75
90
|
iOS:
|
76
91
|
rules:
|
77
|
-
-
|
92
|
+
- FileContent:
|
78
93
|
file_name: 'project.pbxproj'
|
79
94
|
file_content_pattern: '\n\s*SDKROOT = iphoneos;\n'
|
80
95
|
|
81
96
|
Refinery CMS:
|
82
97
|
rules:
|
83
|
-
-
|
98
|
+
- Gem:
|
99
|
+
gem_name: 'refinerycms'
|
84
100
|
primary: Rails
|
85
101
|
|
86
102
|
Rack:
|
87
103
|
rules:
|
88
|
-
-
|
89
|
-
|
90
|
-
|
104
|
+
- Gem:
|
105
|
+
gem_name: 'rack'
|
106
|
+
- FileContent:
|
107
|
+
file_name: 'config.ru'
|
91
108
|
file_content_pattern: 'run Proc\.new { \|env\|'
|
109
|
+
|
110
|
+
Magento:
|
111
|
+
rules:
|
112
|
+
- FileContent:
|
113
|
+
file_name: 'composer.json'
|
114
|
+
file_content_pattern: '^\s*"magento":\s*{\s*$'
|
115
|
+
|
116
|
+
Vaadin:
|
117
|
+
rules:
|
118
|
+
- FileContent:
|
119
|
+
file_name: 'pom.xml'
|
120
|
+
file_content_pattern: '<version>\${vaadin.base.version}</version>'
|
121
|
+
|
122
|
+
Spring:
|
123
|
+
rules:
|
124
|
+
- MavenPlugin:
|
125
|
+
plugin_name: 'org.springframework'
|
126
|
+
- MavenPlugin:
|
127
|
+
plugin_name: '${spring.groupId}'
|
128
|
+
|
129
|
+
Felix:
|
130
|
+
rules:
|
131
|
+
- MavenPlugin:
|
132
|
+
plugin_name: 'org.apache.felix'
|
133
|
+
|
134
|
+
GWT:
|
135
|
+
rules:
|
136
|
+
- MavenPlugin:
|
137
|
+
plugin_name: 'com.google.gwt'
|
138
|
+
|
139
|
+
Jersey:
|
140
|
+
rules:
|
141
|
+
- MavenPlugin:
|
142
|
+
plugin_name: 'com.sun.jersey'
|
@@ -12,17 +12,6 @@ module Technologist
|
|
12
12
|
repository.head.target.tree
|
13
13
|
end
|
14
14
|
|
15
|
-
# Returns the file content.
|
16
|
-
#
|
17
|
-
# @param file_name [String] the file name
|
18
|
-
#
|
19
|
-
# @return [String] The content of the file or nil if the file cannot be found.
|
20
|
-
def file_content(file_name)
|
21
|
-
file = find_blob(file_name)
|
22
|
-
|
23
|
-
file.content if file
|
24
|
-
end
|
25
|
-
|
26
15
|
# Recursively searches for the blob identified by `blob_name`
|
27
16
|
# in all subdirectories in the repository. A blob is usually either
|
28
17
|
# a file or a directory.
|
@@ -31,18 +20,26 @@ module Technologist
|
|
31
20
|
# @param current_tree [Rugged::Tree] the git directory tree in which to look for the blob.
|
32
21
|
# Defaults to the root tree (see `#root_tree`).
|
33
22
|
#
|
23
|
+
# @yield [Rugged::Blob] Yields the found blob to an optional block.
|
24
|
+
# If the block returns `true` it means that the file is found and
|
25
|
+
# recursion is stopped. If the return value is `false`, the resursion continues.
|
26
|
+
#
|
34
27
|
# @return [Rugged::Blob] The blob blob or nil if it cannot be found.
|
35
|
-
def find_blob(blob_name, current_tree = root_tree)
|
28
|
+
def find_blob(blob_name, current_tree = root_tree, &block)
|
36
29
|
blob = current_tree[blob_name]
|
37
30
|
|
38
31
|
if blob
|
39
|
-
repository.lookup(blob[:oid])
|
40
|
-
|
41
|
-
|
42
|
-
blob = find_blob(blob_name, repository.lookup(sub_tree[:oid]))
|
43
|
-
break blob if blob
|
32
|
+
blob = repository.lookup(blob[:oid])
|
33
|
+
if !block_given? || yield(blob)
|
34
|
+
return blob
|
44
35
|
end
|
45
36
|
end
|
37
|
+
|
38
|
+
# recurse
|
39
|
+
current_tree.each_tree do |sub_tree|
|
40
|
+
blob = find_blob(blob_name, repository.lookup(sub_tree[:oid]), &block)
|
41
|
+
break blob if blob
|
42
|
+
end
|
46
43
|
end
|
47
44
|
|
48
45
|
# Looks for a directory and returns true when the directory
|
@@ -64,5 +61,20 @@ module Technologist
|
|
64
61
|
def file_exists?(file_name)
|
65
62
|
!!find_blob(file_name)
|
66
63
|
end
|
64
|
+
|
65
|
+
# Looks for a file and yields the file content to
|
66
|
+
# the block (if the file can be found). The block's
|
67
|
+
# return value is used to determine if we're done
|
68
|
+
# searching. If the return value is `false`, we
|
69
|
+
# keep searching for the file.
|
70
|
+
#
|
71
|
+
# @param file_name [String] the file name
|
72
|
+
#
|
73
|
+
# @return [Boolean] true if the file can be found.
|
74
|
+
def file_with_content_exists?(file_name)
|
75
|
+
!!find_blob(file_name) do |file|
|
76
|
+
yield file.content
|
77
|
+
end
|
78
|
+
end
|
67
79
|
end
|
68
80
|
end
|
@@ -3,7 +3,9 @@ require 'technologist/rules/rule'
|
|
3
3
|
class FileContentRule < Rule
|
4
4
|
attr_accessor :file_name, :file_content_pattern
|
5
5
|
|
6
|
-
def matches?(
|
7
|
-
!!
|
6
|
+
def matches?(repository)
|
7
|
+
!!repository.file_with_content_exists?(file_name) do |content|
|
8
|
+
content =~ /#{file_content_pattern}/
|
9
|
+
end
|
8
10
|
end
|
9
11
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'technologist/rules/rule'
|
2
|
+
require 'nokogiri'
|
3
|
+
|
4
|
+
class FileXmlContentRule < Rule
|
5
|
+
attr_accessor :file_name, :css_selector
|
6
|
+
|
7
|
+
def matches?(repository)
|
8
|
+
!!repository.file_with_content_exists?(file_name) do |content|
|
9
|
+
xml = Nokogiri::XML(content)
|
10
|
+
xml.css(css_selector).any?
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -3,11 +3,11 @@ require 'technologist/rules/file_content_rule'
|
|
3
3
|
class GemRule < FileContentRule
|
4
4
|
attr_accessor :gem_name
|
5
5
|
|
6
|
-
def
|
6
|
+
def initialize(framework, attributes = {})
|
7
|
+
super
|
8
|
+
|
7
9
|
self.file_name = 'Gemfile'
|
8
|
-
self.gem_name ||=
|
10
|
+
self.gem_name ||= framework.downcase
|
9
11
|
self.file_content_pattern = /^\s*gem ["']#{gem_name}["']/
|
10
|
-
|
11
|
-
super
|
12
12
|
end
|
13
13
|
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'technologist/rules/file_xml_content_rule'
|
2
|
+
|
3
|
+
class MavenPluginRule < FileXmlContentRule
|
4
|
+
attr_accessor :plugin_name
|
5
|
+
|
6
|
+
def initialize(framework, attributes = {})
|
7
|
+
super
|
8
|
+
|
9
|
+
self.file_name = 'pom.xml'
|
10
|
+
self.css_selector = "dependencies > dependency > groupId[text() = '#{plugin_name}']"
|
11
|
+
end
|
12
|
+
end
|
@@ -1,9 +1,13 @@
|
|
1
1
|
class Rule
|
2
|
-
|
2
|
+
attr_accessor :framework
|
3
|
+
|
4
|
+
def initialize(framework, attributes = {})
|
5
|
+
self.framework = framework
|
6
|
+
|
3
7
|
attributes.each { |name, value| self.send(:"#{name}=", value) }
|
4
8
|
end
|
5
9
|
|
6
|
-
def matches?(
|
10
|
+
def matches?(repository)
|
7
11
|
false
|
8
12
|
end
|
9
13
|
end
|
data/lib/technologist/version.rb
CHANGED
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module Technologist
|
4
|
+
class YamlParser
|
5
|
+
attr_reader :file_name
|
6
|
+
|
7
|
+
def initialize(file_name)
|
8
|
+
@file_name = file_name
|
9
|
+
end
|
10
|
+
|
11
|
+
def rules
|
12
|
+
@rules ||=
|
13
|
+
begin
|
14
|
+
parsed_rules = from_file.map do |technology, definition|
|
15
|
+
definition['rules'].map! do |rule|
|
16
|
+
instancify(technology, rule)
|
17
|
+
end
|
18
|
+
|
19
|
+
[technology, definition]
|
20
|
+
end
|
21
|
+
|
22
|
+
Hash[parsed_rules]
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def from_file
|
29
|
+
YAML.load_file(file_name)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Create a class instance for a rule entry
|
33
|
+
def instancify(technology, rule)
|
34
|
+
class_name, attributes = send("parse_rule_of_type_#{rule.class.name.downcase}", rule)
|
35
|
+
|
36
|
+
Rule.const_get("#{class_name}Rule").new(technology, attributes)
|
37
|
+
end
|
38
|
+
|
39
|
+
# Parses a yaml rule where the rule entry is a string,
|
40
|
+
# meaning that only the rule class name is given.
|
41
|
+
# Sample yaml structure:
|
42
|
+
# ```
|
43
|
+
# Rails:
|
44
|
+
# rules:
|
45
|
+
# - Gem
|
46
|
+
# ```
|
47
|
+
def parse_rule_of_type_hash(rule)
|
48
|
+
class_name = rule.keys.first
|
49
|
+
rule.delete(class_name)
|
50
|
+
attributes = rule
|
51
|
+
|
52
|
+
[class_name, attributes]
|
53
|
+
end
|
54
|
+
|
55
|
+
# Parses a yaml rule where the rule entry is a hash,
|
56
|
+
# meaning that the rule class also has attributes to be assigned.
|
57
|
+
# Sample yaml structure:
|
58
|
+
# ```
|
59
|
+
# Rails:
|
60
|
+
# rules:
|
61
|
+
# - Gem:
|
62
|
+
# gem_name: 'jrails'
|
63
|
+
# ```
|
64
|
+
def parse_rule_of_type_string(rule)
|
65
|
+
class_name = rule
|
66
|
+
attributes = {}
|
67
|
+
|
68
|
+
[class_name, attributes]
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
data/technologist.gemspec
CHANGED
@@ -20,6 +20,7 @@ Gem::Specification.new do |spec|
|
|
20
20
|
spec.require_paths = ["lib"]
|
21
21
|
|
22
22
|
spec.add_runtime_dependency "rugged", "~> 0.23.3"
|
23
|
+
spec.add_runtime_dependency "nokogiri", "~> 1.6"
|
23
24
|
|
24
25
|
spec.add_development_dependency "bundler", "~> 1.7"
|
25
26
|
spec.add_development_dependency "rake", "~> 10.0"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: technologist
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alexis Reigel
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-11-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rugged
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - ~>
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 0.23.3
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: nokogiri
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.6'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.6'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: bundler
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -108,9 +122,12 @@ files:
|
|
108
122
|
- lib/technologist/rules/directory_presence_rule.rb
|
109
123
|
- lib/technologist/rules/file_content_rule.rb
|
110
124
|
- lib/technologist/rules/file_presence_rule.rb
|
125
|
+
- lib/technologist/rules/file_xml_content_rule.rb
|
111
126
|
- lib/technologist/rules/gem_rule.rb
|
127
|
+
- lib/technologist/rules/maven_plugin_rule.rb
|
112
128
|
- lib/technologist/rules/rule.rb
|
113
129
|
- lib/technologist/version.rb
|
130
|
+
- lib/technologist/yaml_parser.rb
|
114
131
|
- technologist.gemspec
|
115
132
|
homepage: https://github.com/koffeinfrei/technologist
|
116
133
|
licenses:
|