hubeye 0.3.3 → 0.3.5

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.
@@ -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 :tracker, :hooks
5
+ attr_writer :hooks
6
6
 
7
7
  def initialize
8
- setup_singleton_methods
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 cleanup
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
- def setup_singleton_methods
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