drivcenDRIVENvpackager / src / vpackager / bottools.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 v3 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 subprocess as sp
import os
import psutil
import time

__author__ = 'rbistolfi'
__modified_by__ = 'M0E-lnx'
__author_email__ = 'moc.liamg@xnl.E0M'[::-1]
__version__ = '0.1'



class Execute(object):
    """ A wrapper for the Popen object that provides a run method for shell
    processes and whose stdout and stderr can be read"""
    def __init__(self, command, **kwargs):
        self.command = command
        self.stdout = None
        self.popen = None
        self.observer = Observer()
        self._popen_running = False

    def kill_popen(self, parentpid=None):
        """ Recursively kill the self.popen process and all its children
        processes."""
        parent = psutil.Process(self.popen.pid)
        for child in parent.get_children():
            if child.cmdline[0] in ('make'):
                killer = 'killall %s -u %s'% (child.cmdline[0], child.username)
                proc = sp.Popen(killer.split(), stdout=sp.PIPE, stderr=sp.STDOUT)
                proc.communicate()
            else:
                child.kill()


    def run(self):
        """ Trigger execution of self.command"""
        self._popen_running = True
        popen = self.popen = sp.Popen(
                self.command.split(), stdout=sp.PIPE,
                stderr=sp.STDOUT)
        self.stdout = self.observer.set_file_object(
                popen.stdout, close=True)
        self.observer.notify()
        self.popen.communicate()
        self._popen_running = False

class Emptyproc(Execute):
    """ Just a dummy empty Execute class that does nothing but 'sleep 1'.
    This is used to avoid returning a None or 0 value on methods of any source
    type that do not support a given build method"""
    def __init__(self):
        Execute.__init__(self, 'sleep 1')

class Observer(object):
    """observer pattern for a file-like object"""

    def __init__(self):
        self.file_object = None
        self.close_file = False
        self._callbacks = set()

    def add_callback(self, func):
        """Add a callable function to the set of callbacks. Callbacks must take
        a single argument: A line of the file object."""
        self._callbacks.add(func)
        return

    def notify(self):
        """ Return all the callbacks for each line of the file object"""
        while True:
            line = self.file_object.readline()
            if not line:
                break
            for cb in self._callbacks:
                cb(line)

    def set_file_object(self, file_object, close=False):
        """ Set the file object to observe. If close is True, the file object
        will be closed with self.file_object.close()"""
        self.file_object = file_object
        self.close_file = close
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.