zeus 0.4.6 → 0.10.0.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. data/Gemfile +0 -4
  2. data/Rakefile +52 -8
  3. data/bin/zeus +14 -6
  4. data/build/fsevents-wrapper +0 -0
  5. data/build/zeus-darwin-amd64 +0 -0
  6. data/build/zeus-linux-386 +0 -0
  7. data/build/zeus-linux-amd64 +0 -0
  8. data/examples/zeus.json +22 -0
  9. data/ext/fsevents-wrapper/fsevents-wrapper +0 -0
  10. data/ext/inotify-wrapper/extconf.rb +24 -0
  11. data/ext/inotify-wrapper/inotify-wrapper.cpp +86 -0
  12. data/lib/zeus.rb +123 -35
  13. data/lib/zeus/{server/load_tracking.rb → load_tracking.rb} +1 -3
  14. data/lib/zeus/rails.rb +141 -0
  15. data/man/build/zeus +49 -0
  16. data/man/build/zeus-init +13 -0
  17. data/man/build/zeus-init.txt +17 -0
  18. data/man/build/zeus-start +16 -0
  19. data/man/build/zeus-start.txt +18 -0
  20. data/man/build/zeus.txt +50 -0
  21. data/zeus.gemspec +17 -6
  22. metadata +27 -58
  23. data/.gitignore +0 -17
  24. data/.travis.yml +0 -5
  25. data/.zeus.rb +0 -11
  26. data/README.md +0 -73
  27. data/docs/acceptor_registration.md +0 -14
  28. data/docs/client_server_handshake.md +0 -25
  29. data/ext/fsevents-wrapper/main.m +0 -118
  30. data/lib/thrud.rb +0 -97
  31. data/lib/zeus/cli.rb +0 -80
  32. data/lib/zeus/client.rb +0 -114
  33. data/lib/zeus/client/winsize.rb +0 -28
  34. data/lib/zeus/error_printer.rb +0 -16
  35. data/lib/zeus/plan.rb +0 -18
  36. data/lib/zeus/plan/acceptor.rb +0 -38
  37. data/lib/zeus/plan/node.rb +0 -66
  38. data/lib/zeus/plan/stage.rb +0 -50
  39. data/lib/zeus/server.rb +0 -103
  40. data/lib/zeus/server/acceptor.rb +0 -79
  41. data/lib/zeus/server/acceptor_registration_monitor.rb +0 -75
  42. data/lib/zeus/server/client_handler.rb +0 -106
  43. data/lib/zeus/server/command_runner.rb +0 -70
  44. data/lib/zeus/server/file_monitor.rb +0 -8
  45. data/lib/zeus/server/file_monitor/fsevent.rb +0 -102
  46. data/lib/zeus/server/process_tree_monitor.rb +0 -89
  47. data/lib/zeus/server/stage.rb +0 -88
  48. data/lib/zeus/server/stage/error_state.rb +0 -42
  49. data/lib/zeus/server/stage/feature_notifier.rb +0 -38
  50. data/lib/zeus/templates/rails.rb +0 -133
  51. data/lib/zeus/ui.rb +0 -57
  52. data/lib/zeus/version.rb +0 -3
  53. data/spec/cli_spec.rb +0 -95
  54. data/spec/error_printer_spec.rb +0 -27
  55. data/spec/integration_spec.rb +0 -106
  56. data/spec/server/file_monitor/fsevent_spec.rb +0 -88
  57. data/spec/server/load_tracking_spec.rb +0 -67
  58. data/spec/server/process_tree_monitor_spec.rb +0 -50
  59. data/spec/spec_helper.rb +0 -38
  60. data/spec/ui_spec.rb +0 -54
@@ -1,25 +0,0 @@
1
- # Client/Server handshake
2
-
3
- This takes place in `lib/zeus/server/client_handler.rb`, `lib/zeus/client.rb`, and `lib/zeus/server/acceptor.rb`.
4
-
5
- The model is kind of convoluted, so here's an explanation of what's happening with all these sockets:
6
-
7
- ## Running a command
8
- 1. ClientHandler has a UNIXServer (`SVR`) listening.
9
- 2. ClientHandler has a socketpair with the acceptor referenced by the command (see `docs/acceptor_registration.md`) (`S_ACC`)
10
- 3. When clienthandler receives a connection (`S_CLI`) on `SVR`:
11
- 1. ClientHandler sends `S_CLI` over `S_ACC`, so the acceptor can communicate with the server's client.
12
- 2. ClientHandler sends a JSON-encoded array of `arguments` over `S_ACC`
13
- 3. Acceptor sends the newly-forked worker PID over `S_ACC` to clienthandler.
14
- 4. ClientHandler forwards the pid to the client over `S_CLI`.
15
-
16
-
17
- ## A sort of network diagram
18
- client clienthandler acceptor
19
- 1 ----------> | {command: String, arguments: [String]}
20
- 2 ----------> | Terminal IO
21
- 3 -----------> | Terminal IO
22
- 4 -----------> | Arguments (json array)
23
- 5 <----------- | pid
24
- 6 <--------- | pid
25
-
@@ -1,118 +0,0 @@
1
- #import <Foundation/Foundation.h>
2
- #include <CoreServices/CoreServices.h>
3
- #include <sys/stat.h>
4
- #include <fcntl.h>
5
-
6
-
7
- static CFMutableArrayRef _watchedFiles;
8
- static FSEventStreamRef _activeStream;
9
- static NSMutableDictionary *_fileIsWatched;
10
-
11
- static int flagsWorthReloadingFor = \
12
- kFSEventStreamEventFlagItemRemoved | \
13
- kFSEventStreamEventFlagItemRenamed | \
14
- kFSEventStreamEventFlagItemModified;
15
-
16
- void myCallbackFunction(
17
- ConstFSEventStreamRef streamRef,
18
- void *clientCallBackInfo,
19
- size_t numEvents,
20
- void *eventPaths,
21
- const FSEventStreamEventFlags eventFlags[],
22
- const FSEventStreamEventId eventIds[])
23
- {
24
- int i, flags;
25
- char **paths = eventPaths;
26
-
27
- for (i = 0; i < numEvents; i++) {
28
- flags = eventFlags[i];
29
-
30
- if (flags & (kFSEventStreamEventFlagItemIsFile | flagsWorthReloadingFor)) {
31
- printf("%s\n", paths[i]);
32
- fflush(stdout);
33
- }
34
- }
35
- }
36
-
37
- void configureStream()
38
- {
39
- if (CFArrayGetCount(_watchedFiles) == 0) return;
40
-
41
- if (_activeStream) {
42
- FSEventStreamStop(_activeStream);
43
- FSEventStreamUnscheduleFromRunLoop(_activeStream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
44
- //CFRelease(_activeStream);
45
- }
46
-
47
- _activeStream = FSEventStreamCreate(NULL,
48
- &myCallbackFunction,
49
- NULL,
50
- _watchedFiles,
51
- kFSEventStreamEventIdSinceNow,
52
- 1.0, // latency
53
- kFSEventStreamCreateFlagFileEvents);
54
-
55
- FSEventStreamScheduleWithRunLoop(_activeStream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
56
-
57
- FSEventStreamStart(_activeStream);
58
-
59
- }
60
-
61
- int maybeAddFileToWatchList(char *line)
62
- {
63
- CFStringRef file = CFStringCreateWithCString(NULL, line, kCFStringEncodingASCII);
64
- struct stat buf;
65
-
66
- if ([_fileIsWatched valueForKey:(__bridge NSString *)file]) {
67
- return 0;
68
- } else if (stat(line, &buf) == 0) {
69
- [_fileIsWatched setValue:@"yes" forKey:(__bridge NSString *)file];
70
- CFArrayAppendValue(_watchedFiles, file);
71
- return 1;
72
- } else {
73
- return 0;
74
- }
75
- }
76
-
77
- void handleInputFiles()
78
- {
79
- int anyChanges = 0;
80
-
81
- char line[2048];
82
-
83
- while (fgets(line, sizeof(line), stdin) != NULL) {
84
- line[strlen(line)-1] = 0;
85
- anyChanges |= maybeAddFileToWatchList(line);
86
- }
87
-
88
- if (anyChanges) {
89
- configureStream();
90
- }
91
- }
92
-
93
- void configureTimerAndRun()
94
- {
95
- CFRunLoopTimerRef timer = CFRunLoopTimerCreate(NULL,
96
- 0,
97
- 0.5,
98
- 0,
99
- 0,
100
- &handleInputFiles,
101
- NULL);
102
-
103
- CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopDefaultMode);
104
- CFRunLoopRun();
105
- }
106
-
107
- int main(int argc, const char * argv[])
108
- {
109
- int flags = fcntl(0, F_GETFL);
110
- flags |= O_NONBLOCK;
111
- fcntl(STDIN_FILENO, F_SETFL, flags);
112
-
113
- _watchedFiles = CFArrayCreateMutable(NULL, 0, NULL);
114
- _fileIsWatched = [[NSMutableDictionary alloc] initWithCapacity:500];
115
-
116
- configureTimerAndRun();
117
- return 0;
118
- }
@@ -1,97 +0,0 @@
1
- class Thrud
2
-
3
- class Task < Struct.new(:method_name, :desc, :long_desc, :method_options)
4
- def arity(obj)
5
- obj.method(method_name).arity
6
- end
7
- end
8
-
9
- def self.desc(name, a)
10
- @desc = a
11
- end
12
- def self.long_desc(a)
13
- @long_desc = a
14
- end
15
- def self.method_option(*a)
16
- @method_options ||= []
17
- @method_options << a
18
- end
19
-
20
- def self.method_added(m)
21
- desc, long_desc, method_options = @desc, @long_desc, (@method_options||[])
22
- @desc, @long_desc, @method_options = nil, nil, nil
23
-
24
- @tasks ||= {}
25
- @tasks[m.to_s] = Task.new(m, desc, long_desc, method_options)
26
- end
27
-
28
- def self.map(a)
29
- a.each do |aliases, target|
30
- aliases = [aliases] unless aliases.kind_of?(Array)
31
- aliases.each do |name|
32
- @tasks[name.to_s] = @tasks[target.to_s]
33
- end
34
- end
35
- end
36
-
37
- def self.task_for_name(name)
38
- @tasks[name.to_s]
39
- end
40
-
41
- def task_for_name(name)
42
- self.class.task_for_name(name)
43
- end
44
-
45
- def help(taskname = nil)
46
- if taskname && task = task_for_name(taskname)
47
- arity = task.arity(self)
48
- Zeus.ui.info <<-BANNER
49
- Usage:
50
- zeus #{taskname} #{arity == -1 ? "[ARGS]" : ""}
51
-
52
- Description:
53
- #{task.long_desc || task.desc}
54
- BANNER
55
- else
56
- # this is super non-generic. problem for future-burke.
57
- project_tasks = self.class.instance_variable_get("@tasks").
58
- reject{|k,v|['definition_file', 'initialize', 'version', 'init', 'start', 'help'].include?(v.method_name.to_s)}.values.uniq
59
-
60
- tasks = project_tasks.map { |task|
61
- " zeus %-14s # %s" % [task.method_name, task.desc]
62
- }
63
-
64
- Zeus.ui.info <<-BANNER
65
- Global Commands:
66
- zeus help # show this help menu
67
- zeus help [COMMAND] # show help for a specific command
68
- zeus init # #{task_for_name(:init).desc}
69
- zeus start # #{task_for_name(:start).desc}
70
- zeus version # #{task_for_name(:version).desc}
71
-
72
- Project-local Commands:
73
- #{tasks.join("\n")}
74
- BANNER
75
- end
76
- end
77
-
78
- def self.start
79
- taskname = ARGV.shift
80
- arguments = ARGV
81
-
82
- taskname ||= "help"
83
-
84
- unless task = @tasks[taskname.to_s]
85
- Zeus.ui.error "Could not find task \"#{taskname}\""
86
- exit 1
87
- end
88
-
89
- instance = new
90
- if instance.method(task.method_name).arity == 0 && arguments.any?
91
- Zeus.ui.error "\"#{task.method_name}\" was called incorrectly. Call as \"zeus #{task.method_name}\"."
92
- exit 1
93
- end
94
- instance.send(task.method_name, *arguments)
95
- end
96
-
97
- end
@@ -1,80 +0,0 @@
1
- require 'thrud'
2
-
3
- module Zeus
4
- class CLI < Thrud
5
-
6
- def initialize(*)
7
- super
8
- Zeus.ui = Zeus::UI.new
9
- Zeus.ui.debug! #if options['verbose']
10
- end
11
-
12
- desc "init", "Generates a zeus config file in the current working directory"
13
- long_desc <<-D
14
- Init tries to determine what kind of project is in the current working directory,
15
- and generates a relevant config file. Currently the only supported template is
16
- rails.
17
- D
18
- # method_option "rails", type: :string, banner: "Use the rails template instead of auto-detecting based on project contents"
19
- def init
20
- require 'fileutils'
21
-
22
- if File.exist?(".zeus.rb")
23
- Zeus.ui.error ".zeus.rb already exists at #{Dir.pwd}/.zeus.rb"
24
- exit 1
25
- end
26
-
27
- Zeus.ui.info "Writing new .zeus.rb to #{Dir.pwd}/.zeus.rb"
28
- FileUtils.cp(File.expand_path("../templates/rails.rb", __FILE__), '.zeus.rb')
29
- end
30
-
31
- desc "start", "Start a zeus server for the project in the current working directory"
32
- long_desc <<-D
33
- starts a server that boots your application using the config file in
34
- .zeus.rb. The server will take several seconds to start, after which you may
35
- use the zeus runner commands (see `zeus help` for a list of available commands).
36
- D
37
- def start
38
- begin
39
- require self.class.definition_file
40
- rescue LoadError
41
- Zeus.ui.error("Your project is missing a config file (.zeus.rb), and it doesn't appear\n"\
42
- "to be a rails project. You can run `zeus init` to generate a config file.")
43
- exit 1
44
- end
45
- Zeus::Server.new.run
46
- end
47
-
48
- def help(*)
49
- super
50
- end
51
-
52
- desc "version", "Print zeus's version information and exit"
53
- def version
54
- Zeus.ui.info "Zeus version #{Zeus::VERSION}"
55
- end
56
- map %w(-v --version) => :version
57
-
58
- def self.definition_file
59
- if !File.exists?('.zeus.rb') && File.exists?('script/rails')
60
- File.expand_path("../templates/rails.rb", __FILE__)
61
- else
62
- './.zeus.rb'
63
- end
64
- end
65
-
66
- begin
67
- require definition_file
68
- rescue LoadError
69
- end
70
-
71
- Zeus::Server.acceptors.each do |acc|
72
- desc acc.name, (acc.description || "#{acc.name} task defined in zeus definition file")
73
- define_method(acc.name) { |*args|
74
- Zeus::Client.run(acc.name, args)
75
- }
76
- map acc.aliases => acc.name
77
- end
78
-
79
- end
80
- end
@@ -1,114 +0,0 @@
1
- # encoding: utf-8
2
- begin
3
- require "io/console"
4
- rescue LoadError
5
- Zeus.ui.error "io/console not found. Please `gem install io-console` or, preferably, " +
6
- "install ruby 1.9.3 by following the instructions at: " +
7
- "https://gist.github.com/1688857"
8
- exit 1
9
- end
10
- require "json"
11
- require "pty"
12
- require "socket"
13
-
14
- require 'zeus/client/winsize'
15
-
16
- module Zeus
17
- class Client
18
- include Winsize
19
-
20
- attr_accessor :pid
21
-
22
- SIGNALS = {
23
- "\x03" => "INT",
24
- "\x1C" => "QUIT",
25
- "\x1A" => "TSTP",
26
- }
27
- SIGNAL_REGEX = Regexp.union(SIGNALS.keys)
28
-
29
- def self.run(command, args)
30
- new.run(command, args)
31
- end
32
-
33
- def run(command, args)
34
- maybe_raw do
35
- PTY.open do |master, slave|
36
- @exit_status, @es2 = IO.pipe
37
- @master = master
38
- set_winsize
39
- make_winch_channel
40
- @pid = connect_to_server(command, args, slave)
41
-
42
- select_loop!
43
- end
44
- end
45
- end
46
-
47
- private
48
-
49
- def select_loop!
50
- buffer = ""
51
- while ready = select([winch, @master, $stdin, @exit_status])[0]
52
- handle_winch if ready.include?(winch)
53
- handle_stdin(buffer) if ready.include?($stdin)
54
- handle_master(buffer) if ready.include?(@master)
55
- handle_exit if ready.include?(@exit_status)
56
- end
57
- rescue EOFError
58
- end
59
-
60
- def handle_exit
61
- exit @exit_status.readline.chomp.to_i
62
- end
63
-
64
- def connect_to_server(command, arguments, slave, socket_path = Zeus::SOCKET_NAME)
65
- socket = UNIXSocket.new(socket_path)
66
- socket << {command: command, arguments: arguments}.to_json << "\n"
67
- socket.send_io(slave)
68
- socket.send_io(@es2)
69
- slave.close
70
-
71
- pid = socket.readline.chomp.to_i
72
- trap("CONT") { Process.kill("CONT", @pid) }
73
- pid
74
- rescue Errno::ENOENT, Errno::ECONNREFUSED, Errno::ECONNRESET
75
- # we need a \r at the end because the terminal is in raw mode.
76
- Zeus.ui.error "Zeus doesn't seem to be running, try 'zeus start`\r"
77
- exit 1
78
- end
79
-
80
- def handle_stdin(buffer)
81
- input = $stdin.readpartial(4096, buffer)
82
- input.scan(SIGNAL_REGEX).each { |signal|
83
- begin
84
- send_signal(signal, pid)
85
- rescue Errno::ESRCH
86
- exit # the remote process died. Just quit.
87
- end
88
- }
89
- @master << input
90
- end
91
-
92
- def send_signal(signal, pid)
93
- if SIGNALS[signal] == "TSTP"
94
- Process.kill("STOP", pid)
95
- Process.kill("TSTP", Process.pid)
96
- else
97
- Process.kill(SIGNALS[signal], pid)
98
- end
99
- end
100
-
101
- def handle_master(buffer)
102
- $stdout << @master.readpartial(4096, buffer)
103
- end
104
-
105
- def maybe_raw(&b)
106
- if $stdout.tty?
107
- $stdout.raw(&b)
108
- else
109
- b.call
110
- end
111
- end
112
-
113
- end
114
- end
@@ -1,28 +0,0 @@
1
- module Zeus
2
- class Client
3
- module Winsize
4
-
5
- attr_reader :winch
6
-
7
- def set_winsize
8
- $stdout.tty? and @master.winsize = $stdout.winsize
9
- end
10
-
11
- def make_winch_channel
12
- @winch, winch_ = IO.pipe
13
- trap("WINCH") { winch_ << "\0" }
14
- end
15
-
16
- def handle_winch
17
- @winch.read(1)
18
- set_winsize
19
- begin
20
- Process.kill("WINCH", pid) if pid
21
- rescue Errno::ESRCH
22
- exit # the remote process died. Just quit.
23
- end
24
- end
25
-
26
- end
27
- end
28
- end