reviser 0.0.1.1.pre.beta
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 +7 -0
- data/bin/reviser +6 -0
- data/config.yml +80 -0
- data/ext/html_validator.rb +21 -0
- data/ext/valgrind.rb +24 -0
- data/labels.yml +8 -0
- data/lang/C.yml +22 -0
- data/lang/HTML.yml +49 -0
- data/lang/Java.yml +15 -0
- data/lang/Ruby.yml +26 -0
- data/lib/component.rb +53 -0
- data/lib/components/archiver.rb +118 -0
- data/lib/components/checker.rb +78 -0
- data/lib/components/extractors.rb +139 -0
- data/lib/components/generator.rb +47 -0
- data/lib/components/generators.rb +130 -0
- data/lib/components/organiser.rb +181 -0
- data/lib/config.rb +48 -0
- data/lib/exec.rb +136 -0
- data/lib/helpers/code_analysis.rb +64 -0
- data/lib/helpers/compilation.rb +40 -0
- data/lib/helpers/criteria.rb +186 -0
- data/lib/helpers/execution.rb +83 -0
- data/lib/helpers/git.rb +37 -0
- data/lib/helpers/project.rb +39 -0
- data/lib/helpers/system.rb +56 -0
- data/lib/loggers/logger.rb +41 -0
- data/lib/loggers/modes.rb +74 -0
- data/lib/project.rb +155 -0
- data/lib/reviser.rb +68 -0
- data/res/css/component.css +115 -0
- data/res/css/normalize.css +1 -0
- data/res/js/jquery.stickyheader.js +149 -0
- data/type/CProject.yml +32 -0
- data/type/HelloWorldRuby.yml +2 -0
- data/type/HtmlASRALL.yml +1 -0
- data/type/Labyrinthe.yml +42 -0
- metadata +83 -0
@@ -0,0 +1,47 @@
|
|
1
|
+
require_relative 'generators'
|
2
|
+
|
3
|
+
|
4
|
+
module Components
|
5
|
+
|
6
|
+
# Generator is used to create a file result after the analysis.
|
7
|
+
# Currently, Generator supports HTML, XLS and CSV format.
|
8
|
+
#
|
9
|
+
# @author Renan Strauss
|
10
|
+
# @author Yann Prono
|
11
|
+
#
|
12
|
+
class Generator < Component
|
13
|
+
|
14
|
+
# Include all supported formats
|
15
|
+
include Generators
|
16
|
+
|
17
|
+
def initialize(data)
|
18
|
+
super data
|
19
|
+
end
|
20
|
+
|
21
|
+
# Run the generation of results file in all asked formats by user.
|
22
|
+
def run
|
23
|
+
begin
|
24
|
+
if Cfg[:out_format].respond_to? 'each'
|
25
|
+
Cfg[:out_format].each { |f| send f.to_sym }
|
26
|
+
else
|
27
|
+
send Cfg[:out_format].to_sym
|
28
|
+
end
|
29
|
+
rescue Object => e
|
30
|
+
@logger.h1 Logger::FATAL, "Wrong format : #{e.to_s}"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Get all criterias of marking
|
35
|
+
# used to display informations in documents.
|
36
|
+
# @return [Array] Array with all criterias.
|
37
|
+
def criterias
|
38
|
+
@data.values.first.keys.unshift.map! { |cri| Generator.titleize(cri.to_s) }
|
39
|
+
end
|
40
|
+
|
41
|
+
# Quite handy
|
42
|
+
def self.titleize(str)
|
43
|
+
str.split(/_/).join(' ').capitalize
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
|
2
|
+
# Module containing all methods for writing results.
|
3
|
+
#
|
4
|
+
# Convention over configuration !
|
5
|
+
#
|
6
|
+
# To add a new format, you need maybe to install a gem.
|
7
|
+
# Find a gem which supports a specified format on rubygems.org.
|
8
|
+
# Add the line "gem <gem>" in the Gemfile and execute "bundle install"
|
9
|
+
#
|
10
|
+
# Now, you can write the method corresponding to the format.
|
11
|
+
# The name of the method corresponds to the format.
|
12
|
+
# For example, if you want to generate a word file (.doc), the name of the method will be: "doc"
|
13
|
+
# Don't forget to require the gem: "require <gem>" at the beginning of the method !
|
14
|
+
# the header of method looks like the following block:
|
15
|
+
#
|
16
|
+
# def <format> (ext = '<format>')
|
17
|
+
# require <gem>
|
18
|
+
# ...
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
# To write results, you have to go through in the data instance variable.
|
22
|
+
# data is a [Hash]:
|
23
|
+
# - key: The person's name.
|
24
|
+
# - value: Results of analysis
|
25
|
+
#
|
26
|
+
# Each value of data is also a [Hash]:
|
27
|
+
# - key: the name of criterion checked.
|
28
|
+
# - value: The result of criterion.
|
29
|
+
#
|
30
|
+
#
|
31
|
+
# @author Renan Strauss
|
32
|
+
# @author Yann Prono
|
33
|
+
#
|
34
|
+
module Components
|
35
|
+
module Generators
|
36
|
+
|
37
|
+
# Generates the CSV file
|
38
|
+
def csv(ext = '.csv')
|
39
|
+
require 'csv'
|
40
|
+
CSV.open(out(ext), 'wb') do |f|
|
41
|
+
# Criterias as columns
|
42
|
+
f << (criterias).unshift('projet')
|
43
|
+
|
44
|
+
# Values for each project as rows
|
45
|
+
@data.keys.each do |proj|
|
46
|
+
f << @data[proj].values.unshift(proj)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Generates a Excel file
|
52
|
+
def xls(ext = '.xls')
|
53
|
+
require 'spreadsheet'
|
54
|
+
Spreadsheet.client_encoding = 'UTF-8'
|
55
|
+
book = Spreadsheet::Workbook.new
|
56
|
+
sheet = book.create_worksheet :name => 'Results'
|
57
|
+
|
58
|
+
# header
|
59
|
+
format = Spreadsheet::Format.new :weight => :bold, :size => 14 ,
|
60
|
+
:horizontal_align => :center
|
61
|
+
|
62
|
+
(criterias.unshift('Projets')).each_with_index do |crit, i|
|
63
|
+
sheet[0,i] = crit
|
64
|
+
sheet.column(i).width = (crit.size * format.font.size/10) + 5
|
65
|
+
end
|
66
|
+
sheet.row(0).default_format = format
|
67
|
+
sheet.row(0).height = 18
|
68
|
+
|
69
|
+
# Values for each project as rows
|
70
|
+
@data.keys.each_with_index do |proj, i|
|
71
|
+
sheet.insert_row(i+1,@data[proj].values.unshift(proj))
|
72
|
+
end
|
73
|
+
|
74
|
+
book.write out(ext)
|
75
|
+
end
|
76
|
+
|
77
|
+
# Generates an HTML file
|
78
|
+
def html(ext = '.html')
|
79
|
+
out = '<!DOCTYPE html><html><head>'
|
80
|
+
out += '<meta charset= "UTF-8">'
|
81
|
+
out += "<link rel=\"stylesheet\" href=\"#{Cfg[:res_dir]}/css/component.css\" />"
|
82
|
+
out += "<link rel=\"stylesheet\" href=\"#{Cfg[:res_dir]}/css/normalize.css\" />"
|
83
|
+
out += '<script src="res/js/component.css"></script>'
|
84
|
+
out += '<title>Results</title>'
|
85
|
+
out += "</head>\n<body><table><thead>"
|
86
|
+
out += ' <tr>'
|
87
|
+
|
88
|
+
criterias.unshift('Projet').each { |crit| out += "<th>#{crit}</th>" }
|
89
|
+
|
90
|
+
out += '</tr></thead><tbody>'
|
91
|
+
# Values for each project as rows
|
92
|
+
@data.keys.each do |proj|
|
93
|
+
out += "<tr><th>#{proj}</th>"
|
94
|
+
@data[proj].each do |k, v|
|
95
|
+
if k.to_s[/(compilation|execution)/]
|
96
|
+
out += '<td class="console">'
|
97
|
+
else
|
98
|
+
out += '<td>'
|
99
|
+
end
|
100
|
+
|
101
|
+
# If file, generate a link, else do nothing !
|
102
|
+
out += file?(v) && "<pre><a href=\"#{v.gsub(' ','%20')}\" target=\"_blank\">#{v}</a></pre></td>" ||"<pre>#{v}</pre></td>"
|
103
|
+
|
104
|
+
end
|
105
|
+
out += '</tr>'
|
106
|
+
end
|
107
|
+
|
108
|
+
out += '</tbody></table>'
|
109
|
+
|
110
|
+
out += '<script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>'
|
111
|
+
out += '<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery-throttle-debounce/1.1/jquery.ba-throttle-debounce.min.js"></script>'
|
112
|
+
#out += "<script src=\"#{Cfg[:res_dir]}/js/jquery.stickyheader.js\"></script>"
|
113
|
+
|
114
|
+
out += '</body></html>'
|
115
|
+
|
116
|
+
File.open(out(ext), 'w') { |f| f.write(out) }
|
117
|
+
end
|
118
|
+
|
119
|
+
private
|
120
|
+
|
121
|
+
def out(ext)
|
122
|
+
Cfg[:out] + ext
|
123
|
+
end
|
124
|
+
|
125
|
+
def file? path
|
126
|
+
File.exist? path.to_s
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
130
|
+
end
|
@@ -0,0 +1,181 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require_relative '../helpers/git'
|
3
|
+
require_relative '../project'
|
4
|
+
|
5
|
+
|
6
|
+
module Components
|
7
|
+
|
8
|
+
# Class which organizes all directories to simplify projects' analysis.
|
9
|
+
# Organiser renames projects folders and organises the whole of projects
|
10
|
+
# in order to have a structured folder (files at the root of folder)
|
11
|
+
# During this step, a git repository will be created, with an initial commit.
|
12
|
+
#
|
13
|
+
# @author Yann Prono
|
14
|
+
# @author Renan Strauss
|
15
|
+
#
|
16
|
+
class Organiser < Component
|
17
|
+
|
18
|
+
# Include all tools
|
19
|
+
include Helpers::Git
|
20
|
+
include Project
|
21
|
+
|
22
|
+
# All entries to ignore during sort and organization
|
23
|
+
$rejected_entries = ['.', '..', '__MACOSX']
|
24
|
+
|
25
|
+
# initialize tool.
|
26
|
+
# Organiser has to :
|
27
|
+
# - get all students
|
28
|
+
# - get all groups (classes)
|
29
|
+
# - get all teams (binoms)
|
30
|
+
# - get all unknown soldiers ...
|
31
|
+
def initialize(data)
|
32
|
+
raise ArgumentError if data == nil || !data.respond_to?('each')
|
33
|
+
|
34
|
+
super data
|
35
|
+
|
36
|
+
@directory = Cfg[:dest]
|
37
|
+
@path = @directory
|
38
|
+
@git = nil
|
39
|
+
@students = []
|
40
|
+
@binoms = []
|
41
|
+
@groups = []
|
42
|
+
@unknown = []
|
43
|
+
|
44
|
+
# How many patterns are in the pseudo-regex?
|
45
|
+
@count_patterns = {}
|
46
|
+
end
|
47
|
+
|
48
|
+
# Rename directories more clearly.
|
49
|
+
# @param entry [String] path of the entry to rename.
|
50
|
+
def rename(entry)
|
51
|
+
name = format entry
|
52
|
+
if name != nil
|
53
|
+
if name != entry
|
54
|
+
new_path = File.join(@directory, name)
|
55
|
+
FileUtils.mkdir_p new_path.split(File.basename(new_path))[0]
|
56
|
+
FileUtils.mv(File.join(@directory, entry), new_path, :force => true)
|
57
|
+
|
58
|
+
@logger.h2 Logger::INFO, "renaming #{File.basename(entry)} to #{File.basename(name)}"
|
59
|
+
else
|
60
|
+
@logger.h2 Logger::INFO, "#{entry} has not been renamed}, already formatted"
|
61
|
+
end
|
62
|
+
else
|
63
|
+
@logger.h2 Logger::ERROR, "Can't rename #{File.basename(entry)} - Datas not found in name"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# Method which moves project's directories in order to
|
68
|
+
# have the same hierarchy for all project.
|
69
|
+
# @param entry [String] path of the entry to structure.
|
70
|
+
def structure(entry)
|
71
|
+
chdir entry
|
72
|
+
@logger.h2 Logger::INFO, "#{entry} => #{@path}"
|
73
|
+
level = 0
|
74
|
+
@logger.h2 Logger::INFO, "Files in #{@path}"
|
75
|
+
@logger.h3 Logger::INFO, "#{all}"
|
76
|
+
|
77
|
+
@logger.h2 Logger::INFO, "Dirs in #{@path}"
|
78
|
+
@logger.h3 Logger::INFO, "#{directories}"
|
79
|
+
# directory to delete if the project directory is not structured
|
80
|
+
rm = directories.first
|
81
|
+
|
82
|
+
# Loop to find the core of project
|
83
|
+
#
|
84
|
+
# Basically running through
|
85
|
+
# each level of directories
|
86
|
+
# while there are only directories
|
87
|
+
# in the current directory
|
88
|
+
#
|
89
|
+
while all == directories
|
90
|
+
level += 1
|
91
|
+
@logger.h2 Logger::DEBUG, "Level += 1\nPath = #{@path}"
|
92
|
+
chdir directories.first
|
93
|
+
@logger.h2 Logger::DEBUG, "New path = #{@path}"
|
94
|
+
end
|
95
|
+
|
96
|
+
# If the core of project is not at the root of directory ...
|
97
|
+
if level >= 1
|
98
|
+
Dir.glob(File.join(@path,'*')).each do |file|
|
99
|
+
FileUtils.mv(file,File.join(@directory, entry))
|
100
|
+
end
|
101
|
+
@logger.h2 Logger::INFO, "Structuring #{File.join(@path)}"
|
102
|
+
@logger.h2 Logger::INFO, "Removing #{File.join(@directory, entry, rm)}"
|
103
|
+
FileUtils.rm_rf(File.join(@directory, entry, rm))
|
104
|
+
end
|
105
|
+
|
106
|
+
@path = @directory
|
107
|
+
end
|
108
|
+
|
109
|
+
# Initialize a git repo.
|
110
|
+
# @param entry [String] Directory to process.
|
111
|
+
def git(entry)
|
112
|
+
Dir.chdir File.join(@directory, entry) do
|
113
|
+
git_init
|
114
|
+
git_add
|
115
|
+
git_commit
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
|
120
|
+
# Method which run the organiser.
|
121
|
+
# It will apply all importants methods of this class for each project.
|
122
|
+
def run
|
123
|
+
@data.each do |entry|
|
124
|
+
@logger.h1 Logger::INFO, "Work on #{entry}"
|
125
|
+
@logger.h1 Logger::INFO, "Structure project"
|
126
|
+
structure entry
|
127
|
+
|
128
|
+
@logger.h1 Logger::INFO, "Initializing git repo"
|
129
|
+
git entry
|
130
|
+
|
131
|
+
@logger.h1 Logger::INFO, "Renaming directory"
|
132
|
+
rename entry
|
133
|
+
@logger.newline
|
134
|
+
end
|
135
|
+
|
136
|
+
@logger.h1 Logger::INFO, "#{@groups.size} group#{'s' if @groups.size > 1} have been detected"
|
137
|
+
@logger.h1 Logger::INFO, "#{@students.size} student#{'s' if @students.size > 1} have been detected"
|
138
|
+
@logger.h1 Logger::INFO, "#{@binoms.size} binom#{'s' if @binoms.size > 1} have been detected"
|
139
|
+
|
140
|
+
log_resume(@groups, Logger::INFO, "Groups:")
|
141
|
+
log_resume(@students, Logger::INFO, "Students:")
|
142
|
+
log_resume(@binoms, Logger::INFO, "Binoms:")
|
143
|
+
|
144
|
+
log_resume(@unknown, Logger::ERROR, "\n#{@unknown.size} projects didn't matched with regex")
|
145
|
+
end
|
146
|
+
|
147
|
+
private
|
148
|
+
#
|
149
|
+
# Take attention : these accessors
|
150
|
+
# are meant to be used by structure
|
151
|
+
# only ! Because @path is initialized
|
152
|
+
# for that, and used only in this def
|
153
|
+
#
|
154
|
+
def all
|
155
|
+
Dir.entries(@path) - $rejected_entries
|
156
|
+
end
|
157
|
+
|
158
|
+
def directories
|
159
|
+
all.select { |e| File.directory? File.join(@path, e) }
|
160
|
+
end
|
161
|
+
|
162
|
+
def chdir(dir)
|
163
|
+
base = @path
|
164
|
+
@path = File.join(base, dir)
|
165
|
+
end
|
166
|
+
|
167
|
+
|
168
|
+
# Shortuct for logs ...
|
169
|
+
# @param data [Array] to loop.
|
170
|
+
# @param severity [Integer] Severity of the log.
|
171
|
+
# @param message [String] Message to log before writing data..
|
172
|
+
def log_resume(data ,severity, message)
|
173
|
+
unless data.empty?
|
174
|
+
@logger.newline
|
175
|
+
@logger.h1 severity, message
|
176
|
+
data.each {|d| @logger.h2 severity, "#{d}" }
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
end
|
181
|
+
end
|
data/lib/config.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
#
|
2
|
+
# @author Renan Strauss
|
3
|
+
# Externalises the configuration
|
4
|
+
#
|
5
|
+
require 'yaml'
|
6
|
+
|
7
|
+
class Cfg
|
8
|
+
# Path for specialized config files for projects
|
9
|
+
ROOT = File.join(File.dirname(File.dirname(__FILE__)))
|
10
|
+
|
11
|
+
# Is the config is loaded ?
|
12
|
+
@@loaded = false
|
13
|
+
|
14
|
+
def self.[](key)
|
15
|
+
@@mem[key] if @@loaded
|
16
|
+
end
|
17
|
+
|
18
|
+
# @return true if there is the key in the config
|
19
|
+
def self.has_key?(key)
|
20
|
+
@@mem.has_key? key
|
21
|
+
end
|
22
|
+
|
23
|
+
# Method class alias
|
24
|
+
# might remove this at some point ( sorry Yannou I know u worked hard :( )
|
25
|
+
self.singleton_class.send(:alias_method, :=~, :has_key?)
|
26
|
+
|
27
|
+
def self.load(cfg_file)
|
28
|
+
@@loaded = true
|
29
|
+
@@mem = {}
|
30
|
+
|
31
|
+
populate YAML.load(File.read(cfg_file))
|
32
|
+
type_file = File.join(ROOT,'type',"#{@@mem[:type]}.yml")
|
33
|
+
type_cfg = YAML.load(File.read(type_file))
|
34
|
+
populate YAML.load(File.read(File.join(ROOT,'lang',"#{type_cfg['language']}.yml")))
|
35
|
+
# So that project's type Cfg overrides
|
36
|
+
# lang Cfg
|
37
|
+
populate type_cfg
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
#
|
42
|
+
# Handy method to convert string keys
|
43
|
+
# read from Cfg file to symbols
|
44
|
+
#
|
45
|
+
def self.populate(hash)
|
46
|
+
hash.each { |k, v| @@mem[k.to_sym] = v}
|
47
|
+
end
|
48
|
+
end
|
data/lib/exec.rb
ADDED
@@ -0,0 +1,136 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
require_relative 'reviser'
|
5
|
+
require_relative 'helpers/criteria'
|
6
|
+
|
7
|
+
#
|
8
|
+
# Module used for managing all actions in command line
|
9
|
+
# This module enables to user the programm in command line.
|
10
|
+
# It use the powerful toolkit Thor for building command line interfaces
|
11
|
+
#
|
12
|
+
# @author Yann Prono
|
13
|
+
#
|
14
|
+
class Exec < Thor
|
15
|
+
|
16
|
+
@@setup = false
|
17
|
+
|
18
|
+
# path of config template file.
|
19
|
+
$template_path = File.join(File.dirname(File.dirname(__FILE__)),'config.yml')
|
20
|
+
|
21
|
+
def initialize(*args)
|
22
|
+
super
|
23
|
+
# If config.yml already exists in the working
|
24
|
+
# directory, then we setup reviser here
|
25
|
+
config_file = File.expand_path('config.yml')
|
26
|
+
setup config_file if File.exist? config_file
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
# Say hello to the user !
|
31
|
+
desc 'hello','Say hello to the user !'
|
32
|
+
def hello
|
33
|
+
puts 'Hello, I am reviser'
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
# Create a environnment for checking projects
|
38
|
+
# This method only copies the config file into the current directory.
|
39
|
+
desc 'init DIRECTORY', 'Create a new App project. By default,DIRECTORY is the current.'
|
40
|
+
def init(dir = '.')
|
41
|
+
pwd = FileUtils.pwd
|
42
|
+
msg = File.exist?(File.join(pwd,dir,File.basename($template_path))) && 'Recreate' || 'Create'
|
43
|
+
FileUtils.mkdir_p dir unless Dir.exist?(File.join(pwd, dir))
|
44
|
+
FileUtils.cp($template_path, dir)
|
45
|
+
message(msg, File.basename($template_path))
|
46
|
+
|
47
|
+
setup File.expand_path(File.join(dir, File.basename($template_path))) unless @@setup
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
# Clean the directory of logs, projects and results.
|
52
|
+
desc 'clean', 'Delete datas creating by the App (logs, projects, results files ...).'
|
53
|
+
def clean
|
54
|
+
if File.exist? 'config.yml'
|
55
|
+
FileUtils.rm_rf(Cfg[:dest], :verbose => true)
|
56
|
+
if Cfg.has_key?(:options) && Cfg[:options].has_key?(:log_dir)
|
57
|
+
FileUtils.rm_rf(Cfg[:options][:log_dir], :verbose => true)
|
58
|
+
else
|
59
|
+
FileUtils.rm_f(Dir['*.txt'], :verbose => true)
|
60
|
+
end
|
61
|
+
|
62
|
+
if Cfg[:out_format].respond_to? 'each'
|
63
|
+
Cfg[:out_format].each { |format| FileUtils.rm_f(Dir["*.#{format}"], :verbose => true) }
|
64
|
+
else
|
65
|
+
FileUtils.rm_f(Dir["*.#{Cfg[:out_format]}"], :verbose => true)
|
66
|
+
end
|
67
|
+
|
68
|
+
FileUtils.rm_rf(Cfg[:res_dir], :verbose => true)
|
69
|
+
else
|
70
|
+
message("Error", "'config.yml' doesn't exist! Check if you are in the good directory.")
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
|
75
|
+
|
76
|
+
# Let do it for analysis.
|
77
|
+
# @param current_dir [String] the directory where the programm has to be launched.
|
78
|
+
desc 'work', 'Run components to analysis computing projects.'
|
79
|
+
def work
|
80
|
+
Reviser::load :component => 'archiver'
|
81
|
+
Reviser::load :component => 'organiser', :inputFrom => 'archiver'
|
82
|
+
Reviser::load :component => 'checker', :inputFrom => 'organiser'
|
83
|
+
Reviser::load :component => 'generator', :inputFrom => 'checker'
|
84
|
+
|
85
|
+
Reviser::run
|
86
|
+
end
|
87
|
+
|
88
|
+
# Launch archiver !
|
89
|
+
desc 'extract', 'Launch archiver and extract all projects.'
|
90
|
+
def extract
|
91
|
+
Reviser::load :component => 'archiver'
|
92
|
+
Reviser::run
|
93
|
+
end
|
94
|
+
|
95
|
+
# Launch organiser !
|
96
|
+
desc 'organise', 'Launch organiser and prepare all projects for analysis'
|
97
|
+
def organise
|
98
|
+
Reviser::load :component => 'organiser'
|
99
|
+
Reviser::run
|
100
|
+
end
|
101
|
+
|
102
|
+
# Launch checker and generator as well !
|
103
|
+
desc 'check', 'Launch checker for analysis and generate results.'
|
104
|
+
def check
|
105
|
+
Reviser::load :component => 'checker'
|
106
|
+
Reviser::load :component => 'generator', :inputFrom => 'checker'
|
107
|
+
Reviser::run
|
108
|
+
end
|
109
|
+
|
110
|
+
# For the moment, associate a label to a criterion (method).
|
111
|
+
desc 'add METH "LABEL" ', 'Add to the method METH a associated LABEL'
|
112
|
+
def add meth, label
|
113
|
+
res = Criteria::Labels.add meth, label
|
114
|
+
message "#{res} label",meth + " => " + label
|
115
|
+
end
|
116
|
+
|
117
|
+
|
118
|
+
no_tasks do
|
119
|
+
# A Formatter message for command line
|
120
|
+
def message(keyword, desc)
|
121
|
+
puts "\t#{keyword}\t\t#{desc}"
|
122
|
+
end
|
123
|
+
|
124
|
+
def setup(config_file)
|
125
|
+
Reviser::setup config_file
|
126
|
+
|
127
|
+
path_res = File.join(File.dirname(File.dirname(__FILE__)),"#{Cfg[:res_dir]}")
|
128
|
+
FileUtils.cp_r(path_res, FileUtils.pwd)
|
129
|
+
|
130
|
+
@@setup = true
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
135
|
+
|
136
|
+
Exec.start(ARGV)
|
@@ -0,0 +1,64 @@
|
|
1
|
+
#
|
2
|
+
# @Author Renan Strauss
|
3
|
+
#
|
4
|
+
# Basic stuff needed for Checker
|
5
|
+
#
|
6
|
+
|
7
|
+
module Helpers
|
8
|
+
module CodeAnalysis
|
9
|
+
|
10
|
+
def all_files
|
11
|
+
files.join("\r")
|
12
|
+
end
|
13
|
+
|
14
|
+
#
|
15
|
+
# @return all files matching the
|
16
|
+
# extenstion language list (note that Cfg[:extension] must be an array)
|
17
|
+
#
|
18
|
+
def src_files
|
19
|
+
sources.join("\r")
|
20
|
+
end
|
21
|
+
|
22
|
+
#
|
23
|
+
# @return the total amount of lines of code
|
24
|
+
#
|
25
|
+
def lines_count
|
26
|
+
count = sources.inject(0) { |sum, f|
|
27
|
+
sum + File.open(f).readlines.select { |l| !l.chomp.empty? }.size
|
28
|
+
}
|
29
|
+
|
30
|
+
count - comments_count # FIXME
|
31
|
+
end
|
32
|
+
|
33
|
+
#
|
34
|
+
# @return the number of lines of comments
|
35
|
+
#
|
36
|
+
def comments_count
|
37
|
+
tab_comments = sources.inject([]) { |t, f| t << IO.read(f).scrub.scan(Cfg[:regex_comments]) }
|
38
|
+
lines = tab_comments.inject('') { |s, comm| s << find_comments(comm) }.split "\n"
|
39
|
+
|
40
|
+
lines.size
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
#
|
46
|
+
# @return all the files in the project's folder
|
47
|
+
#
|
48
|
+
def files
|
49
|
+
Dir.glob("**/*").select { |f| (File.file?(f)) }
|
50
|
+
end
|
51
|
+
|
52
|
+
def sources
|
53
|
+
files.select { |f| Cfg[:extension].include? File.extname(f) }
|
54
|
+
end
|
55
|
+
|
56
|
+
#
|
57
|
+
# Translates a sub-match returned by scan
|
58
|
+
# into raw comments string
|
59
|
+
#
|
60
|
+
def find_comments(comm)
|
61
|
+
comm.inject('') { |t, l| t << l.detect { |a| (a != nil) && !a.strip.empty? } + "\n" }
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
#
|
2
|
+
# @Author Yann Prono
|
3
|
+
# @Author Renan Strauss
|
4
|
+
#
|
5
|
+
# Needed stuff for compiled languages
|
6
|
+
# such as C, Java, and so on.
|
7
|
+
#
|
8
|
+
|
9
|
+
module Helpers
|
10
|
+
module Compilation
|
11
|
+
include Project
|
12
|
+
include System
|
13
|
+
|
14
|
+
#
|
15
|
+
# Only here for compiled language,
|
16
|
+
#
|
17
|
+
def compile
|
18
|
+
#
|
19
|
+
# For now, we compile only if there's
|
20
|
+
# no missing file
|
21
|
+
# We should maybe make it more
|
22
|
+
# understandable in the Cfg
|
23
|
+
#
|
24
|
+
if missing_files.empty?
|
25
|
+
cmd = "#{Cfg[(Cfg.has_key? :preferred_build_command) && :preferred_build_command || :default_build_command]}"
|
26
|
+
out = exec_with_timeout cmd
|
27
|
+
|
28
|
+
if out.has_key? :process_status
|
29
|
+
return "Exit status: 0\r#{out[:stdout]}" unless out[:process_status].exitstatus != 0
|
30
|
+
end
|
31
|
+
|
32
|
+
if Cfg.has_key? :preferred_build_command
|
33
|
+
out = exec_with_timeout Cfg[:default_build_command]
|
34
|
+
end
|
35
|
+
|
36
|
+
(out[:process_status].exitstatus == 0) ? "Exit status: 0\r#{out[:stdout]}" : "#{out[:stdout]}\r#{out[:stderr]}"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|