hubeye 0.3.3 → 0.3.5
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +59 -40
- data/VERSION.rb +2 -2
- data/bin/hubeye +7 -12
- data/lib/hubeye/client/client.rb +3 -5
- data/lib/hubeye/config/environment.rb +0 -1
- data/lib/hubeye/hooks/{executer.rb → command.rb} +8 -4
- data/lib/hubeye/hooks/git.rb +19 -0
- data/lib/hubeye/log/logger.rb +1 -0
- data/lib/hubeye/server/commit.rb +17 -39
- data/lib/hubeye/server/server.rb +79 -531
- data/lib/hubeye/server/session.rb +5 -32
- data/lib/hubeye/server/strategies/add_hook.rb +32 -0
- data/lib/hubeye/server/strategies/add_repo.rb +91 -0
- data/lib/hubeye/server/strategies/decision.rb +121 -0
- data/lib/hubeye/server/strategies/exit.rb +23 -0
- data/lib/hubeye/server/strategies/list_hooks.rb +38 -0
- data/lib/hubeye/server/strategies/list_tracking.rb +27 -0
- data/lib/hubeye/server/strategies/load_hook.rb +34 -0
- data/lib/hubeye/server/strategies/load_repo.rb +35 -0
- data/lib/hubeye/server/strategies/next.rb +13 -0
- data/lib/hubeye/server/strategies/rm_repo.rb +34 -0
- data/lib/hubeye/server/strategies/save_hook.rb +31 -0
- data/lib/hubeye/server/strategies/save_repo.rb +31 -0
- data/lib/hubeye/server/strategies/shutdown.rb +23 -0
- data/lib/hubeye/server/tracker.rb +89 -0
- data/tasks/install.rb +8 -9
- data/test/helpers/server.rb +39 -0
- metadata +19 -4
- data/lib/hubeye/hooks/git_hooks.rb +0 -19
@@ -2,24 +2,21 @@ module Hubeye
|
|
2
2
|
module Server
|
3
3
|
class Session
|
4
4
|
attr_accessor :repo_name, :username, :continuous
|
5
|
-
attr_writer
|
5
|
+
attr_writer :hooks
|
6
6
|
|
7
7
|
def initialize
|
8
|
-
|
9
|
-
end
|
10
|
-
|
11
|
-
def tracker
|
12
|
-
@tracker ||= {}
|
8
|
+
defaults!
|
13
9
|
end
|
14
10
|
|
15
11
|
def hooks
|
16
12
|
@hooks ||= {}
|
17
13
|
end
|
18
14
|
|
19
|
-
def
|
15
|
+
def defaults!
|
20
16
|
reset_username
|
21
17
|
reset_repo_name
|
22
18
|
end
|
19
|
+
alias cleanup! defaults!
|
23
20
|
|
24
21
|
private
|
25
22
|
def reset_username
|
@@ -30,30 +27,6 @@ module Hubeye
|
|
30
27
|
self.repo_name = ""
|
31
28
|
end
|
32
29
|
|
33
|
-
|
34
|
-
tracker.singleton_class.class_eval do
|
35
|
-
def add_or_replace! input, new_sha=nil
|
36
|
-
if Hash === input and new_sha.nil?
|
37
|
-
repo = input.keys.first
|
38
|
-
hash = true
|
39
|
-
else
|
40
|
-
repo = input
|
41
|
-
two_args = true
|
42
|
-
end
|
43
|
-
if keys.include? repo and self[repo] == new_sha
|
44
|
-
return
|
45
|
-
elsif keys.include? repo
|
46
|
-
ret = {:replace => true}
|
47
|
-
else
|
48
|
-
ret = {:add => true}
|
49
|
-
end
|
50
|
-
two_args ? merge!(repo => new_sha) : merge!(input)
|
51
|
-
ret
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
end # end of Session class
|
30
|
+
end
|
57
31
|
end
|
58
32
|
end
|
59
|
-
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Hubeye
|
2
|
+
module Server
|
3
|
+
module Strategies
|
4
|
+
|
5
|
+
class AddHook
|
6
|
+
def call
|
7
|
+
cwd = File.expand_path('.')
|
8
|
+
repo_name = @matches[1]
|
9
|
+
directory = @matches[3]
|
10
|
+
command = @matches[4]
|
11
|
+
hooks = session.hooks
|
12
|
+
if repo_name.nil? and command.nil?
|
13
|
+
socket.deliver "Format: 'hook add user/repo [dir: /my/dir/repo ] cmd: some_cmd'"
|
14
|
+
return
|
15
|
+
end
|
16
|
+
directory = directory || cwd
|
17
|
+
if hooks[repo_name]
|
18
|
+
if hooks[repo_name][directory]
|
19
|
+
hooks[repo_name][directory] << command
|
20
|
+
else
|
21
|
+
hooks[repo_name][directory] = [command]
|
22
|
+
end
|
23
|
+
else
|
24
|
+
hooks[repo_name] = {directory => [command]}
|
25
|
+
end
|
26
|
+
socket.deliver "Hook added"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
module Hubeye
|
4
|
+
module Server
|
5
|
+
module Strategies
|
6
|
+
|
7
|
+
class AddRepo
|
8
|
+
STATES = [:added, :replaced, :unchanged, :invalid].freeze
|
9
|
+
ADDED = "%{committer} => %{message}\n".freeze
|
10
|
+
REPLACED = "New commit on %s\n".freeze
|
11
|
+
UNCHANGED = "Repository %s hasn't changed\n".freeze
|
12
|
+
INVALID = "%s isn't a valid Github repository\n".freeze
|
13
|
+
|
14
|
+
# Add the given space-separated Github repo(s) if they're valid
|
15
|
+
def call
|
16
|
+
repo_names_given = @matches[1].split
|
17
|
+
@multiple_repos_given = repo_names_given.size > 1
|
18
|
+
@unique_repo_names = Set.new
|
19
|
+
# hash of states associated with repository names.
|
20
|
+
# Ex: {:added => ['luke-gru/hubeye'], :replaced => ['rails/rails'], ...}
|
21
|
+
@states_with_repos = Hash[STATES.map {|s| [ s, [] ]}]
|
22
|
+
repo_names_given.each do |name|
|
23
|
+
full_name = server.full_repo_name(name)
|
24
|
+
@unique_repo_names << full_name
|
25
|
+
end
|
26
|
+
add_repos
|
27
|
+
gather_output
|
28
|
+
socket.deliver @output
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def add_repos
|
34
|
+
@unique_repo_names.each do |full_name|
|
35
|
+
change_state = tracker << full_name
|
36
|
+
@states_with_repos[change_state] << full_name
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def gather_output
|
41
|
+
@output = ''
|
42
|
+
STATES.each do |state|
|
43
|
+
@states_with_repos[state].each do |full_name|
|
44
|
+
@output << header(full_name) if @multiple_repos_given
|
45
|
+
case state
|
46
|
+
when :added
|
47
|
+
cmt = tracker.commit(full_name)
|
48
|
+
@output << ADDED % {:committer => cmt.committer_name, :message => cmt.message}
|
49
|
+
when :replaced
|
50
|
+
cmt = tracker.commit(full_name)
|
51
|
+
@output << REPLACED % full_name
|
52
|
+
log_change(full_name, cmt)
|
53
|
+
when :unchanged
|
54
|
+
@output << UNCHANGED % full_name
|
55
|
+
when :invalid
|
56
|
+
@output << INVALID % full_name
|
57
|
+
end
|
58
|
+
@output << "\n" if @multiple_repos_given && full_name != last_repo_outputted
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def header(full_name)
|
64
|
+
''.tap do |output|
|
65
|
+
output << full_name + "\n"
|
66
|
+
output << ('=' * full_name.length) + ("\n" * 2)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def log_change(repo_name, cmt)
|
71
|
+
if server.daemonized
|
72
|
+
Logger.log_change("#{repo_name}", cmt.message, cmt.committer_name)
|
73
|
+
else
|
74
|
+
Logger.log_change("#{repo_name}", cmt.message, cmt.committer_name,
|
75
|
+
:include_terminal => true)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def last_repo_outputted
|
80
|
+
return @last if @last
|
81
|
+
STATES.reverse_each do |state|
|
82
|
+
repo_names = @states_with_repos[state]
|
83
|
+
next if repo_names.last.nil?
|
84
|
+
return (@last = repo_names.last)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end # end of AddRepo
|
88
|
+
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
3
|
+
$decision_relatives = Dir.glob( File.join(File.expand_path("../", __FILE__), '*') )
|
4
|
+
$decision_relatives.each {|file| require file }
|
5
|
+
|
6
|
+
module Hubeye
|
7
|
+
module Server
|
8
|
+
module Strategies
|
9
|
+
|
10
|
+
# STRATEGIES hash
|
11
|
+
# ===============
|
12
|
+
# keys: input matches
|
13
|
+
# OR
|
14
|
+
# lambda {|input| input.something?} => SomeStrategy.new(decision)
|
15
|
+
#
|
16
|
+
# values: lambda {|decision, matches| SomeStrategy.new(decision, matches)}
|
17
|
+
STRATEGIES = {
|
18
|
+
%r{\Ashutdown\Z} => lambda {|d, m| Shutdown.new(d, m)},
|
19
|
+
%r{\Aquit|exit\Z} => lambda {|d, m| Exit.new(d, m)},
|
20
|
+
%r{\Atracking\s*\Z} => lambda {|d, m| ListTracking.new(d, m)},
|
21
|
+
%r{\Atracking\s*-d\Z} => lambda {|d, m| ListTracking.new(d, m, :details => true)},
|
22
|
+
%r{\Aadd (.*)} => lambda {|d, m| AddRepo.new(d, m)},
|
23
|
+
%r{\A\s*save hook(s?) as (.+)\Z} => lambda {|d, m| SaveHook.new(d, m)},
|
24
|
+
%r{\A\s*save repo(s?) as (.+)\Z} => lambda {|d, m| SaveRepo.new(d, m)},
|
25
|
+
%r{\A\s*load hook(s?) (.+)\Z} => lambda {|d, m| LoadHook.new(d, m)},
|
26
|
+
%r{\A\s*load repo(s?) (.+)\Z} => lambda {|d, m| LoadRepo.new(d, m)},
|
27
|
+
%r{\A\s*internal load hook(s?) (.+)\Z} => lambda {|d, m| LoadHook.new(d, m, :internal => true)},
|
28
|
+
%r{\A\s*internal load repo(s?) (.+)\Z} => lambda {|d, m| LoadRepo.new(d, m, :internal => true)},
|
29
|
+
%r{\Ahook add ([-\w]+/[-\w]+) (dir:\s?(.*))?\s*cmd:\s?(.*)\Z} => lambda {|d, m| AddHook.new(d, m)},
|
30
|
+
%r{\Ahook list\Z} => lambda {|d, m| ListHooks.new(d, m)},
|
31
|
+
%r{^\s*$} => lambda {|d, m| Next.new(d, m)},
|
32
|
+
%r{\Arm\s*-a\Z} => lambda {|d, m| RmRepo.new(d, m, :all => true)},
|
33
|
+
%r{\Arm ([-\w]+/?[-\w]*)\Z} => lambda {|d, m| RmRepo.new(d, m)},
|
34
|
+
# if all else fails, try to add the input as a repo
|
35
|
+
%r{\A(.*)} => lambda {|d, m| AddRepo.new(d, m)},
|
36
|
+
}
|
37
|
+
|
38
|
+
class Decision
|
39
|
+
extend Forwardable
|
40
|
+
attr_reader :server, :input
|
41
|
+
InvalidInput = Class.new(StandardError)
|
42
|
+
|
43
|
+
def_delegators :@server, :tracker, :session, :sockets, :socket
|
44
|
+
|
45
|
+
def initialize(server, options={})
|
46
|
+
@server = server
|
47
|
+
opts = {:internal_input => nil}.merge options
|
48
|
+
invalid_input = lambda {
|
49
|
+
@server.remote_connection = false
|
50
|
+
throw(:invalid_input)
|
51
|
+
}
|
52
|
+
|
53
|
+
if !opts[:internal_input]
|
54
|
+
begin
|
55
|
+
@input = socket.read_all
|
56
|
+
rescue => e
|
57
|
+
STDOUT.puts e
|
58
|
+
invalid_input.call
|
59
|
+
end
|
60
|
+
# check if the client pressed ^C or ^D
|
61
|
+
if @input.nil?
|
62
|
+
invalid_input.call
|
63
|
+
end
|
64
|
+
else
|
65
|
+
@input = opts[:internal_input]
|
66
|
+
end
|
67
|
+
@input = @input.strip.downcase
|
68
|
+
@input.gsub! /diiv/, '/'
|
69
|
+
end
|
70
|
+
|
71
|
+
# Get all the strategy classes from the files names in the /server/strategies/
|
72
|
+
# directory
|
73
|
+
|
74
|
+
@@strategy_classes = []
|
75
|
+
relatives = $decision_relatives.dup
|
76
|
+
relatives.delete_if {|file| file == __FILE__}
|
77
|
+
|
78
|
+
relatives.each do |file|
|
79
|
+
strat = File.basename(file)
|
80
|
+
class_name = strat.sub(/\.rb/, '').split('_').map(&:capitalize).join
|
81
|
+
@@strategy_classes << class_name
|
82
|
+
end
|
83
|
+
|
84
|
+
@@strategy_classes.each do |class_name|
|
85
|
+
klass = Hubeye::Server::Strategies.const_get(class_name)
|
86
|
+
klass.class_eval do
|
87
|
+
extend Forwardable
|
88
|
+
attr_reader :server
|
89
|
+
|
90
|
+
def_delegators :@decision, :input
|
91
|
+
def_delegators :@server, :tracker, :session, :sockets, :socket
|
92
|
+
|
93
|
+
def initialize decision, matches=nil, options={}
|
94
|
+
@decision = decision
|
95
|
+
@matches = matches
|
96
|
+
@options = options
|
97
|
+
@server = @decision.server
|
98
|
+
call
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def call_strategy
|
104
|
+
STRATEGIES.each do |inp,strat|
|
105
|
+
if inp.respond_to? :match
|
106
|
+
if m = @input.match(inp)
|
107
|
+
return strat.call(self, m)
|
108
|
+
end
|
109
|
+
elsif inp.respond_to? :call
|
110
|
+
if inp.call(@input)
|
111
|
+
return strat.call(self)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
raise InvalidInput
|
116
|
+
end
|
117
|
+
end # end of Decision
|
118
|
+
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Hubeye
|
2
|
+
module Server
|
3
|
+
module Strategies
|
4
|
+
|
5
|
+
class Exit
|
6
|
+
def call
|
7
|
+
socket.deliver "Bye!"
|
8
|
+
# mark the session as continuous to not wipe the log file
|
9
|
+
session.continuous = true
|
10
|
+
server.remote_connection = false
|
11
|
+
Logger.log "Closing connection to #{socket.peeraddr[2]}"
|
12
|
+
unless tracker.empty?
|
13
|
+
Logger.log "Tracking: #{tracker.repo_names.join ', '}"
|
14
|
+
end
|
15
|
+
Logger.log ""
|
16
|
+
sockets.delete(socket)
|
17
|
+
socket.close
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Hubeye
|
2
|
+
module Server
|
3
|
+
module Strategies
|
4
|
+
|
5
|
+
class ListHooks
|
6
|
+
def call
|
7
|
+
hooks = session.hooks
|
8
|
+
if hooks.empty?
|
9
|
+
socket.deliver "No hooks"
|
10
|
+
return
|
11
|
+
end
|
12
|
+
pwd = File.expand_path('.')
|
13
|
+
format_string = ""
|
14
|
+
hooks.each do |repo, hash|
|
15
|
+
local_dir = nil
|
16
|
+
command = nil
|
17
|
+
hash.each do |dir,cmd|
|
18
|
+
if dir.nil?
|
19
|
+
local_dir = pwd
|
20
|
+
command = cmd.join("\n" + (' ' * 8))
|
21
|
+
else
|
22
|
+
command = cmd
|
23
|
+
local_dir = dir
|
24
|
+
end
|
25
|
+
end
|
26
|
+
format_string << <<EOS
|
27
|
+
remote: #{repo}
|
28
|
+
dir: #{local_dir}
|
29
|
+
cmds: #{command}\n
|
30
|
+
EOS
|
31
|
+
end
|
32
|
+
socket.deliver format_string
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Hubeye
|
2
|
+
module Server
|
3
|
+
module Strategies
|
4
|
+
|
5
|
+
class ListTracking
|
6
|
+
def call
|
7
|
+
output = ''
|
8
|
+
if @options[:details]
|
9
|
+
commit_list = tracker.commit_list
|
10
|
+
commit_list.each do |cmt|
|
11
|
+
output << cmt.repo_name + "\n"
|
12
|
+
underline = '=' * cmt.repo_name.length
|
13
|
+
output << underline + "\n\n"
|
14
|
+
output << (cmt.committer_name + " => ") + (cmt.message + "\n")
|
15
|
+
output << "\n" unless cmt.repo_name == commit_list.last.repo_name
|
16
|
+
end
|
17
|
+
else
|
18
|
+
output << tracker.repo_names.join(', ')
|
19
|
+
end
|
20
|
+
output = "none" if output.empty?
|
21
|
+
socket.deliver output
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module Hubeye
|
4
|
+
module Server
|
5
|
+
module Strategies
|
6
|
+
|
7
|
+
class LoadHook
|
8
|
+
def call
|
9
|
+
if _t = @options[:internal]
|
10
|
+
@silent = _t
|
11
|
+
end
|
12
|
+
hookfile = "#{ENV['HOME']}/.hubeye/hooks/#{@matches[2]}.yml"
|
13
|
+
new_hooks = nil
|
14
|
+
if File.exists?(hookfile)
|
15
|
+
File.open(hookfile) do |f|
|
16
|
+
new_hooks = YAML.load(f)
|
17
|
+
end
|
18
|
+
# need to fix this to check if there are already commands for that
|
19
|
+
# repo
|
20
|
+
session.hooks.merge!(new_hooks)
|
21
|
+
unless @silent
|
22
|
+
socket.deliver "Loaded #{@matches[1]} #{@matches[2]}"
|
23
|
+
end
|
24
|
+
else
|
25
|
+
unless @silent
|
26
|
+
socket.deliver "No #{@matches[1]} file to load from"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module Hubeye
|
4
|
+
module Server
|
5
|
+
module Strategies
|
6
|
+
|
7
|
+
class LoadRepo
|
8
|
+
def call
|
9
|
+
if _t = @options[:internal]
|
10
|
+
@silent = _t
|
11
|
+
end
|
12
|
+
if File.exists?(repo_file = "#{ENV['HOME']}/.hubeye/repos/#{@matches[2]}.yml")
|
13
|
+
new_repos = nil
|
14
|
+
File.open(repo_file) do |f|
|
15
|
+
new_repos = YAML.load(f)
|
16
|
+
end
|
17
|
+
if !new_repos
|
18
|
+
socket.deliver "Unable to load #{@matches[2]}: empty file" unless @silent
|
19
|
+
return
|
20
|
+
end
|
21
|
+
new_repos.each do |r|
|
22
|
+
tracker << server.full_repo_name(r)
|
23
|
+
end
|
24
|
+
unless @silent
|
25
|
+
socket.deliver "Loaded #{@matches[2]}.\nTracking:\n#{tracker.repo_names.join ', '}"
|
26
|
+
end
|
27
|
+
else
|
28
|
+
socket.deliver "No file to load from" unless @silent
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|