You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@whimsical.apache.org by ru...@apache.org on 2016/05/12 14:12:07 UTC

[whimsy] branch master updated: rough in a pubsub tool

This is an automated email from the ASF dual-hosted git repository.

rubys pushed a commit to branch master
in repository https://git-dual.apache.org/repos/asf/whimsy.git

The following commit(s) were added to refs/heads/master by this push:
       new  4c023ff   rough in a pubsub tool
4c023ff is described below

commit 4c023ff06a44c43b4456043274fc25d7ac9c7032
Author: Sam Ruby <ru...@intertwingly.net>
AuthorDate: Thu May 12 10:11:35 2016 -0400

    rough in a pubsub tool
---
 tools/pubsub.rb | 201 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 201 insertions(+)

diff --git a/tools/pubsub.rb b/tools/pubsub.rb
new file mode 100644
index 0000000..c4572c3
--- /dev/null
+++ b/tools/pubsub.rb
@@ -0,0 +1,201 @@
+#
+# Whimsy pubsub support: watches for updates to the whimsy repository,
+# fetches the changes and deploys them.
+#
+# For usage instructions, try
+#
+#   ruby pubsub.rb --help
+#
+
+require 'optparse'
+require 'ostruct'
+require 'etc'
+require 'net/http'
+require 'json'
+require 'thread'
+require 'fileutils'
+
+# extract script name
+script = File.basename(__FILE__, '.rb')
+
+#
+### option parsing
+#
+
+options = OpenStruct.new
+options.remote = 'https://git-dual.apache.org/repos/asf/whimsy.git'
+options.local = '/srv/whimsy'
+options.pidfile = "/var/run/#{script}.pid"
+options.streamURL = 'http://gitpubsub-wip.apache.org:2069/json/*'
+# options.streamURL = 'http://svn.apache.org:2069/commits'
+
+optionparser = OptionParser.new do |opts|
+  opts.on '-u', '--user id', "Optional user to run #{script} as" do |user|
+    options.user = user
+  end
+
+  opts.on '-g', '--group id', "Optional group to run #{script} as" do |group|
+    options.group = group
+  end
+
+  opts.on '-p', '--pidfile path', "Optional pid file location" do |path|
+    options.pidfile = path
+  end
+
+  opts.on '-d', '--daemonize', "Run as daemon" do
+    options.daemonize = true
+  end
+
+  opts.on '-s', '--stream', "StreamURL" do |url|
+    options.streamURL = url
+  end
+
+  opts.on '-r', '--remote', "Git Clone URL" do |url|
+    options.streamURL = url
+  end
+
+  opts.on '-c', '--clone', "Git Clone Directory" do |path|
+    options.local = path
+  end
+
+  opts.on '--stop', "Kill the currently running #{script} process" do
+    options.kill = true
+  end
+end
+
+optionparser.parse!
+
+#
+### process management
+#
+
+# Either kill old process, or start a new one
+if options.kill
+  if File.exists? options.pidfile
+    Process.kill 'TERM', File.read(options.pidfile).to_i
+    File.delete options.pidfile if File.exists? options.pidfile
+    exit 0
+  end
+else
+  # optionally daemonize
+  Process.daemon if options.daemonize
+
+  # PID file management
+  if File.writable? options.pidfile
+    File.write options.pidfile, Process.pid.to_s
+    at_exit { File.delete options.pidfile if File.exists? options.pidfile }
+  else
+    STDERR.puts "EACCES: Skipping creation of pidfile #{options.pidfile}"
+  end
+end
+
+# Optionally change user/group
+if Process.uid == 0
+  Process::Sys.setgid Etc.getgrnam(options.group).gid if options.group
+  Process::Sys.setuid Etc.getpwnam(options.user).uid if options.user
+end
+
+# Perform initial clone
+if not Dir.exist? options.local
+  FileUtils.mkdir_p File.basename(options.local)
+  system "git clone #{options.remote} #{options.local}"
+end
+
+#
+# Monitor PubSub endpoint (see http://www.apache.org/dev/gitpubsub.html)
+#
+
+# prime the pump
+restartable = false
+notification_queue = Queue.new
+notification_queue.push 'commit' => {'project' => 'whimsy'}
+
+ps_thread = Thread.new do
+  begin
+    uri = URI.parse(options.streamURL)
+
+    Net::HTTP.start(uri.host, uri.port) do |http|
+      request = Net::HTTP::Get.new uri.request_uri
+
+      http.request request do |response|
+        body = ''
+        response.read_body do |chunk|
+          if chunk =~ /\r\n$|\0$/
+            notification = JSON.parse(body + chunk.chomp("\0"))
+            body = ''
+
+            if notification['stillalive']
+              restartable = true
+            elsif notification['commit']
+              notification_queue << notification
+            elsif notification['svnpubsub']
+              next
+            else
+              STDERR.puts '*** unexpected notification ***'
+              STDERR.puts notification.inspect
+            end
+          else
+            body += chunk
+          end
+        end
+      end
+    end
+  rescue Errno::ECONNREFUSED => e
+    restartable = true
+    STDERR.puts e
+    sleep 3
+  rescue Exception => e
+    STDERR.puts e
+    STDERR.puts e.backtrace
+  end
+end
+
+#
+# Process queued requests
+#
+project = File.basename(options.remote, '.git')
+
+begin
+  while ps_thread.alive?
+    notification = notification_queue.pop
+    next unless notification['commit']['project'] == project
+    notification_queue.clear
+    Dir.chdir(options.local) do
+      before = `git log --oneline -1`
+      system 'git fetch origin'
+      system 'git clean -df'
+      system 'git reset --hard origin/master'
+      if File.exist? 'Rakefile' and `git log --oneline -1` != before
+        system 'rake update'
+      end
+    end
+  end
+rescue SignalException => e
+  STDERR.puts e
+  restartable = false 
+rescue Exception => e
+  if ps_thread.alive?
+    STDERR.puts e
+    STDERR.puts e.backtrace
+    restartable = false 
+  end
+end
+
+#
+# restart
+#
+
+if restartable
+  STDERR.puts 'restarting'
+
+  # reconstruct path to Ruby executable
+  require 'rbconfig'
+  ruby = File.join(
+    RbConfig::CONFIG["bindir"],
+    RbConfig::CONFIG["ruby_install_name"] + RbConfig::CONFIG["EXEEXT"]
+  )
+
+  # relaunch script after a one second delay
+  sleep 1
+  exec ruby, __FILE__, *ARGV 
+end

-- 
To stop receiving notification emails like this one, please contact
['"commits@whimsical.apache.org" <co...@whimsical.apache.org>'].