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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 3ad369beae7c279013559eaca2a371be84de43a0
4
+ data.tar.gz: d08c27df554743428484267bf53872053bf75fb0
5
+ SHA512:
6
+ metadata.gz: 27115ae008fd154acc4e3c0ff6ee9b7cb0da06578634d78f14817b790a3a2bf1e30ba4c376f2d90f9e8becabeccf9bc3882f64cdea7c559ee44764877a5a3181
7
+ data.tar.gz: fda1bc73fb4ff4bb9d90e9a005554dab160601a9cef5a6eb8c8ed2768a9e2ea35452862b5ec9102b84c8ab25ab8f005aca23c6a1db1e3812e33ebc54926e09ee
data/bin/reviser ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'scrub_rb' unless RUBY_VERSION.split('.')[0] == '2'
4
+
5
+ # Command line interface
6
+ require_relative '../lib/exec'
data/config.yml ADDED
@@ -0,0 +1,80 @@
1
+ ---
2
+
3
+ ################################################
4
+ # Config file #
5
+ ################################################
6
+
7
+
8
+ ######## Archiver config ########
9
+
10
+ # File name of the archive containing all projects
11
+ src: projects.zip
12
+
13
+ # The destination directory for these projects
14
+ dest: projects
15
+
16
+
17
+ ######## Organiser config ########
18
+
19
+ # Conventiong naming of projects, useful to rename folders
20
+ # You have to write a pseudo-regex with some constants:
21
+ # [ GROUP, FIRSTN, NAME ]
22
+ #
23
+ # '^GROUP_NAME_NAME' => Project starts with GROUP (S2A for example) and contains two names.
24
+ # '^GROUP_NAME(_NAME)*' => Project starts with GROUP and contains minimum one name.
25
+ # '^TP_html_NAME_FIRSTN' => name starts by 'TP_html_' and contains a name and firstname.
26
+ projects_names: '^FIRSTN NAME'
27
+
28
+
29
+ ######## Generator config ########
30
+
31
+ # The file name for results which will be generated
32
+ out: results
33
+
34
+ # The type/format of the previous file => currently supported: [csv, html, xls]
35
+ out_format:
36
+ - csv
37
+ - html
38
+
39
+ # Ressources directory
40
+ # (needed for html format)
41
+ res_dir: res
42
+
43
+
44
+ ######## Reviser config ########
45
+
46
+ # The type of project (<type>.yml must exists)
47
+ type: Labyrinthe
48
+
49
+ # Default timeout
50
+ # shall be overriden in sorts
51
+ timeout: 5
52
+
53
+
54
+ ######## Global config ########
55
+
56
+ # Criteria you want for analysis
57
+ # Can be overriden or declared in
58
+ # project's config file
59
+ #
60
+ # Basics criteria, available in lib/helpers
61
+ criteria:
62
+ - all_files
63
+ - src_files
64
+ - lines_count
65
+ - comments_count
66
+ - compile
67
+ - execute
68
+
69
+ # Extensions you want to use, available in ext/
70
+ extensions:
71
+ - memleaks
72
+
73
+
74
+ # Options of all components
75
+ # For the moment, there is just verbose option (for logger)
76
+ options:
77
+ :verbose: true
78
+ :log_dir: logs
79
+ # mode of logger => [org, txt ...]
80
+ :log_mode: org
@@ -0,0 +1,21 @@
1
+ require 'html5_validator/validator'
2
+
3
+ module Extensions
4
+ module HtmlValidator
5
+ include Helpers::CodeAnalysis
6
+
7
+ def validate_html
8
+ validator = Html5Validator::Validator.new
9
+
10
+ results = {}
11
+ # Might need to take care of other extensions
12
+ sources.each do |f|
13
+ validator.validate_text File.read(f)
14
+ results.store f, validator.errors
15
+ end
16
+
17
+ results
18
+ end
19
+ end
20
+
21
+ end
data/ext/valgrind.rb ADDED
@@ -0,0 +1,24 @@
1
+ module Extensions
2
+ module Valgrind
3
+
4
+ include Helpers::Execution
5
+ include Helpers::System
6
+
7
+ VALGRIND_FILE = "valgrind.txt"
8
+
9
+ #
10
+ # Check memory leaks of the program
11
+ # The module uses execution value written in the config file of the project
12
+ #
13
+ def memleaks
14
+ executable = find_executable
15
+ program = "#{Cfg[:program_prefix]}#{executable}"
16
+ param = Cfg.has_key?(:execution_value) ? Cfg[:execution_value].first : ''
17
+ cmd = "valgrind --leak-check=full --track-origins=yes --show-reachable=yes #{program} #{param}"
18
+ out = exec_with_timeout cmd
19
+ File.open(VALGRIND_FILE, 'w') { |f| f.write "$ #{cmd}\r#{out[:stdout]}\r#{out[:stderr]}" }
20
+ File.join(FileUtils.pwd, VALGRIND_FILE)
21
+ end
22
+
23
+ end
24
+ end
data/labels.yml ADDED
@@ -0,0 +1,8 @@
1
+ ---
2
+ all_files: Fichiers
3
+ src_files: Fichiers sources
4
+ lines_count: Nombre de lignes de code
5
+ comments_count: Nombre de lignes de commentaires
6
+ compile: Resultats compilation
7
+ execute: Resultats execution
8
+ memleaks: Fuites memoires
data/lang/C.yml ADDED
@@ -0,0 +1,22 @@
1
+ ---
2
+ # C language
3
+
4
+ # List of source files extensions
5
+ extension:
6
+ - .c
7
+ - .h
8
+
9
+ # Whether it's a compiled or an interpreted language
10
+ compiled: true
11
+
12
+ # Program prefix, needed especially for C
13
+ # The execution command will look like this :
14
+ # [execute_command=(java, ruby, python, ...)] [program_prefix]<program> [args]
15
+ # [] are optionals, whereas <> mandatory
16
+ program_prefix: ./
17
+
18
+ # Fallback if no command is specified in project type
19
+ default_build_command: gcc -ansi -pedantic -Wall -g *.c
20
+
21
+ # Ruby regex to find C-style comments
22
+ regex_comments: !ruby/regexp '/(\/\/(.*?)^)|(\/\*(.*?)\*\/)/m'
data/lang/HTML.yml ADDED
@@ -0,0 +1,49 @@
1
+ ---
2
+
3
+ # HTML language
4
+
5
+ # List of source files extensions
6
+ # !!!!! Recent changes make me think
7
+ # we should actually think about
8
+ # renaming it to ext for instance !!!!!!!!
9
+
10
+ # HTML
11
+
12
+ # List of source files extensions
13
+ extension:
14
+ - .html
15
+
16
+ # Whether it's a compiled or an interpreted language
17
+ compiled: false
18
+
19
+ #
20
+ # In all HTML projects, we'll need
21
+ # the html_validator extension
22
+ #
23
+ extensions:
24
+ html_validator:
25
+ :valid: Validite HTML 5
26
+
27
+ # Program prefix, needed especially for C
28
+ # The execution command will look like this :
29
+ # [execute_command=(java, ruby, python, ...)] [program_prefix]<program> [args]
30
+ # [] are optionals, whereas <> mandatory
31
+ # program_prefix:
32
+
33
+ # For interpreted languages
34
+ # execute_command: ruby
35
+
36
+ # If not specified, the first
37
+ # executable file found will be executed
38
+ # program_name: main.rb
39
+
40
+ regex_comments: !ruby/regexp '/#([^{].*)$/'
41
+
42
+ criteria:
43
+ - all_files
44
+ - src_files
45
+ - lines_count
46
+ - comments_count
47
+
48
+ extensions:
49
+ - validate_html
data/lang/Java.yml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ # Java language
3
+
4
+ # List of source files extensions
5
+ extension:
6
+ - .java
7
+
8
+ # Whether it's a compiled or an interpreted language
9
+ compiled: true
10
+
11
+ # Fallback if no command is specified in project type
12
+ default_build_command: javac *.java
13
+
14
+ # Ruby regex to find C-style comments
15
+ regex_comments: !ruby/regexp '/(\/\/(.*?)^)|(\/\*(.*?)\*\/)/m'
data/lang/Ruby.yml ADDED
@@ -0,0 +1,26 @@
1
+ ---
2
+ # Ruby language
3
+
4
+ # List of source files extensions
5
+ extension:
6
+ - .rb
7
+
8
+ # Whether it's a compiled or an interpreted language
9
+ compiled: false
10
+
11
+ # Program prefix, needed especially for C
12
+ # The execution command will look like this :
13
+ # [execute_command=(java, ruby, python, ...)] [program_prefix]<program> [args]
14
+ # [] are optionals, whereas <> mandatory
15
+ # program_prefix:
16
+
17
+ # For interpreted languages
18
+ execute_command: ruby
19
+
20
+ # If not specified, the first
21
+ # executable file found will be executed
22
+ program_name: main.rb
23
+
24
+ regex_comments: !ruby/regexp '/#([^{].*)$/'
25
+
26
+ timeout: 1
data/lib/component.rb ADDED
@@ -0,0 +1,53 @@
1
+ #
2
+ # Author:: Renan Strauss
3
+ #
4
+ require 'yaml'
5
+ require_relative 'loggers/logger'
6
+
7
+ class Component
8
+
9
+ # Each component has a logger (currently a txt file)
10
+ # $logger
11
+
12
+ #
13
+ # Don't forget to call super in your component's initializer !
14
+ # This method is all about : it stores the data from another
15
+ # component accordingly to what you told to Reviser, and
16
+ # creates a hash for child to easily access config file values
17
+ #
18
+ def initialize(data = nil)
19
+ @data = data
20
+ ext = options.has_key?(:log_mode) && options[:log_mode] || 'txt'
21
+ log_file = File.join(options.has_key?(:log_dir) && options[:log_dir] || '.', "#{ self.class.name.split('::').last || ''}.#{ext}")
22
+
23
+ # For now, we output to stderr if verbose option is not set
24
+ # In the future, it would be a good idea to always have logs,
25
+ # but to let the user change the level
26
+ @logger = Loggers::Logger.new(options[:verbose] && log_file || STDERR)
27
+ end
28
+
29
+ # Place-holder
30
+ # Just like an abstract method
31
+ def run
32
+ raise NotImplementedError, 'All components must implement a run method'
33
+ end
34
+
35
+ # Method template
36
+ # So that when somebody implements a custom
37
+ # Component, he doesn't have to carry about
38
+ # logger being closed or not.
39
+ # Might be even more useful at some point
40
+ def work
41
+ data = run
42
+ @logger.close
43
+
44
+ data
45
+ end
46
+
47
+ protected
48
+ #
49
+ # @return all options for all components if they exist in config file.
50
+ def options
51
+ (Cfg.has_key? :options) && Cfg[:options] || { :verbose => false }
52
+ end
53
+ end
@@ -0,0 +1,118 @@
1
+ require 'fileutils'
2
+ require_relative 'extractors'
3
+
4
+
5
+ module Components
6
+
7
+ # Manages uncompression of archive.
8
+ # Archiver extracts all data in a given compressed file.
9
+ #
10
+ # In case of the University of Lorraine,
11
+ # the archive contains all computing projects, compressed too.
12
+ #
13
+ # @example The simple way to extract a compressed file is :
14
+ # Archiver.extract(myFile, myDirectory)
15
+ #
16
+ # @author Yann Prono
17
+ #
18
+ class Archiver < Component
19
+
20
+ # methods for each different archive format
21
+ extend Extractors
22
+
23
+ # Ignored entries
24
+ $rejected = ['.','..']
25
+
26
+ # Initialize archive file and the directory of destination.
27
+ def initialize(data)
28
+ super data
29
+ @src = Cfg[:src]
30
+ @destination = Cfg[:dest]
31
+ @results = []
32
+ end
33
+
34
+
35
+ # Check if the directory destination exists.
36
+ # else create it.
37
+ # For the moment, if the directory exists // TODO little input to confirm
38
+ # @param destination [String] the destination directory
39
+ #
40
+ def self.destination?(destination)
41
+ unless $rejected.include? File.basename destination
42
+ FileUtils.rm_rf(destination) if Dir.exists? destination
43
+ FileUtils.mkdir_p destination, :mode => 0700
44
+ end
45
+ end
46
+
47
+
48
+ # Extract the archive into the destination directory.
49
+ # @param file_name [String] The name of the archive.
50
+ # @param destination [String] The destination directory.
51
+ #
52
+ def self.extract(file_name, destination = '.')
53
+ raise Errno::ENOENT unless File.exist? file_name
54
+
55
+ # Get extension of file_name to know which method calls
56
+ ext = File.extname(file_name)
57
+ ext = ext.delete('.')
58
+
59
+ # Raise exception if the format is unknown by Archiver
60
+ raise "Unknown format '#{r}'" unless respond_to?(ext)
61
+ # Check if destination exists
62
+ self::destination? destination
63
+
64
+ # Run extraction!
65
+ send(ext,file_name, destination)
66
+ end
67
+
68
+
69
+ # Method which extract an archive
70
+ # which contains all computing projects.
71
+ #
72
+ # This method extracts,in first time,the archive
73
+ # given in the constructor and after, all extracted files.
74
+ #
75
+ # Use this method in a global usage of Reviser!
76
+ # Options are for the moment :verbose
77
+ #
78
+ def run
79
+ @logger.h1 Logger::INFO,"First extraction - #{@src}"
80
+ # Extract the original archive
81
+ Archiver.extract(@src, @destination)
82
+
83
+ @logger.h1 Logger::INFO,'Extraction of sub archives'
84
+
85
+ # Extract all sub archives
86
+ entries = Dir.entries(@destination) - $rejected
87
+ extracted = 0
88
+
89
+ entries.each do |entry|
90
+
91
+ ext = File.extname entry
92
+ basename = File.basename entry, ext
93
+ begin
94
+ file_name = File.join(@destination,File.basename(entry))
95
+ destination = File.join(@destination,basename)
96
+
97
+ # Run extraction!
98
+ Archiver.extract(file_name, destination)
99
+ extracted += 1
100
+
101
+ @logger.h2 Logger::INFO, "extracting #{file_name} to #{destination}"
102
+ @results << basename
103
+
104
+ # In case of it can't extract the file
105
+ rescue => e
106
+ @logger.h2 Logger::ERROR, "Can't extract #{entry}: #{e.message}"
107
+ puts e
108
+ end
109
+ # Delete in all case the archive (useless after this step
110
+ FileUtils.rm_rf file_name
111
+ end
112
+ @logger.h1 Logger::INFO, "[#{extracted}/#{entries.size}] projects have been processed"
113
+
114
+ @results
115
+ end
116
+ end
117
+
118
+ end
@@ -0,0 +1,78 @@
1
+ #
2
+ # Author:: Renan Strauss
3
+ #
4
+ # The Checker is a component that wraps
5
+ # all required tools to do the analysis.
6
+ # It adapts itself dynamically
7
+ # to the language Cfg.
8
+ #
9
+ #
10
+ require 'open3'
11
+
12
+ require_relative '../helpers/criteria'
13
+
14
+ module Components
15
+ class Checker < Component
16
+ include Helpers::Criteria
17
+
18
+ def initialize(data)
19
+ super data
20
+
21
+ init_criteria_helper
22
+
23
+ @results = {}
24
+ end
25
+
26
+ # Yann : je ne recupere pas les datas de l'organiser,
27
+ # Je considere que tous les projets sont dans le dossier courant.
28
+ # TODO a voir si cela marche dans certains cas particuliers
29
+ def run
30
+ # We'll work in the dest directory
31
+ Dir.chdir Cfg[:dest] do
32
+ projects = Dir.entries('.') - ['.','..']
33
+ projects.each_with_index do |proj, i|
34
+ puts "\t[#{i+1}/#{projects.size}]\t#{proj}"
35
+ Dir.chdir(proj) { check proj }
36
+ end
37
+ end
38
+
39
+ @results
40
+ end
41
+
42
+ private
43
+
44
+ #
45
+ # Being called in the project's directory,
46
+ # this methods maps all the criterias to
47
+ # their analysis value
48
+ #
49
+ def check(proj)
50
+ # Init results
51
+ @results[proj] = {}
52
+
53
+ # for each method asked by user with its label
54
+ @output.each do |meth, label|
55
+ if @criteria.has_key? meth
56
+ @results[proj][label] = call meth
57
+ else
58
+ @logger.h1(Logger::ERROR, "Unknown method '#{meth}'' for project #{proj}")
59
+ end
60
+ end
61
+ end
62
+
63
+ #
64
+ # This method is what would be the constructor
65
+ # of criteria_helper if it was a class
66
+ #
67
+ def init_criteria_helper
68
+ @criteria = Hash.new
69
+ @output = Hash.new
70
+ @logger.h1 Logger::INFO, "Loading modules"
71
+ load PWD, '../helpers/*'
72
+ load EXT, '*'
73
+ @logger.h1 Logger::INFO, "Loading labels"
74
+ [:criteria, :extensions].each { |x| load_labels x }
75
+ end
76
+
77
+ end
78
+ end
@@ -0,0 +1,139 @@
1
+ require 'rubygems'
2
+ require 'fileutils'
3
+
4
+ module Components
5
+
6
+ # The module contains all methods to extract an archive
7
+ # regardless the format.
8
+ #
9
+ # Convention over configuration !
10
+ #
11
+ # To add a new format, maybe you need to install the a gem.
12
+ # Find your gem which uncompress a specified format on rubygems.org.
13
+ # Add the line "gem <gem>" in the Gemfile and execute "bundle install"
14
+ #
15
+ # Now, you can write the method corresponding to the format.
16
+ # The name of the method corresponds to the format.
17
+ # For example, if you want to use 'rar' format, the name of the method will be: "rar"
18
+ # Don't forget to require the gem: "require <gem>" at the beginning of the method!
19
+ # the header of method looks like the following block:
20
+ #
21
+ # def <format> (archive, destination)
22
+ # require <gem>
23
+ # ...
24
+ # end
25
+ #
26
+ # @author Anthony Cerf
27
+ # @author Yann Prono
28
+ #
29
+ module Extractors
30
+
31
+ # Method which unzip a file.
32
+ # @param zip_file [String] the zip file.
33
+ # @param destination [String] Destination of extracted data.
34
+ def zip zip_file, destination
35
+ require 'zip'
36
+ # Cfg the gem
37
+ Zip.on_exists_proc = true
38
+ Zip.continue_on_exists_proc = true
39
+
40
+ Zip::File.open(zip_file) do |archive|
41
+ #Entry = file or directory
42
+ archive.each do |entry|
43
+ #Create filepath
44
+ filepath = File.join(destination, entry.name)
45
+
46
+ # Check if it doesn't exist because of directories (overwrite)
47
+ unless File.exist?(filepath)
48
+ # Create directories to access file
49
+ FileUtils.mkdir_p(File.dirname(filepath))
50
+ entry.extract(filepath)
51
+ end
52
+ end
53
+ end
54
+ end
55
+
56
+ # Method which ungz a file.
57
+ # @param gz_file [String] the gz file.
58
+ # @param destination [String] Destination of extracted data.
59
+ def gz gz_file, destination
60
+ require 'zlib'
61
+ file = Zlib::GzipReader.open(gz_file)
62
+ unzipped = StringIO.new(file.read)
63
+ file.close
64
+ tar(unzipped, destination)
65
+ end
66
+
67
+ # Alias for format shortcut
68
+ # CC Dominique Colnet!
69
+ alias :tgz :gz
70
+
71
+ # Method which untar a tarfile.
72
+ # @param tar_file [String] the tar file.
73
+ # @param destination [String] Destination of extracted data.
74
+ def tar tar_file, destination
75
+ require 'rubygems/package'
76
+ # test if src is String (filename) or IO stream
77
+ if tar_file.is_a? String
78
+ stream = File.open(tar_file)
79
+ else
80
+ stream = tar_file
81
+ end
82
+
83
+ Gem::Package::TarReader.new(stream) do |tar|
84
+ tar.each do |tarfile|
85
+ destination_file = File.join destination, tarfile.full_name
86
+ if tarfile.directory?
87
+ FileUtils.mkdir_p destination_file
88
+ else
89
+ destination_directory = File.dirname(destination_file)
90
+ FileUtils.mkdir_p destination_directory unless File.directory?(destination_directory)
91
+ File.open destination_file, 'wb' do |f|
92
+ f.print tarfile.read
93
+ end
94
+ end
95
+ tarfile.close unless tarfile.closed?
96
+ end
97
+ tar.close
98
+ end
99
+ stream.close
100
+ end
101
+
102
+ # Method which unrar a rar file, if it is possible (proprietary format grr ...)
103
+ # @param rar_file [String] the rar file.
104
+ # @param destination [String] Destination of extracted data.
105
+ def rar rar_file, destination
106
+ require 'shellwords'
107
+ `which unrar`
108
+ if $?.success?
109
+ src = Shellwords.escape(rar_file)
110
+ destination = Shellwords.escape(destination)
111
+ `unrar e #{src} #{destination}`
112
+ else
113
+ puts 'Please install unrar : sudo apt-get install unrar'
114
+ end
115
+ end
116
+
117
+ # Method which un7zip a 7zip file.
118
+ # @param seven_zip_file [String] the 7zip file.
119
+ # @param destination [String] Destination of extracted data.
120
+ def seven_zip seven_zip_file, destination
121
+ require 'seven_zip_ruby'
122
+ File.open(seven_zip_file, 'rb') do |file|
123
+ SevenZipRuby::Reader.open(file) do |szr|
124
+ szr.extract_all destination
125
+ end
126
+ end
127
+ end
128
+
129
+ # Use first of all for seven zip format (little tip, can't call it directly).
130
+ def method_missing(m, *args, &block)
131
+ if (ext = File.extname(args[0]).delete('.') == '7z')
132
+ seven_zip(args[0], args[1])
133
+ else
134
+ raise "Format '#{ext.delete('.')}' not supported"
135
+ end
136
+ end
137
+
138
+ end
139
+ end