Last active
August 29, 2015 14:08
-
-
Save jtsagata/b284622ed7c2af8ecf17 to your computer and use it in GitHub Desktop.
Poor mens CI. Continious Integration with Zeus, RSpec, tmux/tmuxinator like clone. Autotest and autoreload functionality (Work in progress)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env python | |
| # filename <app>/ci_tool | |
| # Zeus CI IDE | |
| # Created by talos aka Giannis Tsagatakis | |
| # --color | |
| # --require spec_helper | |
| # --format documentation | |
| # --format html -o "tmp/rspec.html" | |
| import gi | |
| gi.require_version('Gtk', '3.0') | |
| from gi.repository import Gtk, Vte, Gio, GLib, GObject, WebKit | |
| import os, subprocess, pyinotify | |
| GObject.threads_init() | |
| site_url = "http://myhost.no-ip.org:3000/" | |
| rails_root = os.getcwd() | |
| # socket = rails_root+"/.zeus.sock" | |
| # if os.path.exists(socket): | |
| # os.remove(socket) | |
| class MyTerm(Vte.Terminal): | |
| def __init__(self, command, *args, **kwds): | |
| super(MyTerm, self).__init__(*args, **kwds) | |
| self.command = command | |
| self.runcmd() | |
| self.connect ("child-exited", lambda term: self.rerun()) | |
| self | |
| def runcmd(self): | |
| self.fork_command_full( | |
| Vte.PtyFlags.DEFAULT, | |
| rails_root, | |
| self.command, | |
| [], | |
| GLib.SpawnFlags.DO_NOT_REAP_CHILD, | |
| None, | |
| None, | |
| ) | |
| def rerun(self): | |
| self.runcmd() | |
| class ZeusWindow(Gtk.Window): | |
| def __init__(self): | |
| Gtk.Window.__init__(self, title="Zues") | |
| self.set_border_width(5) | |
| self.set_default_size(400, 300) | |
| self.console = MyTerm(["/bin/bash", "-c", "zeus start"]) | |
| self.add(self.console) | |
| self.connect("delete-event", self.on_hide ) | |
| self.set_icon_name('abrt') | |
| def on_hide(self,*args): | |
| self.toogle(args) | |
| def toogle(self,event): | |
| if self.get_visible(): | |
| self.hide() | |
| else: | |
| self.show_all() | |
| class Launcher(Gtk.Button): | |
| def __init__(self, iconic, command, *args, **kwds): | |
| super(Launcher, self).__init__(*args, **kwds) | |
| icon = Gio.ThemedIcon(name=iconic) | |
| image = Gtk.Image.new_from_gicon(icon, Gtk.IconSize.BUTTON) | |
| self.add(image) | |
| self.connect("clicked", lambda x: subprocess.Popen(command) ) | |
| class RailsTab1(Gtk.VPaned): | |
| def __init__(self, *args, **kwds): | |
| super(RailsTab1, self).__init__(*args, **kwds) | |
| self.console1 = MyTerm(["/bin/bash", "-c", "tail -f log/development.log"]) | |
| self.add(self.console1) | |
| self.console2 = MyTerm(["/bin/bash", "-c", "zeus server"]) | |
| self.add(self.console2) | |
| self.set_position(200) | |
| class RailsTab2(Gtk.VPaned): | |
| def __init__(self, *args, **kwds): | |
| super(RailsTab2, self).__init__(*args, **kwds) | |
| self.console1 = MyTerm(["/bin/bash", "-c", "bundle exec guard"]) | |
| self.add(self.console1) | |
| self.console2 = MyTerm(["/bin/bash", "-c", "zeus console"]) | |
| self.add(self.console2) | |
| self.set_position(200) | |
| class RailsTab3(Gtk.VPaned): | |
| def __init__(self, *args, **kwds): | |
| super(RailsTab3, self).__init__(*args, **kwds) | |
| self.console1 = MyTerm(["/bin/bash"]) | |
| self.add(self.console1) | |
| self.console2 = MyTerm(["/bin/zsh"]) | |
| self.add(self.console2) | |
| self.set_position(60) | |
| class LivePreview(Gtk.VPaned): | |
| def __init__(self, *args, **kwds): | |
| super(LivePreview, self).__init__(*args, **kwds) | |
| scroller = Gtk.ScrolledWindow() | |
| web = WebKit.WebView() | |
| scroller.add(web) | |
| self.add(scroller) | |
| web.open(site_url) | |
| self.page = web | |
| class RSpecView(Gtk.VPaned): | |
| def __init__(self, *args, **kwds): | |
| super(RSpecView, self).__init__(*args, **kwds) | |
| scroller = Gtk.ScrolledWindow() | |
| web = WebKit.WebView() | |
| scroller.add(web) | |
| self.add(scroller) | |
| web.open("file://"+ rails_root + "/tmp/rspec.html") | |
| self.page = web | |
| class MyWindow(Gtk.Window): | |
| def __init__(self): | |
| Gtk.Window.__init__(self, title="Rails CI IDE") | |
| self.set_border_width(5) | |
| self.set_default_size(800, 500) | |
| # GTK Header | |
| hb = Gtk.HeaderBar() | |
| hb.set_show_close_button(True) | |
| hb.props.title = "Rails CI IDE" | |
| zeus_button = Gtk.Button() | |
| icon = Gio.ThemedIcon(name="zim") | |
| zeus_image = Gtk.Image.new_from_gicon(icon, Gtk.IconSize.BUTTON) | |
| zeus_button.add(zeus_image) | |
| hb.pack_end(zeus_button) | |
| self.zeus_button = zeus_button | |
| hb.pack_end( Launcher("git-cola",["git-cola"])) | |
| hb.pack_end( Launcher("gitg",["gitg"])) | |
| hb.pack_end( Launcher("nemo",["nemo", rails_root])) | |
| self.set_titlebar(hb) | |
| box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) | |
| Gtk.StyleContext.add_class(box.get_style_context(), "linked") | |
| button = Gtk.Button() | |
| button.add(Gtk.Arrow(Gtk.ArrowType.LEFT, Gtk.ShadowType.NONE)) | |
| button.connect("clicked", lambda w: self.prev_page()) | |
| box.add(button) | |
| button = Gtk.Button() | |
| button.add(Gtk.Arrow(Gtk.ArrowType.RIGHT, Gtk.ShadowType.NONE)) | |
| button.connect("clicked", lambda w: self.next_page()) | |
| box.add(button) | |
| hb.pack_start(box) | |
| vbox = Gtk.VBox(False, 0) | |
| self.add(vbox) | |
| # self.console = MyTerm(["/bin/bash", "-c", "zeus console"]) | |
| # vbox.add(self.console) | |
| self.tab1 = RailsTab1() | |
| label1 = Gtk.Label("Server") | |
| self.tab2 = RailsTab2() | |
| label2 = Gtk.Label("Console") | |
| self.tab3 = RailsTab3() | |
| label3 = Gtk.Label("Terminal") | |
| self.web1 = LivePreview() | |
| wlabel1 = Gtk.Label("Live: user") | |
| self.web2 = RSpecView() | |
| wlabel2 = Gtk.Label("CI View") | |
| notebook = Gtk.Notebook() | |
| notebook.set_tab_pos(Gtk.PositionType.BOTTOM) | |
| notebook.append_page(self.tab1, label1) | |
| notebook.append_page(self.tab3, label3) | |
| notebook.prepend_page(self.tab2, label2) | |
| notebook.append_page(self.web1, wlabel1) | |
| notebook.append_page(self.web2, wlabel2) | |
| vbox.add(notebook) | |
| self.notebook = notebook | |
| # Add status bar to vbox | |
| # self.statusbar = Gtk.Statusbar() | |
| # vbox.pack_start(self.statusbar, False, False, 0) | |
| self.set_icon_name('abrt') | |
| def next_page(self): | |
| num_pages = self.notebook.get_n_pages() | |
| cur_page = self.notebook.get_current_page() | |
| if num_pages - 1 == cur_page: | |
| self.notebook.set_current_page(0) | |
| else: | |
| self.notebook.next_page() | |
| def prev_page(self): | |
| cur_page = self.notebook.get_current_page() | |
| num_pages = self.notebook.get_n_pages() | |
| if cur_page == 0: | |
| self.notebook.set_current_page( num_pages - 1 ) | |
| else: | |
| self.notebook.prev_page() | |
| zeus = ZeusWindow() | |
| win = MyWindow() | |
| win.connect("delete-event", Gtk.main_quit) | |
| win.zeus_button.connect("clicked", zeus.toogle ) | |
| win.show_all() | |
| wm = pyinotify.WatchManager() # Watch Manager | |
| mask = pyinotify.IN_DELETE | pyinotify.IN_CREATE | pyinotify.IN_MODIFY | |
| class ReloadHandler(pyinotify.ProcessEvent): | |
| def process_IN_CREATE(self, event): | |
| self.process(event.pathname) | |
| def process_IN_DELETE(self, event): | |
| self.process(event.pathname) | |
| def process_IN_MODIFY(self, event): | |
| self.process(event.pathname) | |
| def process(self,pathname): | |
| extension = os.path.splitext(pathname)[1] | |
| win.web1.page.reload() | |
| print "realoading: " + pathname | |
| notifier1 = pyinotify.ThreadedNotifier(wm, ReloadHandler()) | |
| notifier1.start() | |
| wdd = wm.add_watch('app', mask, rec=True) | |
| # wdd = wm.add_watch('tmp/rspec.html', mask, rec=False) | |
| def file_changed (monitor, file, unknown, event): | |
| if event == Gio.FileMonitorEvent.CHANGES_DONE_HINT: | |
| win.web2.page.reload() | |
| print "realoading: specs" | |
| rspec_status = rails_root + "/tmp/rspec.html" | |
| monitor_file = Gio.File.new_for_path(rspec_status) | |
| monitor = monitor_file.monitor_file(Gio.FileMonitorFlags.NONE, None) | |
| monitor.connect ("changed", file_changed) | |
| import signal | |
| signal.signal(signal.SIGINT, signal.SIG_DFL) | |
| Gtk.main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment