Commits

Moises Henriquez committed 65f2609

Adding sqlite dbase and front end to manage job queue

  • Participants
  • Parent commits a383cb6

Comments (0)

Files changed (8)

 syntax: glob
 *.py~
 *.pyc
+*.swp

File bbot.py

-#!/usr/bin/env python
-
-#    This file is part of vpackager.
-#
-#    vpackager is free software: you can redistribute it and/or modify
-#    it under the terms of the GNU General Public License v2 as published by
-#    the Free Software Foundation.
-#
-#    vpackager is distributed in the hope that it will be useful,
-#    but WITHOUT ANY WARRANTY; without even the implied warranty of
-#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#    GNU General Public License for more details.
-#
-#    You should have received a copy of the GNU General Public License
-#    along with vpackager.  If not, see <http://www.gnu.org/licenses/>.
-
-import os
-import subprocess as sp
-import dbconn as db
-
-buildproc = None
-
-class AutoTools(object):
-    def __init__(self, srcpath, app, version):
-        self.path = srcpath
-        self.config = ['--prefix=/usr',
-            '--sysconfdir=/etc', '--mandir=/usr/man',
-            '--disable-debug']
-        if os.uname()[-1] == 'x86_64':
-            self.cflags = '-O2 -fpic'
-            self.arch = os.uname()[-1]
-        elif os.uname()[-1] in ('i386', 'i486', 'i586', 'i686'):
-            self.arch = 'i586'
-            self.cflags = '-O2 -march=i586 -mtune=i686'
-        elif os.uname()[-1] == 'powerpc':
-            self.cflags='-O2'
-            self.arch = os.uname()[-1]
-        self.path = srcpath
-        self.workdir = os.path.join(srcpath, '%s-%s'%(app, version))
-        self.app = app
-        self.version = version
-
-    def _open_log(self):
-        self.log = open(os.path.join(self.path, 'bbot_build.log'), 'a')
-    def _close_log(self):
-        return self.log.close()
-    def do_log(self, log):
-        self._open_log()
-        self.log.write(log)
-        self._close_log()
-        
-    def configure(self):
-        os.chdir(self.workdir)
-        cstr = './configure ' + ' '.join(self.config)
-        buildproc = sp.Popen(cstr.split(), stdout=sp.PIPE, stderr=sp.STDOUT)
-        output = buildproc.communicate()[0]
-        self.do_log(output)
-        return buildproc.returncode
-    
-    def compile(self):
-        os.chdir(self.workdir)
-        buildproc = sp.Popen([
-            'make'], stdout=sp.PIPE, stderr=sp.STDOUT)
-        output = buildproc.communicate()[0]
-        self.do_log(output)
-        return buildproc.returncode
-    
-    def mkinstall(self):
-        os.chdir(self.workdir)
-        pkg = os.path.join(self.workdir, 'PKG')
-        os.makedirs(pkg)
-        self.pkgdir = pkg
-        buildproc = sp.Popen([
-            'make','DESTDIR=%s'% pkg, 'install'],
-            stdout=sp.PIPE, stderr=sp.STDOUT)
-        output = buildproc.communicate()[0]
-        self.do_log(output)
-        return buildproc.returncode
-    def package(self, buildno='1', tag=''):
-        pkgdir = os.path.join(self.workdir, 'PKG')
-        try :
-            os.makedirs(pkgdir)
-        except :
-            pass
-        self.pkgdir = pkgdir
-        os.chdir(self.pkgdir)
-        pname = '%s-%s-%s-%s%s.%s'% (
-            self.app, self.version, self.arch, buildno, tag, 'tlz')
-            
-        buildproc = sp.Popen(['makepkg', '-p', '-l', 'y', '-c', 'n',
-            os.path.join(self.path, pname)],
-            stdout = sp.PIPE, stderr=sp.STDOUT)
-        output = buildproc.communicate()[0]
-        self.do_log(output)
-        return buildproc.returncode
-    
-class AutoMake(AutoTools):
-    def __init__(self, srcpath, app, version):
-        AutoTools.__init__(self, srcpath, app, version)
-    
-    def configure(self):
-        ### Goes straight to make, so always return 0
-        return 0
-
-class Python(object):
-    def __init__(self, srcpath, app, version):
-        self.path = srcpath
-        #self.workdir = srcpath
-        self.workdir = os.path.join(srcpath, '%s-%s'%(app, version))
-        #self.tmpdir = os.path.join(srcpath, '%s-%s'%(app,version))
-        ### Open the build log and leave the stream open for the rest of the
-        ### build process
-        self.app = app
-        self.version = version
-        #self.log = open(os.pardir.join(srcpath, 'bbot_build.log'), 'a')
-    
-    def _open_log(self):
-        self.log = open(os.path.join(self.path, 'bbot_build.log'), 'a')
-    def _close_log(self):
-        return self.log.close()
-    def do_log(self, log):
-        self._open_log()
-        self.log.write(log)
-        self._close_log()
-    def configure(self):
-        self._open_log()
-        os.chdir(self.workdir)
-        buildproc = sp.Popen(['python', 'setup.py', 'build'],
-            stdout=sp.PIPE, stderr=sp.STDOUT)
-        output = ''.join(buildproc.stdout.readlines())
-        self.do_log(output)
-        return buildproc.returncode
-    def compile(self):
-        return 0
-    def mkinstall(self):
-        pkg = os.path.join(self.workdir, 'PKG')
-        os.makedirs(pkg)
-        self.pkgdir = pkg
-        os.chdir(self.workdir)
-        #os.chdir(self.pkgdir)
-        buildproc = sp.Popen(['python', 'setup.py', 'install',
-        '--root=%s'% self.pkgdir], stdout=sp.PIPE, stderr=sp.STDOUT)
-        output = ''.join(buildproc.stdout.readlines())
-        self.do_log(output)
-        return buildproc.returncode
-    def package(self, buildno='1', tag=''):
-        arch = os.uname()[-1]
-        if arch in ('i386', 'i486', 'i586', 'i686'):
-            arch = 'i586'
-        os.chdir(self.pkgdir)
-        pkgname = '%s-%s-%s-%s%s.%s'% (
-            self.app, self.version, arch, buildno, tag, 'tlz')
-        buildproc = sp.Popen(
-            ['makepkg', '-p', '-l', 'y', '-c', 'n',
-            os.path.join(self.path, pkgname)], 
-            stdout=sp.PIPE, stderr=sp.STDOUT)
-        output = ''.join(buildproc.stdout.readlines())
-        self.do_log(output)
-        return buildproc.returncode
-
-    
-        
-class Source(object):
-    def __init__(self, path, app='', version=''):
-        tmpdir='/tmp/bbot'
-        self.path = path
-        
-        self.buildtool = None
-        split=self._split_filename()
-        self.app = app
-        self.version = version
-        if not app: self.app = split[0]
-        if not version: self.version = split[1]
-        self.srcpath = os.path.join(tmpdir, self.app, self.version)
-        self.type = self._get_type()
-    def configure(self):
-        return self.buildtool.configure()
-    def compile(self):
-        return self.buildtool.compile()
-    def mkinstall(self):
-        return self.buildtool.mkinstall()
-    def package(self):
-        return self.buildtool.package()
-    
-
-    
-    
-    def _split_filename(self):
-        fn = os.path.split(self.path)[-1]
-        sp = os.path.splitext(fn)
-        if sp[0].endswith('.tar'):
-            rname = sp[0][:-4]
-        return rname.rsplit('-',2)
-        
-        
-    def get_type(self):
-        return self.type
-        
-    def _get_type(self):
-        l = sp.Popen([
-            'tar', '-tf', self.path], stdout=sp.PIPE,
-            stderr=sp.PIPE).communicate()[0]
-        if 'configure' in l:
-            self.buildtool = AutoTools(self.srcpath, self.app, self.version)
-            return 'autotools'
-        if 'Makefile' in l:
-            self.buildtool = AutoMake(self.srcpath, self.app, self.version)
-            return 'automake'
-        if 'setup.py' in l:
-            self.buildtool = Python(self.srcpath, self.app, self.version)
-            return 'python'
-        return None
-    
-    def extract(self, dir=''):
-        if not dir: dir = self.srcpath
-        if not os.path.isdir(self.srcpath): os.makedirs(self.srcpath)
-        self.logfile = os.path.join(self.srcpath, 'bbot_build.log')
-        self.logstream = open(self.logfile, 'w')            
-        
-        ext = os.path.splitext(self.path)[-1]
-        if ext in ('.gz', '.bz2'):
-            buildproc = sp.Popen(['tar', 'xfv', self.path, '-C', dir],
-            stdout=sp.PIPE, stderr=sp.STDOUT)
-            output = buildproc.communicate()[0]
-            self.logstream.write(output)
-            self.logstream.close()
-           
-            return buildproc.returncode
-
-    def log_build_activity(self, result):
-        stdout = self.logfile
-        srcpath = self.path
-        res = result
-        
-        return db.log_build_attempt(srcpath, stdout, result)
-    

File bot.py

-#!/usr/bin/env python
-
-#    This file is part of vpackager.
-#
-#    vpackager is free software: you can redistribute it and/or modify
-#    it under the terms of the GNU General Public License v2 as published by
-#    the Free Software Foundation.
-#
-#    vpackager is distributed in the hope that it will be useful,
-#    but WITHOUT ANY WARRANTY; without even the implied warranty of
-#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#    GNU General Public License for more details.
-#
-#    You should have received a copy of the GNU General Public License
-#    along with vpackager.  If not, see <http://www.gnu.org/licenses/>.
-
-import threading
-import time
-import gobject
-import gtk
-import bbot
-import dbconn
-import dialogs
-
-gtk.gdk.threads_init()
-todo = None #dbconn.refresh_todo()
-
-_busy = False
-
-class Monitor(threading.Thread):
-    def __init__(self, label):
-        super(Monitor, self).__init__()
-        self.label = label
-        self.quit = False
-        global _busy
-        
-    def update_label(self, txt):
-        self.label.set_text(txt)
-        #return False
-    
-    def run(self):
-        counter = 0
-        global _busy
-        while _busy is True:
-           gobject.idle_add(self.update_label,'Working')
-         
-           time.sleep(1)
-
-        gobject.idle_add(self.update_label,'Idle')
-        time.sleep(1)
-        
-
-class tbp(threading.Thread):
-    '''Threaded build process.'''
-    def __init__(self, src):
-        global _busy
-        global w
-        super(tbp, self).__init__()
-        self.src = src
-        _busy  = True
-
-        ### Take a split second to log the activity to the database
-        sql = 'INSERT INTO en_history (srcpath, buildstart, result)' + \
-        " values ('%s',%s,'Running')"% (src.path, 'CURRENT_TIMESTAMP')
-        dbconn.push_data(sql)
-        ### Another update is made when the process ends in exit_build
-        
-    def supdate(self, txt):
-        w.info_label1.set_text(txt)
-        w.info_label2.set_text(self.src.app)
-        #return False
-    def run(self):
-        global _busy
-        
-        gobject.idle_add(self.supdate,'Extracting')
-        if self.src.extract() > 0:
-            _busy = False
-        
-            gobject.idle_add(self.supdate,'Etraction error')
-            return self.exit_build('Fail', 1)
-        
-        gobject.idle_add(self.supdate, 'Running configure')
-        if self.src.configure() > 0:
-            _busy = False
-        
-            gobject.idle_add(self.supdate, 'configure error')
-            return self.exit_build('Fail', 1)
-        
-        gobject.idle_add(self.supdate, 'RUnning make')
-        if self.src.compile() > 0:
-            _busy = False
-        
-            gobject.idle_add(self.supdate, 'Compilation error')
-            return self.exit_build('Fail', 1)
-        
-        gobject.idle_add(self.supdate, 'Installing')
-        if self.src.mkinstall() > 0:
-            _busy = False
-        
-            gobject.idle_add(self.supdate, 'installation error')
-            return self.exit_build('Fail', 1)
-        
-        gobject.idle_add(self.supdate, 'Packaging')
-        if self.src.package() > 0:
-            _busy = False
-        
-            gobject.idle_add(self.supdate, 'Error packaging')
-            return self.exit_build('Fail', 1)
-        
-        gobject.idle_add(self.supdate, 'Packaged')
-        
-        _busy = False
-        return self.exit_build('Success', 0)
-        
-        
-    def exit_build(self, result, retval):
-        logfile = self.src.logfile
-
-
-        sql = 'UPDATE en_history SET stdout="%s", buildend=%s, result="%s" WHERE srcpath="%s" AND result="Running"'%(logfile,
-        'CURRENT_TIMESTAMP',result, self.src.path)
-        
-        sql2 = 'DELETE FROM todo WHERE srcpath="%s"'% self.src.path
-
-        dbconn.push_data(sql)  ## Update status to finished with result
-        dbconn.push_data(sql2) ## Remove from todo list
-    
-        return retval
-        
-
-class dispatcher(threading.Thread):
-    '''Create threaded build objects one at a time and deploy them'''
-    def __init__(self):
-        global todo
-        global _busy
-        super(dispatcher, self).__init__()
-
-    def run(self):
-        global todo
-        global _busy
-        for task in todo:
-            src = bbot.Source(task[1])
-            while _busy is True:
-                time.sleep(1)
-            threaded_build = tbp(src)
-            print '[dispatch] %s'% task[1]
-            threaded_build.start()
-        #print 'Finished building'
-
-    def update_status(self, status):
-        w.info_label3.set_text(status)
-
-class guiMonitor(threading.Thread):
-    '''Monitor the gridlist in the GUI'''
-    def __init__(self, f):
-        self.f = f
-        threading.Thread.__init__(self, name = 'GuiMonitor')
-    
-    def run(self):
-        global _busy
-        while _busy is True:
-            time.sleep(5) # Refresh the GUI every 5 seconds
-            self.f()
-        
-
-class mWindow(gtk.Window):
-    '''Main top level GUI'''
-    def treeview_click(self, treeview):
-    
-        sel,itr = treeview.get_selection().get_selected()
-        id = self._todo_list.get_value(itr, 0)
-        src_ = self._todo_list.get_value(itr, 1)
-        dsc_ = self._todo_list.get_value(itr, 2)
-        
-        
-        self.selected_job = id
-        self.selected_job_src = src_
-        self.selected_job_dsc = dsc_
-        
-    def delete_job(self, widget, job_id):
-        '''Delete a job'''
-        if not self.selected_job: 
-            dia = dialogs.info(message='Please select a job first', parent=self)
-            if dia.run(): dia.destroy()
-            return
-        ### Present some kind of dialog to verify before you do this
-        conf = dialogs.question(parent=self,
-        question = 'Are you sure you want to delete job %s?' %self.selected_job )
-        
-        res = conf.run()
-        conf.destroy()
-        if res == gtk.RESPONSE_CANCEL:
-            return
-        
-        ### Only continue if the action has been verified by the dialog.
-        sql = "DELETE FROM todo WHERE id='%s'"% self.selected_job
-        dbconn.push_data(sql)
-        self._todo_list.clear()
-        self.refresh_task_list()
-    def __init__(self):
-        self.selected_job = None
-        self.selected_job_dsc = None
-        self.selected_job_src = None
-        treestore = gtk.TreeStore(str, str, str)
-        self._todo_list = treestore
-        
-        
-        # Setup a thread that monitors the database so that when a build is done
-        # the gui is automagically updated.
-        # This thread only runs when the build process is running.
-        
-        gmon = guiMonitor(self.refresh_task_list)
-        gmon.start()
-        
-        
-        ## Get the todo list from the database:
-        _lst = dbconn.refresh_todo()
-        if _lst == 1 or _lst is None:
-            msgerr = dialogs.error(message='Unable to connect to mysql server', parent=self)
-            if msgerr.run(): msgerr.destroy()
-            import sys
-            sys.exit()
-        else:
-            
-            for row in _lst:
-                treestore.append(None, [row[0], row[1], row[2]])
-
-        
-        gtk.Window.__init__(self, gtk.WINDOW_TOPLEVEL)
-        self.set_default_size(600,400)
-        self.set_position(gtk.WIN_POS_CENTER)
-        self.set_property('title', 'buildbot')
-        body = gtk.VBox(False, 4)
-        banner = gtk.Label()
-        banner.set_property('use-markup', True)
-        banner.set_property('label', 'Welcome to the buildbot')
-        banner.set_property('xalign', 0.0)
-        
-        hbanner = gtk.HBox(False, 4)
-        hbanner.pack_start(banner, True, True, 4)
-        body.pack_start(hbanner, False, False, 0)
-        blank = gtk.Label()
-        body.pack_start(blank, False, False, 4)
-        frm_todo = gtk.Frame('Scheduled Builds')
-        ### ------------------ Scheduled builds list -------------------##
-        frm_todo_int = gtk.VBox(False, 4)
-        
-        sw = gtk.ScrolledWindow()
-        
-        
-
-        tv = gtk.TreeView(treestore)
-        tv.connect('cursor-changed', self.treeview_click)
-        col = gtk.TreeViewColumn('Task ID')
-        col1 = gtk.TreeViewColumn('Source URI')
-        col2 = gtk.TreeViewColumn('Description URI')
-        tv.append_column(col)
-        tv.append_column(col1)
-        tv.append_column(col2)
-        
-        cell = gtk.CellRendererText()
-        cell1 = gtk.CellRendererText()
-        cell2 = gtk.CellRendererText()
-        col.pack_start(cell, True)
-        col1.pack_start(cell1, True)
-        col2.pack_start(cell2, True)
-        col.add_attribute(cell, 'text', 0)
-        col1.add_attribute(cell1, 'text', 1)
-        col2.add_attribute(cell2, 'text', 2)
-
-        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
-        sw.add(tv)
-        ### End of tree, Lets add some action buttons in the same frame
-        
-        toolbar_frame = gtk.Frame()
-        task_toolbar = gtk.HBox(False, 4)
-        bt_addtask = gtk.Button(label='New Job')
-        bt_addtask.connect('clicked', self._show_add_form)
-        img = gtk.Image()
-        img.set_from_stock(gtk.STOCK_ADD, gtk.ICON_SIZE_BUTTON)
-        bt_addtask.set_image(img)
-        
-        img1 = gtk.Image()
-        bt_remove = gtk.Button('Delete Job')
-        img1.set_from_stock(gtk.STOCK_REMOVE, gtk.ICON_SIZE_BUTTON)
-        bt_remove.set_image(img1)
-        bt_remove.connect('clicked', self.delete_job, self.selected_job)
-        
-        bt_edit = gtk.Button('Edit Job')
-        bt_edit.connect('clicked', self._show_edit_job)
-        img2 = gtk.Image()
-        img2.set_from_stock(gtk.STOCK_EDIT, gtk.ICON_SIZE_BUTTON)
-        bt_edit.set_image(img2)
-        
-        lhblank = gtk.Label()
-        rhblank = gtk.Label()
-        task_toolbar.pack_start(lhblank, True, True, 0)
-        task_toolbar.pack_start(bt_addtask, False, False, 2)
-        task_toolbar.pack_start(bt_remove, False, False, 2)
-        task_toolbar.pack_start(bt_edit, False, False, 2)
-        task_toolbar.pack_start(rhblank, True, True, 0)
-        toolbar_frame.add(task_toolbar)
-        frm_todo_int.pack_start(sw, True, True, 4)
-        frm_todo_int.pack_start(toolbar_frame, False, True, 4)
-        
-        #frm_todo_int.pack_start(int_lbl, True, True, 4)
-        frm_todo.add(frm_todo_int)
-        
-        body.pack_start(frm_todo, True, True, 4)
-        ### ------------------- End of scheduled buidls list -----------##
-        frm_history = gtk.Frame('Current bot status')
-        frm_history_int = gtk.VBox(False, 4)
-        frm_history.add(frm_history_int)
-        hist_lbl = gtk.Label('current status information here.')
-        blnk = gtk.Label()
-        frm_history_int.pack_start(hist_lbl, True, True, 4)
-        frm_history_int.pack_start(blnk, True, True, 4)
-        
-        body.pack_start(frm_history, False, False, 4)
-        
-        self.statusbar = gtk.Statusbar()
-        body.pack_start(self.statusbar, False, True, 4)
-
-
-        
-        self.info_label1 = gtk.Label()
-        self.info_label2 = gtk.Label()
-        self.info_label3 = gtk.Label()
-        
-        self.add(body)
-        self.connect('destroy', gtk.main_quit)
-    
-    def _show_edit_job(self, widget):
-        if not self.selected_job:
-            err = dialogs.info(message='Nothing selected yet', parent=self)
-            if err.run(): err.destroy()
-            return
-        
-        ej = JobEdit(parent=self,
-            id = self.selected_job,
-            srcpath = self.selected_job_src,
-            descpath = self.selected_job_dsc)
-        
-        res = ej.run()
-        ej.destroy()
-        if res == gtk.RESPONSE_CANCEL:
-            return
-    
-        self._do_edit_job(self.selected_job,
-            ej.srcpath, ej.descpath)
-        
-        
-    def _do_edit_job(self, id, srcpath, descpath):
-        sql = "UPDATE todo SET srcpath='%s' WHERE id='%s'"% (srcpath, id)
-        sql2 = "UPDATE todo SET descpath='%s' WHERE id='%s'"% (descpath, id)
-        
-        dbconn.push_data(sql)
-        dbconn.push_data(sql2)
-        
-        self.refresh_task_list()
-        
-    def _show_add_form(self, widget):
-
-        aj = _AddJobWindow(parent=self)
-        res = aj.run()
-        if res == gtk.RESPONSE_ACCEPT:
-            self.add_job(aj.srcpath, aj.descpath)
-        
-        aj.destroy()
-    
-    def add_job(self, srcpath, descpath):
-        sql = 'INSERT INTO todo (srcpath, descpath) VALUES ("%s","%s")'% \
-        (srcpath, descpath)
-        ## Push the sql data into the database
-        dbconn.push_data(sql)
-        ## Refresh the GUI
-        self.refresh_task_list()
-        
-        
-    
-    def refresh_task_list(self):
-        _lst = dbconn.refresh_todo()
-        self._todo_list.clear()
-        for row in _lst:
-            self._todo_list.append(None, [row[0], row[1], row[2]])
-
-
-
-
-        
-class _AddJobWindow(gtk.Dialog):
-    '''Add task dialog'''
-    def __init__(self, parent):
-        self.srcpath = ''
-        self.descpath = ''
-        gtk.Dialog.__init__(self, parent=parent, buttons=(gtk.STOCK_OK, 
-            gtk.RESPONSE_ACCEPT, gtk.STOCK_CANCEL, 
-            gtk.RESPONSE_CANCEL), title='Add new Job')
-        self.set_default_size(600,200)
-        self.resize(600,200)
-        self.set_position(gtk.WIN_POS_CENTER)
-        dbody = self.vbox
-        
-        hdr = gtk.Label()
-        self.header = hdr
-        hdr.set_property('use-markup', True)
-        hdr.set_property('label', 'Add new job')
-        hdr.set_property('xalign', 0.0)
-        dbody.pack_start(hdr, True, True, 2)
-        
-        blnk = gtk.Label()
-        dbody.pack_start(blnk)
-        srcline = gtk.HBox(False, 4)
-        dbody.pack_start(srcline, False, False, 2)
-        src_line_lbl = gtk.Label()
-        src_line_lbl.set_property('xalign', 0.0)
-        src_line_lbl.set_property('label', 'URI to Source')
-        srcline.pack_start(src_line_lbl, False, False, 0)
-        src_line_txt = gtk.Entry()
-        srcline.pack_start(src_line_txt, True, True, 2)
-        src_line_btn = gtk.Button(stock=gtk.STOCK_OPEN)
-        src_line_btn.connect('clicked', self.load_src)
-        srcline.pack_start(src_line_btn, False, False, 2)
-        self._src_entry = src_line_txt
-        self._src_entry.connect('changed', self._src_entry_changed)
-        
-        descline = gtk.HBox(False, 4)
-        dsc_line_lbl = gtk.Label()
-        dsc_line_lbl.set_property('xalign', 0.0)
-        dsc_line_lbl.set_property('label', 'URI to Description')
-        descline.pack_start(dsc_line_lbl, False, False, 0)
-        dsc_line_txt = gtk.Entry()
-        descline.pack_start(dsc_line_txt, True, True, 2)
-        dsc_line_btn = gtk.Button(stock=gtk.STOCK_OPEN)
-        dsc_line_btn.connect('clicked', self.load_desc)
-        descline.pack_start(dsc_line_btn, False, False, 2)
-        self._desc_entry = dsc_line_txt
-        self._desc_entry.connect('changed', self._desc_entry_changed)
-        
-        dbody.pack_start(descline, False, False, 2)
-        
-
-        self.show_all()
-    
-    def _src_entry_changed(self, widget):
-        self.srcpath = widget.get_text()
-        
-    def _desc_entry_changed(self, widget):
-        self.descpath = widget.get_text()
-    
-    def load_src(self, widget):
-        dia = gtk.FileChooserDialog(buttons = (gtk.STOCK_OPEN,
-        gtk.RESPONSE_ACCEPT, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL))
-        dia.set_title('Select source file')
-        filt = gtk.FileFilter()
-        filt.set_name('Compressed Archives')
-        filt.add_pattern('*.tar.*')
-        dia.add_filter(filt)
-        
-        ans = dia.run()
-        if ans == gtk.RESPONSE_ACCEPT:
-            self.srcpath = dia.get_filename()
-        else:
-            self.srcpath= ''
-        
-        self._src_entry.set_text(self.srcpath)
-        dia.destroy()
-    
-    def load_desc(self, widget):
-        dia = gtk.FileChooserDialog(buttons = (gtk.STOCK_OPEN,
-        gtk.RESPONSE_ACCEPT, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL))
-        dia.set_title('Select Description File')
-        
-        ans = dia.run()
-        if ans == gtk.RESPONSE_ACCEPT:
-            self.descpath = dia.get_filename()
-        else:
-            self.descpath = ''
-        
-        self._desc_entry.set_text(self.descpath)
-        dia.destroy()
-        
-class JobEdit(_AddJobWindow):
-    '''Edit task dialog'''
-    def __init__(self, parent, id, srcpath, descpath):
-        _AddJobWindow.__init__(self, parent=parent)
-        self.set_title('Edit Task')
-        self._src_entry.set_text(srcpath)
-        self._desc_entry.set_text(descpath)
-        self.header.set_text('Edit existing task on to-do list')
-
-if __name__ == '__main__':
-    w = mWindow()
-    w.statusbar.push(0, 'Idle')
-    w.show_all()
-    tmon = Monitor(w.info_label1)
-    tmon.start()
-    gtk.gdk.threads_enter()
-    gtk.main()
-    gtk.gdk.threads_leave()
-
-    _busy = False

File dbconn.py

-#!/usr/bin/env python
-
-#    This file is part of vpackager.
-#
-#    vpackager is free software: you can redistribute it and/or modify
-#    it under the terms of the GNU General Public License v2 as published by
-#    the Free Software Foundation.
-#
-#    vpackager is distributed in the hope that it will be useful,
-#    but WITHOUT ANY WARRANTY; without even the implied warranty of
-#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#    GNU General Public License for more details.
-#
-#    You should have received a copy of the GNU General Public License
-#    along with vpackager.  If not, see <http://www.gnu.org/lici
-
-import MySQLdb as dbase
-from _mysql_exceptions import *
-
-db = None
-
-def open_connection():
-    """ Convenience method to open the connection to the database"""
-    global db
-    try:
-        db = dbase.connect(host='localhost', user='root', db='buildbot')
-    except OperationalError:
-        print "Unable to open connection to mysql database. is mysql running?"
-        return 1
-    return 0
-
-def close_connection():
-    global db
-    db.close()
-    return 0
-def refresh_todo():
-    '''Read the todo list from the database'''
-    global db
-    if open_connection() > 0: return 1
-    if db.cursor is None: return 1
-    cursor = db.cursor()
-    cursor.execute("""SELECT * FROM todo ORDER BY id""")
-    res = []
-    for row in cursor.fetchall():
-        res.append(row)
-    cursor.close()
-    
-    close_connection()
-    
-    return res
-
-def push_data(sql_data):
-    global db
-    
-    open_connection()
-    cursor = db.cursor()
-    cursor.execute(sql_data)
-    db.commit()
-    close_connection()
-    
-
-def refresh_build_history():
-    '''Read the build history from the database'''
-    global db
-    open_connection()
-    if db.cursor is None: return 1
-    cursor = db.cursor()
-    cursor.execute("""SELECT * FROM en_history ORDER BY id""")
-    res = []
-    for row in cursor.fetchall():
-        res.append(row)
-    cursor.close()
-    close_connection()
-    return res
-
-def log_build_attempt(srcpath, stdoutpath, buildresult):
-    global db
-    open_connection()
-    cursor = db.cursor()
-    if db.cursor is None: return 1
-    cursor.execute("""INSERT INTO history (srcpath, stdout, result) values (
-        '%s','%s','%s')"""% (srcpath, stdoutpath, buildresult))
-    cursor.execute("""DELETE FROM todo WHERE srcpath='%s'"""% srcpath)
-    db.commit()
-    close_connection()
-    return 0
-    
-
-if __name__ == '__main__':
-    print refresh_todo()
-    
-    

File jobmanage.py

+#!/usr/bin/env python
+
+#    This file is part of vpackager.
+#
+#    vpackager is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License v2 as published by
+#    the Free Software Foundation.
+#
+#    vpackager is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with vpackager.  If not, see <http://www.gnu.org/licenses/>.
+
+import gtk
+from vpackager import dbutils
+from vpackager import guitools
+from vpackager import buildutils
+
+__author__ = 'M0E-lnx'
+__author_email__ = 'moc.liamg@xnl.E0M'[::-1]
+__version__ = '0.1'
+
+
+class Main(gtk.VBox):
+    '''job manager main container'''
+    def __init__(self):
+        gtk.VBox.__init__(self)
+        hbtop = gtk.HBox()
+        self.pack_start(hbtop, False, True, 4)
+        lbtop = gtk.Label('Manage job queue')
+        hbtop.pack_start(lbtop, True, True, 2)
+
+        scrl = gtk.ScrolledWindow()
+        scrl.set_policy(gtk.POLICY_AUTOMATIC,
+                gtk.POLICY_AUTOMATIC)
+        scrl.add(self._get_tree())
+        self._fill_tree_with_queue()
+        self.pack_start(scrl, True, True, 8)
+        hbbot = gtk.HBox()
+        self.pack_start(hbbot, False, True, 4)
+        self.btAdd = gtk.Button(stock=gtk.STOCK_ADD)
+        self.btRem = gtk.Button(stock=gtk.STOCK_REMOVE)
+        self.btRem.connect('clicked', self._btDeleteClick)
+        self.btAdd.connect('clicked', self._btAddClick)
+        frmJobCtrl = gtk.Frame('Job Control')
+        jobsvbox = gtk.HBox()
+        frmJobCtrl.add(jobsvbox)
+        jobsvbox.pack_start(self.btAdd, False, False, 2)
+        jobsvbox.pack_start(self.btRem, False, False, 2)
+        hbbot.pack_start(frmJobCtrl, True, True , 4)
+
+    def _btAddClick(self, widget=None):
+        dia = guitools.JobAddDialog(parent=self)
+        res = dia.run()
+        dia.hide()
+        if res == gtk.RESPONSE_OK:
+            app = dia.app
+            ver = dia.ver
+            desc = dia.DescURI
+            srcuri = dia.SrcURI
+            rel = dia.release
+            dia.destroy()
+            dbutils.NewJob(app, ver, srcuri, desc, rel)
+            return self._update_queue()
+
+    def _btDeleteClick(self, widget=None):
+        if self._selected_jobid:
+            dbutils.RemoveJob(self._selected_jobid)
+            self._update_queue()
+
+    def _update_queue(self):
+        self.tree.set_model(
+                gtk.ListStore(int, str, str, str, str, str))
+        lst = dbutils.GetQueue()
+        for entry in lst:
+            self.tree.get_model().append(entry)
+
+    def _get_tree(self):
+        mod = gtk.ListStore(int, str, str, str, str, str)
+        self.tree = gtk.TreeView(model = mod)
+        self.tree.connect('cursor-changed', self._tree_click_event)
+
+        i = 0
+        for field in ('ID', 'Application', 'Version',
+                'Source URI', 'Description', 'Release'):
+            col = gtk.TreeViewColumn(field)
+            cr = gtk.CellRendererText()
+            col.pack_start(cr)
+            col.add_attribute(cr, 'text', i)
+            self.tree.append_column(col)
+            i += 1
+
+
+        return self.tree
+
+    def _tree_click_event(self, tree=None):
+        sel = tree.get_selection()
+        (model, iter) = sel.get_selected()
+        selrow = tree.get_model()[iter][0]
+
+        self._selected_jobid = selrow
+
+
+    def _fill_tree_with_queue(self):
+        tm = self.tree.get_model()
+        q = dbutils.GetQueue()
+        for item in q:
+            tm.append(item)
+
+if __name__ == '__main__':
+    w = gtk.Window(gtk.WINDOW_TOPLEVEL)
+    w.connect('destroy', gtk.main_quit)
+    w.set_title('Job Queue Manager')
+    w.set_size_request(600, 400)
+    w.add(Main())
+    w.show_all()
+    gtk.gdk.threads_init()
+    gtk.gdk.threads_enter()
+    gtk.main()
+    gtk.gdk.threads_leave()

File vpackager/__init__.py

+#!/usr/bin/env python
+
+#    This file is part of vpackager.
+#
+#    vpackager is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License v2 as published by
+#    the Free Software Foundation.
+#
+#    vpackager is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with vpackager.  If not, see <http://www.gnu.org/licenses/>.
+
+__author__ = 'M0E-lnx'
+__author_email__ = 'moc.liamg@xnl.E0M'[::-1]
+__version__ = '0.1'
+
+"""Tools collection to easily build software from source using a fimiliar
+GTK front end with the stability of sbbuilder"""

File vpackager/dbutils.py

+#!/usr/bin/env python
+
+#    This file is part of vpackager.
+#
+#    vpackager is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License v2 as published by
+#    the Free Software Foundation.
+#
+#    vpackager is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with vpackager.  If not, see <http://www.gnu.org/licenses/>.
+
+import sqlite3
+
+__author__ = 'M0E-lnx'
+__author_email__ = 'moc.liamg@xnl.E0M'[::-1]
+__version__ = '0.1'
+
+db = sqlite3.connect('/tmp/vpackager.db')
+
+def __create_queue_table():
+    c = db.cursor()
+    c.execute("""create table queue
+    (id integer primary key autoincrement,
+    app text, ver text, srcURI text, descURI text, release text)""")
+    db.commit()
+    c.close()
+
+    return
+
+def __create_history_table():
+    c = db.cursor()
+    c.execute('''
+    create table history
+    (id integer primary key autoincrement,
+    app text, ver text, source text, desc text, buildstart text,
+    buildend text, status text, stdout text)''')
+    db.commit()
+    c.close()
+
+    return
+
+def NewJob(app, ver, srcURI, descURI, release):
+    t = (app, ver, srcURI, descURI, release)
+    c = db.cursor()
+    c.execute("insert into queue (app, ver, srcURI, descURI, release) values (?,?,?,?,?)", t)
+
+    db.commit()
+    c.close()
+
+def RemoveJob(_id):
+    c = db.cursor()
+    t = (_id,)
+    c.execute('delete from queue where id=?', t)
+    db.commit()
+    c.close()
+
+def LogJobStart(jobid, starttime):
+    return
+
+
+def GetQueue():
+    c = db.cursor()
+    ret = c.execute('select * from queue').fetchall()
+    c.close()
+    return ret
+
+
+
+

File vpackager/guitools.py

+#!/usr/bin/env python
+
+#    This file is part of vpackager.
+#
+#    vpackager is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License v2 as published by
+#    the Free Software Foundation.
+#
+#    vpackager is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with vpackager.  If not, see <http://www.gnu.org/licenses/>.
+
+import gtk
+import os
+import buildutils
+
+__author__ = 'M0E-lnx'
+__author_email__ = 'moc.liamg@xnl.E0M'[::-1]
+__version__ = '0.1'
+
+class vButton(gtk.Button):
+    '''Button class that can use a stock image with a custon label'''
+    def __init__(self, stock=None, label=''):
+        gtk.Button.__init__(self)
+        if stock is not None:
+            img = gtk.Image()
+            img.set_from_stock(stock, gtk.ICON_SIZE_BUTTON)
+            self.set_image(img)
+
+        self.set_label(label)
+
+class JobAddDialog(gtk.Dialog):
+    '''Dialog window used to add a job to the queue'''
+    def __init__(self, title='Add Job', parent=None):
+        gtk.Dialog.__init__(self)
+        self.SrcURI = None
+        self.DescURI = None
+        self.app = None
+        self.ver = None
+        self.release = 1
+        self.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK)
+        self.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
+        self.set_has_separator(True)
+        self.set_default_response(gtk.RESPONSE_OK)
+        body = self.get_content_area()
+        self.set_title('Add New Job')
+        self.set_size_request(500,300)
+        frmSrc = gtk.Frame('Source Archive')
+        body.pack_start(frmSrc, False, True, 8)
+        hsrc = gtk.HBox()
+        frmSrc.add(hsrc)
+        self.srcentry = gtk.Entry()
+        self.srcentry.connect('changed', self._src_entry_event)
+        hsrc.pack_start(self.srcentry, True, True, 2)
+        self.btBrowse = vButton(stock=gtk.STOCK_OPEN,
+                label='Browse')
+        self.btBrowse.connect('clicked', self._browse)
+        hsrc.pack_start(self.btBrowse, False, False, 2)
+        self.okButton = self.get_action_area().get_children()[1]
+        self.okButton.set_property('sensitive', False)
+
+        frmDesc = gtk.Frame('Package Description')
+        body.pack_start(frmDesc, False, True, 4)
+        hbdesc = gtk.HBox()
+        frmDesc.add(hbdesc)
+        self.descEntry = gtk.Entry()
+        self.descEntry.connect('changed', self._descURI_change)
+        btDescBrowse = vButton(stock=gtk.STOCK_OPEN, label='Browse')
+        btDescBrowse.connect('clicked', self._desc_browse)
+        hbdesc.pack_start(self.descEntry, True, True, 2)
+        hbdesc.pack_start(btDescBrowse, False, True, 2)
+
+        lb = gtk.Label('Application')
+        self.appEntry = gtk.Entry()
+        bapp = gtk.HBox()
+        body.pack_start(bapp, False, True, 8)
+        bapp.pack_start(lb, False, False, 2)
+        bapp.pack_start(self.appEntry, False, False, 2)
+
+        lbv = gtk.Label('Version')
+        self.verEntry = gtk.Entry()
+        bapp.pack_start(lbv, False, False, 2)
+        bapp.pack_start(self.verEntry, False, False, 2)
+
+        self.appEntry.connect('changed', self._appname_changed)
+        self.verEntry.connect('changed', self._appver_changed)
+
+        bbox = gtk.HBox()
+        lbuild = gtk.Label('Release')
+        rels = gtk.ListStore(int)
+        for x in xrange(1, 5):
+            rels.append([x])
+        cbRel = gtk.ComboBox(rels)
+        cr = gtk.CellRendererText()
+        cbRel.pack_start(cr)
+        cbRel.add_attribute(cr, 'text', 0)
+        cbRel.set_active(0)
+        bbox.pack_start(lbuild, False, False, 2)
+        bbox.pack_start(cbRel, False, False, 2)
+        body.pack_start(bbox, False, True, 4)
+        cbRel.connect('changed', self._release_changed)
+
+
+        self.body = body
+        body.show_all()
+
+    def _release_changed(self, widget=None):
+        self.release = widget.get_model()[widget.get_active()][0]
+
+    def _appname_changed(self, widget=None):
+        self.app = widget.get_text()
+        self.okButton.set_property('sensitive',
+                self.verEntry.get_text() != '')
+        return
+
+    def _appver_changed(self, widget=None):
+        self.ver = widget.get_text()
+        self.okButton.set_property('sensitive',
+                self.appEntry.get_text() != '')
+        return
+
+    def _descURI_change(self, widget=None):
+        self.DescURI = widget.get_text()
+
+    def _desc_browse(self, widget=None):
+        dia = gtk.FileChooserDialog(buttons=(gtk.STOCK_OK,
+            gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL))
+        dia.set_title('Select description file')
+        flt = gtk.FileFilter()
+        flt.add_mime_type('text/plain')
+        flt.set_name('Text files')
+        dia.add_filter(flt)
+        res = dia.run()
+        dia.hide()
+        if res == gtk.RESPONSE_OK:
+            self.descEntry.set_text(dia.get_filename())
+        dia.destroy()
+
+
+    def _browse(self, widget=None):
+        dia = gtk.FileChooserDialog(buttons=(gtk.STOCK_OK,
+            gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL))
+        dia.set_title('Choose source archive')
+        flt = gtk.FileFilter()
+        flt.add_pattern('*.[bgx]z*')
+        flt.set_name('Compressed Files')
+        dia.add_filter(flt)
+        res = dia.run()
+        dia.hide()
+        if res == gtk.RESPONSE_OK:
+            self.SrcURI = dia.get_filename()
+        dia.destroy()
+        if self.SrcURI.startswith('/'):
+            src = buildutils.Source(self.SrcURI)
+            if src.builder is not None:
+                self.appEntry.set_text(src.app)
+                self.verEntry.set_text(src.ver)
+#                self.srcentry.set_text(self.SrcURI)
+
+        self.srcentry.set_text(self.SrcURI)
+        return
+
+
+    def _src_entry_event(self, widget=None):
+        starts = ('http:', 'https:','ftp:')
+        ends = ('.tar.gz', '.xz', '.tar.bz2', '.tgz')
+        uri = widget.get_text()
+        enable = False
+        for i in starts:
+            if uri.startswith(i):
+                #enable = True
+                #self.okButton.set_property('sensitive', enable)
+                self.SrcURI = widget.get_text()
+                return
+        for x in ends:
+            if uri.endswith(x):
+                if os.path.exists(uri):
+                    enable = True
+                    self.okButton.set_property('sensitive', enable)
+                    self.SrcURI = widget.get_text()
+                    return
+
+
+#        self.okButton.set_property('sensitive',
+#                widget.get_text().startswith('http'))
+
+
+