zeus-edge 0.12.1

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in zeus.gemspec
4
+ gemspec
data/MIT-LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Burke Libbey
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,57 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+ require 'fileutils'
4
+ require 'pathname'
5
+
6
+ ROOT_PATH = Pathname.new(File.expand_path("../../", __FILE__))
7
+ RUBYGEM_PATH = Pathname.new(File.expand_path("../", __FILE__))
8
+
9
+ task build: [:import_externals, :version, :manifest]
10
+ task default: :build
11
+
12
+ task :import_externals do
13
+ puts "building rubygem"
14
+
15
+ Rake::Task[:clean].invoke
16
+
17
+ FileUtils.rm_r(RUBYGEM_PATH + "man") rescue nil
18
+ FileUtils.rm_r(RUBYGEM_PATH + "build") rescue nil
19
+
20
+ # manpages
21
+ FileUtils.mkdir(RUBYGEM_PATH + "man")
22
+ FileUtils.cp_r(ROOT_PATH + "man/build", RUBYGEM_PATH + "man")
23
+
24
+ # multi-arch binaries
25
+ FileUtils.cp_r(ROOT_PATH + "build", RUBYGEM_PATH + "build")
26
+
27
+ Rake::Task[:manifest].invoke
28
+ Rake::Task[:build].invoke
29
+ end
30
+
31
+ task :version do
32
+ version = File.read('../VERSION').chomp
33
+ File.open('lib/zeus/version.rb', 'w') { |f| f.puts <<END
34
+ module Zeus
35
+ VERSION = "#{version}"
36
+ end
37
+ END
38
+ }
39
+ end
40
+
41
+ task :manifest do
42
+ files = `find . -type f | sed 's|^\./||'`.lines.map(&:chomp)
43
+ exceptions = [
44
+ /.gitignore$/,
45
+ /^MANIFEST$/,
46
+ /^pkg\//,
47
+ ]
48
+ files.reject! { |f| exceptions.any? {|ex| f =~ ex }}
49
+ File.open('MANIFEST', 'w') {|f| f.puts files.join("\n") }
50
+ end
51
+
52
+ task :clean do
53
+ FileUtils.rm(RUBYGEM_PATH + "lib/zeus/version.rb") rescue nil
54
+ FileUtils.rm_r(RUBYGEM_PATH + "man") rescue nil
55
+ FileUtils.rm_r(RUBYGEM_PATH + "build") rescue nil
56
+ end
57
+
data/bin/zeus ADDED
@@ -0,0 +1,16 @@
1
+ platform = `uname -sm`
2
+
3
+ exe = case platform
4
+ when /^Darwin/ ; "zeus-darwin-amd64"
5
+ when /^Linux.*64/ ; "zeus-linux-amd64"
6
+ when /^Linux.*/ ; "zeus-linux-386"
7
+ else
8
+ puts "Zeus is not supported on your platform."
9
+ puts "It's not likely to ever be possible on Windows."
10
+ puts "If you're using another platform that you think should work easily, open an issue at:"
11
+ puts "https://github.com/burke/zeus/issues"
12
+ exit 1
13
+ end
14
+
15
+ zeusgemdir = File.expand_path("../../", __FILE__)
16
+ exec "#{zeusgemdir}/build/#{exe}", *ARGV
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,24 @@
1
+ if /linux/ =~ RUBY_PLATFORM
2
+ open("Makefile", "wb") do |f|
3
+ f.write <<-EOF
4
+ CXX = g++
5
+ CXXFLAGS = -O3 -g -Wall
6
+
7
+ inotify-wrapper: inotify-wrapper.o
8
+ $(CXX) $(CXXFLAGS) $< -o $@
9
+
10
+ %.o: %.cpp
11
+ $(CXX) $(CXXFLAGS) -c $< -o $@
12
+
13
+ install:
14
+ # do nothing
15
+ EOF
16
+ end
17
+ else
18
+ open("Makefile", "wb") do |f|
19
+ f.write <<-EOF
20
+ install:
21
+ # do nothing
22
+ EOF
23
+ end
24
+ end
@@ -0,0 +1,116 @@
1
+ #include <map>
2
+ #include <string>
3
+
4
+ #include <stdio.h>
5
+ #include <stdlib.h>
6
+ #include <string.h>
7
+ #include <errno.h>
8
+ #include <unistd.h>
9
+ #include <sys/types.h>
10
+ #include <sys/inotify.h>
11
+
12
+ #include <errno.h>
13
+
14
+ #define EVENT_SIZE (sizeof (struct inotify_event))
15
+ #define EVENT_BUF_LEN (1024 * (EVENT_SIZE + 16))
16
+
17
+ using namespace std;
18
+
19
+ static int _inotify_fd;
20
+ static map<int, string> _WatchedFiles;
21
+ static map<string, bool> _FileIsWatched;
22
+
23
+ // static int inotifyFlags = IN_ATTRIB | IN_MODIFY | IN_MOVE_SELF | IN_DELETE_SELF;
24
+ static int inotifyFlags = IN_ATTRIB | IN_MODIFY | IN_MOVE_SELF | IN_DELETE_SELF;
25
+
26
+ void maybeAddFileToWatchList(string file)
27
+ {
28
+ if (_FileIsWatched[file]) return;
29
+
30
+ int wd = inotify_add_watch(_inotify_fd, file.c_str(), inotifyFlags);
31
+ int attempts = 0;
32
+ // Files are momentarily inaccessible when they are rewritten. I couldn't
33
+ // find a good way to deal with this, so we poll 'deleted' files for 0.25s or so
34
+ // to see if they reappear.
35
+ while (wd == -1 && errno == ENOENT) {
36
+ usleep(10000);
37
+ wd = inotify_add_watch(_inotify_fd, file.c_str(), inotifyFlags);
38
+ if (attempts++ == 25) break; // try for at most about a quarter of a second
39
+ }
40
+ if (wd != -1) {
41
+ _WatchedFiles[wd] = file;
42
+ _FileIsWatched[file] = true;
43
+ }
44
+ }
45
+
46
+ // This essentially removes a file from the watchlist then
47
+ // immediately re-adds it. This is because when a file is rewritten,
48
+ // as so many editors love to do, the watchdescriptor no longer refers to
49
+ // the file, so re must re-watch the path.
50
+ void replaceFileInWatchList(int wd, string file)
51
+ {
52
+ _FileIsWatched.erase(file);
53
+ _WatchedFiles.erase(wd);
54
+ inotify_rm_watch(_inotify_fd, wd);
55
+ maybeAddFileToWatchList(file);
56
+ }
57
+
58
+ void handleStdin()
59
+ {
60
+ char line[2048];
61
+ if (fgets(line, sizeof(line), stdin) == NULL) return;
62
+ line[strlen(line)-1] = 0;
63
+
64
+ maybeAddFileToWatchList(string(line));
65
+ }
66
+
67
+ void handleInotify()
68
+ {
69
+ int length;
70
+ int i = 0;
71
+ char buffer[EVENT_BUF_LEN];
72
+ string filename;
73
+
74
+ length = read(_inotify_fd, buffer, EVENT_BUF_LEN);
75
+ if (length < 0) return;
76
+
77
+ while (i < length) {
78
+ struct inotify_event *event = (struct inotify_event *) &buffer[i];
79
+ string file = _WatchedFiles[event->wd];
80
+ if (file != "") {
81
+ printf("%s\n", file.c_str());
82
+ fflush(stdout);
83
+ replaceFileInWatchList(event->wd, file);
84
+ }
85
+
86
+ i += EVENT_SIZE + event->len;
87
+ }
88
+ }
89
+
90
+ void go()
91
+ {
92
+ fd_set rfds;
93
+ int retval;
94
+
95
+ for (;;) {
96
+ FD_ZERO(&rfds);
97
+ FD_SET(0, &rfds);
98
+ FD_SET(_inotify_fd, &rfds);
99
+
100
+ retval = select(_inotify_fd+1, &rfds, NULL, NULL, NULL);
101
+
102
+ if (retval == -1) {
103
+ // perror("select");
104
+ } else if (retval) {
105
+ if (FD_ISSET(0, &rfds)) handleStdin();
106
+ if (FD_ISSET(_inotify_fd, &rfds)) handleInotify();
107
+ }
108
+ }
109
+ }
110
+
111
+
112
+ int main(int argc, const char *argv[])
113
+ {
114
+ _inotify_fd = inotify_init();
115
+ go();
116
+ }
@@ -0,0 +1,53 @@
1
+ module Zeus
2
+ class LoadTracking
3
+ class << self
4
+
5
+ def features_loaded_by(&block)
6
+ old_features = all_features()
7
+ yield
8
+ new_features = all_features() - old_features
9
+ return new_features
10
+ end
11
+
12
+ def add_feature(file)
13
+ path = if File.exist?(File.expand_path(file))
14
+ File.expand_path(file)
15
+ else
16
+ find_in_load_path(file)
17
+ end
18
+ add_extra_feature(path) if path
19
+ end
20
+
21
+ private
22
+
23
+ def all_features
24
+ untracked = defined?($untracked_features) ? $untracked_features : []
25
+ $LOADED_FEATURES + untracked
26
+ end
27
+
28
+ def add_extra_feature(path)
29
+ $untracked_features ||= []
30
+ $untracked_features << path
31
+ end
32
+
33
+ def find_in_load_path(file)
34
+ $LOAD_PATH.map { |path| "#{path}/#{file}" }.detect{ |file| File.exist? file }
35
+ end
36
+ end
37
+ end
38
+ end
39
+
40
+ module Kernel
41
+
42
+ def load(file, *a)
43
+ Kernel.load(file, *a)
44
+ end
45
+
46
+ class << self
47
+ alias_method :__load_without_zeus, :load
48
+ def load(file, *a)
49
+ Zeus::LoadTracking.add_feature(file)
50
+ __load_without_zeus(file, *a)
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,52 @@
1
+ require "forwardable"
2
+
3
+ module Zeus
4
+ module M
5
+ ### Custom wrapper around an array of test methods
6
+ # In charge of some smart querying, filtering, sorting, etc on the the
7
+ # test methods
8
+ class TestCollection
9
+ include Enumerable
10
+ extend Forwardable
11
+ # This should act like an array, so forward some common methods over to the
12
+ # internal collection
13
+ def_delegators :@collection, :size, :<<, :each, :empty?
14
+
15
+ def initialize(collection = nil)
16
+ @collection = collection || []
17
+ end
18
+
19
+ # Slice out tests that may be within the given line.
20
+ # Returns a new TestCollection with the results.
21
+ def within(line)
22
+ # Into a new collection, filter only the tests that...
23
+ self.class.new(select do |test|
24
+ # are within the given boundary for this method
25
+ # or include everything if the line given is nil (no line)
26
+ line.nil? || (test.start_line..test.end_line).include?(line)
27
+ end)
28
+ end
29
+
30
+ # Used to line up method names in `#sprintf` when `m` aborts
31
+ def column_size
32
+ # Boil down the collection of test methods to the name of the method's
33
+ # size, then find the largest one
34
+ @column_size ||= map { |test| test.name.to_s.size }.max
35
+ end
36
+
37
+ # Be considerate when printing out tests and pre-sort them by line number
38
+ def by_line_number(&block)
39
+ # On each member of the collection, sort by line number and yield
40
+ # the block into the sorted collection
41
+ sort_by(&:start_line).each(&block)
42
+ end
43
+
44
+ def contains? test_name
45
+ @collection.each do |test|
46
+ return true if test_name.match(test.name)
47
+ end
48
+ false
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,35 @@
1
+ module Zeus
2
+ module M
3
+ ### Simple data structure for what a test method contains.
4
+ #
5
+ # Too lazy to make a class for this when it's really just a bag of data
6
+ # without any behavior.
7
+ #
8
+ # Includes the name of this method, what line on the file it begins on,
9
+ # and where it ends.
10
+ class TestMethod < Struct.new(:name, :start_line, :end_line)
11
+ # Set up a new test method for this test suite class
12
+ def self.create(suite_class, test_method, find_locations = true)
13
+ # Hopefully it's been defined as an instance method, so we'll need to
14
+ # look up the ruby Method instance for it
15
+ method = suite_class.instance_method(test_method)
16
+
17
+ if find_locations
18
+ # Ruby can find the starting line for us, so pull that out of the array
19
+ start_line = method.source_location.last
20
+
21
+ # Ruby can't find the end line however, and I'm too lazy to write
22
+ # a parser. Instead, `method_source` adds `Method#source` so we can
23
+ # deduce this ourselves.
24
+ #
25
+ # The end line should be the number of line breaks in the method source,
26
+ # added to the starting line and subtracted by one.
27
+ end_line = method.source.split("\n").size + start_line - 1
28
+ end
29
+
30
+ # Shove the given attributes into a new databag
31
+ new(test_method, start_line, end_line)
32
+ end
33
+ end
34
+ end
35
+ end