pintoscheck 0.1.0beta

Sign up to get free protection for your applications and to get access to all the features.
data/bin/ptschk ADDED
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env ruby
2
+ # Pintos Check program
3
+ # http://github.com/ChrisKXu/PintosCheck
4
+ # Written by Christopher Xu
5
+
6
+ require 'pintoscheck'
7
+
8
+ case ARGV[0]
9
+ when '--help' || '--usage'
10
+ help
11
+ when 'init'
12
+ init ARGV[1]
13
+ when 'run'
14
+ run ARGV[1]
15
+ when '--version' || '-v'
16
+ version
17
+ else
18
+ help
19
+ end
@@ -0,0 +1,83 @@
1
+ # Pintos Check program
2
+ # http://github.com/ChrisKXu/PintosCheck
3
+ # Written by Christopher Xu
4
+
5
+ require 'pintoscheck/pintoscheck_config'
6
+ require 'pintoscheck/mail_checker'
7
+ require 'pintoscheck/file_unzipper'
8
+ require 'pintoscheck/pintos_runner'
9
+ require 'fileutils'
10
+ require 'pathname'
11
+
12
+ PTSCHK_VERSION = '0.1.0beta'
13
+
14
+ def version
15
+ puts PTSCHK_VERSION
16
+ end
17
+
18
+ def help
19
+ puts "PintosCheck -- Automatic pintos checker"
20
+ puts "Version: " + PTSCHK_VERSION
21
+ puts "Generic commands: "
22
+ puts " init <my_config_file.config>\t\t\Generates a default config file"
23
+ puts " run <my_config_file.config>\t\t\Run the tasks based on the config file"
24
+ end
25
+
26
+ def usage
27
+ help
28
+ end
29
+
30
+ # Initialize a config script
31
+ def init(file)
32
+ if file.nil?
33
+ puts 'Please specify the file name.'
34
+ help
35
+ else
36
+ PintosCheckConfig.default_config.save_to(file)
37
+ end
38
+ end
39
+
40
+ # Run tasks according to the config script
41
+ def run(file)
42
+ if file.nil?
43
+ puts 'Please specify the file name.'
44
+ help
45
+ else
46
+ # Preparing ...
47
+ printf 'Reading configurations ... '
48
+ config = PintosCheckConfig.load_from(file)
49
+ puts 'done.'
50
+
51
+ # Fetch mail
52
+ printf 'Fetching mail meta-data ... '
53
+ mail_checker = MailChecker.new :host => config.host, :port => config.port, :ssl => config.ssl, :mailaddr => config.mailaddr, :username => config.username, :password => config.password
54
+ msgs = mail_checker.check_mail :mailbox => config.mailbox, :subject => config.search_options[:subject], :sender => config.search_options[:sender], :recipient => config.search_options[:recipient]
55
+ puts "got #{msgs.count} messages, done."
56
+ printf 'Fetching mail attachments ... '
57
+ files = mail_checker.fetch_attachments config.stage_path
58
+ puts "done. Attachments saved to #{config.stage_path}"
59
+
60
+ files.each do |f|
61
+ # Unzip files
62
+ rf = Pathname.new(f).relative_path_from(Pathname.new(config.stage_path))
63
+ dname = config.stage_path + '/'+ rf + '_test'
64
+ if !File.exist?(dname)
65
+ FileUtils.mkdir_p(dname)
66
+ end
67
+ printf "Unzipping #{rf} to #{dname} ... "
68
+ FileUnzipper.unzip(f, dname)
69
+ puts 'done.'
70
+
71
+ # Run test
72
+ printf "Running tests, please wait ... "
73
+ if !File.exist?(config.results_path)
74
+ FileUtils.mkdir_p(config.results_path)
75
+ end
76
+ runner = PintosRunner.new(dname, config.test_dir, config.results_path + '/result_' + rf + '_test.txt')
77
+ runner.validate_path
78
+ runner.run_tests
79
+ puts "done."
80
+ puts "Results saved to #{config.results_path + '/result_' + rf + '_test.txt'}"
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,25 @@
1
+ # Pintos Check program
2
+ # http://github.com/ChrisKXu/PintosCheck
3
+ # Written by Christopher Xu
4
+
5
+ require 'fileutils'
6
+
7
+ class FileUnzipper
8
+
9
+ SUPPORTED_FORMATS = %w[ .zip .tgz .gz .bz2 ]
10
+
11
+ def self.unzip(from, path)
12
+ ext = File.extname(from)
13
+ if File.exist?(from) && SUPPORTED_FORMATS.include?(ext)
14
+ case ext
15
+ when '.zip'
16
+ `unzip #{from} -d #{path}`
17
+ when '.gz' || '.tar.gz' || '.tgz'
18
+ `tar zxf #{from} -C #{path}`
19
+ when '.bz2' || '.tar.bz2'
20
+ `tar jxf #{from} -C #{path}`
21
+ end
22
+ end
23
+ end
24
+
25
+ end
@@ -0,0 +1,111 @@
1
+ # Pintos Check program
2
+ # http://github.com/ChrisKXu/PintosCheck
3
+ # Written by Christopher Xu
4
+
5
+ require 'net/imap'
6
+ require 'fileutils'
7
+
8
+ # This class checks certain mailbox for special kind of mail messages
9
+ # It uses IMAP protocol
10
+ class MailChecker
11
+ attr_accessor :host, :port, :ssl, :mailaddr, :username, :password
12
+
13
+ # ctor
14
+ def initialize(options = {})
15
+ self.host = options[:host] # The imap server, e.g. mail.google.com
16
+ self.port = options[:port] || 143 # The port number, defaults to 143
17
+ self.ssl = options[:ssl] || false # Whether to use ssl
18
+ self.mailaddr = options[:mailaddr] # The email address, e.g. chriskxu@chriskxu.com
19
+ self.username = options[:username] # The username to access the email
20
+ self.password = options[:password] # The password to access the email
21
+ end
22
+
23
+ # Returns a list of message numbers to investigate
24
+ def check_mail(options = {})
25
+ @mailbox = options[:mailbox] || "inbox" # Defaults to inbox
26
+ # regex = options[:regex] # The subject pattern to match
27
+ @subject = options[:subject] # The keyword in the subject to search
28
+ @recipient = options[:recipient] || self.mailaddr # The recipient to match, a string or a list of strings
29
+ @sender = options[:sender] # The sender to match, a string or a list of strings
30
+ @ret = [] # an array of message numbers
31
+
32
+ t = Thread.new do
33
+ # Now we check the email based on the parameters
34
+ imap = Net::IMAP.new(self.host, self.port, self.ssl)
35
+ imap.login(self.username, self.password)
36
+
37
+ imap.examine(@mailbox)
38
+
39
+ if !@subject.nil?
40
+ if @subject.class != Array # subject is NOT an array
41
+ @subject = [@subject]
42
+ end
43
+ @subject.each do |s|
44
+ @ret = imap.search(["SUBJECT", s])
45
+ end
46
+ end
47
+
48
+ if @recipient.class != Array # recipient is NOT an array
49
+ @recipient = [@recipient]
50
+ end
51
+ @recipient.each do |r|
52
+ @ret &= imap.search(["TO", r])
53
+ end
54
+
55
+ if !@sender.nil?
56
+ if @sender.class != Array # sender is NOT an array
57
+ @sender = [@sender]
58
+ end
59
+ @sender.each do |s|
60
+ @ret &= imap.search(["FROM", s])
61
+ end
62
+ end
63
+
64
+ imap.logout
65
+ #imap.close
66
+ end
67
+
68
+ t.join
69
+ @ret = @ret.uniq
70
+ end
71
+
72
+ def fetch_attachments(path)
73
+ imap = Net::IMAP.new(self.host, self.port, self.ssl)
74
+ imap.login(self.username, self.password)
75
+ files = []
76
+
77
+ imap.examine(@mailbox)
78
+ t = Thread.new do
79
+ @ret.each do |mail|
80
+ message = imap.fetch(mail, ["BODY", "ENVELOPE"])[0]
81
+ body = message.attr["BODY"]
82
+ sender = message.attr["ENVELOPE"].sender[0]
83
+ i = 1
84
+ while body.parts[i] != nil && body.parts[i].media_type == "TEXT"
85
+ i += 1
86
+ end
87
+ while body.parts[i] != nil
88
+ attachment = imap.fetch(mail, "BODY[#{i + 1}]")[0].attr["BODY[#{i + 1}]"]
89
+ filename = body.parts[i].param["NAME"]
90
+ # Save the attachment to file
91
+ if !File.exist?(path)
92
+ FileUtils.mkdir_p(path)
93
+ end
94
+ filename = path + "/#{sender.mailbox}_#{filename}"
95
+ files << filename
96
+ file = File.new(filename, 'wb+')
97
+ file.write(attachment.unpack('m'))
98
+ file.close
99
+ i += 1
100
+ end
101
+ end
102
+
103
+ imap.logout
104
+ end
105
+ # imap.close
106
+
107
+ t.join
108
+ files
109
+ end
110
+
111
+ end
@@ -0,0 +1,39 @@
1
+ # Pintos Check program
2
+ # http://github.com/ChrisKXu/PintosCheck
3
+ # Written by Christopher Xu
4
+
5
+ class PintosRunner
6
+ attr_reader :result
7
+
8
+ def initialize(root, testpath, resultspath)
9
+ @root = root
10
+ @testpath = testpath
11
+ @resultspath = resultspath
12
+ end
13
+
14
+ def validate_path
15
+ ret = ''
16
+ if File.exist?("#{@root}/#{@testpath}")
17
+ ret = "#{@root}/#{@testpath}"
18
+ elsif File.exist?("#{@root}/src/#{@testpath}")
19
+ ret = "#{@root}/src/#{@testpath}"
20
+ elsif File.exist?("#{@root}/pintos/#{@testpath}")
21
+ ret = "#{@root}/pintos/#{@testpath}"
22
+ elsif File.exist?("#{@root}/pintos/src/#{@testpath}")
23
+ ret = "#{@root}/pintos/src/#{@testpath}"
24
+ end
25
+
26
+ @runpath = ret
27
+ end
28
+
29
+ def run_tests
30
+ t = Thread.new do
31
+ @result = `cd #{@runpath} && make check 2>/dev/null | tail -n1`
32
+ end
33
+
34
+ t.join
35
+ `cp #{@runpath}/build/results #{@resultspath} && echo "#{@result}" >> #{@resultspath}`
36
+ @result
37
+ end
38
+
39
+ end
@@ -0,0 +1,46 @@
1
+ # Pintos Check program
2
+ # http://github.com/ChrisKXu/PintosCheck
3
+ # Written by Christopher Xu
4
+
5
+ require 'yaml'
6
+
7
+ class PintosCheckConfig
8
+ attr_accessor :mailaddr, :mailbox, :username, :password, :host, :port, :ssl, :stage_path, :test_dir, :results_path
9
+ attr_accessor :search_options
10
+
11
+ def self.default_config
12
+ config = PintosCheckConfig.new do |c|
13
+ c.mailaddr = 'mail@example.com'
14
+ c.mailbox = 'inbox'
15
+ c.username = 'johndoe'
16
+ c.password = 'secret'
17
+ c.host = 'imap.gmail.com'
18
+ c.port = 993
19
+ c.ssl = true
20
+ c.stage_path = '/tmp/pintoscheck'
21
+ c.test_dir = 'threads'
22
+ c.results_path = '/tmp/pintoscheck/results'
23
+ c.search_options[:subject] = 'pintos'
24
+ c.search_options[:sender] = [ 'someone@example.com', 'sometwo@example.com' ]
25
+ c.search_options[:recipient] = 'somethree@example.com'
26
+ end
27
+
28
+ config
29
+ end
30
+
31
+ def self.load_from(filepath)
32
+ data = File.new(filepath, 'r').read
33
+ config = YAML.load(data)
34
+ end
35
+
36
+ def save_to(filepath)
37
+ save = self.to_yaml
38
+ File.new(filepath, 'w+').write(save)
39
+ end
40
+
41
+ def initialize(&block)
42
+ @search_options = {}
43
+ yield(self)
44
+ end
45
+
46
+ end
@@ -0,0 +1,40 @@
1
+ # Pintos Check program
2
+ # http://github.com/ChrisKXu/PintosCheck
3
+ # Written by Christopher Xu
4
+
5
+ require 'pintoscheck/file_unzipper'
6
+ require 'pintoscheck/mail_checker'
7
+ require 'test/unit'
8
+ require 'fileutils'
9
+
10
+ class TestFileUnzipper < Test::Unit::TestCase
11
+
12
+ def setup
13
+ @host = 'imap.gmail.com'
14
+ @username = 'pintoscheck@chriskxu.com'
15
+ @password = 'pintoscheck'
16
+ @port = 993
17
+ @ssl = true
18
+
19
+ @mail_checker = MailChecker.new :host => @host, :port => @port, :username => @username, :password => @password, :ssl => @ssl, :mailaddr => @username
20
+ end
21
+
22
+ def test_unzip
23
+ messages = @mail_checker.check_mail :mailbox => 'inbox', :subject => 'attachment'
24
+ assert_equal [4], messages
25
+
26
+ # Now we fetch the attachments
27
+ path = '/tmp/pintoscheck'
28
+ @mail_checker.fetch_attachments(path)
29
+ assert File.exist?(path)
30
+ # assert File.exist?(path + '/xuhotdogs@gmail.com_s3-qrc-20060301.pdf')
31
+ assert File.exist?(path + '/xuhotdogs@gmail.com_ospdf09.zip')
32
+
33
+ # Now the FileUnzipper comes in
34
+ FileUtils.mkdir_p(path + '/xuhotdogs@gmail.com_ospdf09')
35
+ FileUnzipper.unzip(path + '/xuhotdogs@gmail.com_ospdf09.zip', path + '/xuhotdogs@gmail.com_ospdf09')
36
+ assert File.exist?(path + '/xuhotdogs@gmail.com_ospdf09/ospdf09')
37
+ assert File.exist?(path + '/xuhotdogs@gmail.com_ospdf09/ospdf09/09_0.pdf')
38
+ end
39
+
40
+ end
@@ -0,0 +1,44 @@
1
+ # Pintos Check program
2
+ # http://github.com/ChrisKXu/PintosCheck
3
+ # Written by Christopher Xu
4
+
5
+ require 'pintoscheck/mail_checker'
6
+ require 'test/unit'
7
+
8
+ class TestMailChecker < Test::Unit::TestCase
9
+ def setup
10
+ @host = 'imap.gmail.com'
11
+ @username = 'pintoscheck@chriskxu.com'
12
+ @password = 'pintoscheck'
13
+ @port = 993
14
+ @ssl = true
15
+
16
+ @mail_checker = MailChecker.new :host => @host, :port => @port, :username => @username, :password => @password, :ssl => @ssl, :mailaddr => @username
17
+ end
18
+
19
+ def test_initialize
20
+ assert_equal @host, @mail_checker.host
21
+ assert_equal @username, @mail_checker.username
22
+ assert_equal @password, @mail_checker.password
23
+ assert_equal @port, @mail_checker.port
24
+ assert_equal @username, @mail_checker.mailaddr
25
+ assert_equal @ssl, @mail_checker.ssl
26
+ end
27
+
28
+ def test_check_mail
29
+ result1 = @mail_checker.check_mail :mailbox => 'inbox', :subject => 'gmail'
30
+ assert_equal [1, 2], result1
31
+ end
32
+
33
+ def test_fetch_attachments
34
+ messages = @mail_checker.check_mail :mailbox => 'inbox', :subject => 'attachments'
35
+ assert_equal [3], messages
36
+
37
+ # Now we fetch the attachments
38
+ path = '/tmp/pintoscheck'
39
+ @mail_checker.fetch_attachments(path)
40
+ assert File.exist?(path)
41
+ assert File.exist?(path + '/xuhotdogs@gmail.com_s3-qrc-20060301.pdf')
42
+ end
43
+
44
+ end
@@ -0,0 +1,24 @@
1
+ # Pintos Check program
2
+ # http://github.com/ChrisKXu/PintosCheck
3
+ # Written by Christopher Xu
4
+
5
+ require 'pintoscheck/pintos_runner'
6
+ require 'test/unit'
7
+
8
+ class TestPintosRunner < Test::Unit::TestCase
9
+
10
+ def setup
11
+ @runner = PintosRunner.new '/tmp/pintos', 'threads', '/tmp/pintoscheck/results'
12
+ end
13
+
14
+ def test_validate_path
15
+ assert_equal '/tmp/pintos/threads', @runner.validate_path
16
+ end
17
+
18
+ def test_run_tests
19
+ @runner.validate_path
20
+ result = @runner.run_tests
21
+ assert File.exist?('/tmp/pintoscheck/results')
22
+ end
23
+
24
+ end
metadata ADDED
@@ -0,0 +1,80 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pintoscheck
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0beta
5
+ platform: ruby
6
+ authors:
7
+ - Christopher Xu
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2010-05-05 00:00:00 +08:00
13
+ default_executable: ptschk
14
+ dependencies: []
15
+
16
+ description: |
17
+ == PintosCheck -- Auto Pintos Checker to Save the Day ==
18
+
19
+ == Functionalities ==
20
+ The functionality of this simple script is to download pintos homework assignments from the mail inbox and then run through all the desired tests and finally generate reports in plain text or html formats, all automatically.
21
+
22
+ == Requirements For Running PintosCheck ==
23
+ Since all the scripts are written in ruby, PintosCheck require ruby installed on the system. I use ruby 1.8.7 for development, but ruby 1.9.* versions are expected to function as well. However, ruby 1.8.6 and lower versions are not supported. For information of downloading and installing ruby, see http://www.ruby-lang.org/en/downloads/.
24
+ In addition to ruby itself, RubyGems 1.3.* is also required because it hosts the installation source for this project and almost all other ruby projects as well. To download or update RubyGems, please go to http://gemcutter.org/pages/download for more information.
25
+
26
+ == Installation ==
27
+ Once you have all the requirements on your system, it's really easy to install PintosCheck. In the UNIX shell or Windows command line environment, type the following command(sudo if needed):
28
+ gem install pintoscheck --include-dependencies
29
+ Go grab a cup of coffee, and PintosCheck will automatically download and install itself onto the system.
30
+ To check the installation, type 'ptschk --version', and if something like 'PintosCheck 0.1.0' pops up then you're green to go!
31
+
32
+ == Finally, how do I check my students' pintos homework? ==
33
+ This project ships with a 'ptschk' command tool. This tool needs a task configuration file to actually do everything. The configuration file is in YAML format, which is basically a recursive key-value pair representation. If you're using PintosCheck for the first time, there's a very nice command line option to generate the skeleton for you. Just run 'ptschk init my_first_task.config' and a file named 'my_first_task.config' will be generated for you. Inside this file there is a set of the minimal options for the task to run properly, and you just have to fill in what you need. After you set up your configuration file, run 'ptschk run my_first_task.config' and the tasks will kick off immediately, and after a while the report will be generated. A detailed configuration options for advanced task setup will be available in production release of this project.
34
+
35
+ email: XuHotdogs@gmail.com
36
+ executables:
37
+ - ptschk
38
+ extensions: []
39
+
40
+ extra_rdoc_files: []
41
+
42
+ files:
43
+ - lib/pintoscheck/file_unzipper.rb
44
+ - lib/pintoscheck/mail_checker.rb
45
+ - lib/pintoscheck/pintos_runner.rb
46
+ - lib/pintoscheck/pintoscheck_config.rb
47
+ - lib/pintoscheck.rb
48
+ - bin/ptschk
49
+ has_rdoc: true
50
+ homepage: http://github.com/ChrisKXu/pintoscheck
51
+ licenses: []
52
+
53
+ post_install_message:
54
+ rdoc_options: []
55
+
56
+ require_paths:
57
+ - lib
58
+ required_ruby_version: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: "0"
63
+ version:
64
+ required_rubygems_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">"
67
+ - !ruby/object:Gem::Version
68
+ version: 1.3.1
69
+ version:
70
+ requirements: []
71
+
72
+ rubyforge_project:
73
+ rubygems_version: 1.3.5
74
+ signing_key:
75
+ specification_version: 3
76
+ summary: Auto Pintos Checker to Save the Day
77
+ test_files:
78
+ - tests/test_file_unzipper.rb
79
+ - tests/test_mail_checker.rb
80
+ - tests/test_pintos_runner.rb