vpackager / src / vpackager / buildutils.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 os
import bottools
import glob
import shutil
import exceptions
import preferences


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

try:
    _sources_home = preferences.VPConf().GetSetting('sources_home')
except:
    _source_home = "/tmp/vpackager"
try:
    _packager = preferences.VPConf().GetSetting('packager_name')
except:
    _packager="vpackager"

class SourceCopyError(Exception):
    pass

class SlackBuildCreationError(Exception):
    pass

class MissingSourcesHomeError(Exception):
    pass

class PackageNotFoundError(Exception):
    pass

def get_vltag():
    ''' Return a string representing the distro tag for the installed system'''
    vlconfig = glob.glob('/var/log/packages/vlconfig2*')[0]
    if not vlconfig: return None
    tag = vlconfig[-4:]
    return tag

class Source(object):
    """ Main construct for all compressed source archives. Provides convinient
    methods for extraction, compilation, and packaging different source
    types"""

    def __init__(self, path):
        self.path = path
        self.builder = None
        filename = os.path.split(path)[1]
        if '-' in filename:
            fnsplit = filename.rsplit('-', 1)
        elif '_' in filename:
            fnsplit = filename.rsplit('_', 1)
        self.app = fnsplit[0]

        if '.tar.' in fnsplit[1]:
            self.ver = fnsplit[1].rsplit('.tar.', 2)[0]
        else:
            self.ver = fnsplit[1].rsplit('.', 2)[0]

        self.srclocation = os.path.join(
                _sources_home, self.app,
                '%s-%s'% (self.app, self.ver))
        self.__myhome = os.path.join(_sources_home, self.app)
        self.pkg = os.path.join(
                _sources_home, self.app,
                'package_%s-%s'% (self.app, self.ver))
        self.__dump = []
        #self.builder = self.FindSourceType()

    def install_pkg(self):
        fullpath = glob.glob(os.path.join(
            self.__myhome, self.ver,'%s-%s-*.t?z'% (
                self.app, self.ver)))[0]
        if not fullpath:
            raise PackageNotFoundError

        return bottools.Execute('installpkg %s'% fullpath)


    def makeSlackBuild(self, buildno='1', packager=_packager,
                       config=""):
        """ Generate a slackbuild using sbbuilder to build this source"""
        ### Use sbbuilder to create a slackbuild for his package.
        ### The only diff from using this vs sbbuilder itself is that
        ### This app can guess what type of slackbuild needs to be
        ### created for the app to build.
        if not self.builder:
            self.builder = self.FindSourceType()

        try:
            os.makedirs(_sources_home)
        except:
            pass
        try:
            os.chdir(_sources_home)
        except:
            raise MissingSourcesHomeError

        # call the sbbuilder binary
        proc = bottools.Execute(
            'sbbuilder --package=%s --version=%s --type=%s --build=%s --user=%s --configure_options="%s"' %(
                self.app, self.ver, self.builder, buildno, packager, config))
        proc.run()
        if proc.popen.returncode > 0:
            # the process failed
            raise SlackBuildCreationError

        self.__myhome = os.path.join(_sources_home, self.app)
        self.srclocation = os.path.join(self.__myhome, self.ver, 'src')

        # copy the source archive to the build dir
        try:
            shutil.copy2(self.path, self.srclocation)
        except:
            raise SourceCopyError
        # Return to the original path
 #       os.chdir(_currdir)

        sbpath = os.path.join(
            self.__myhome, self.ver, 'src', '%s.SlackBuild'% self.app)
        if os.path.exists(sbpath):
            return sbpath

        return None

    def buildSlackBuild(self, config=""):
        """ Execute the build script generated by sbbuilder"""
        os.environ['CONFIG_OPTIONS'] = config
        return bottools.Execute('sh %s.SlackBuild'% self.app)

    def Extract(self, srcdir=None):
        """ Extract the contents of the source code. If srcdir is parsed, it
        will be extracted there, otherwise, it defaults to /tmp/vpackager"""
        if not srcdir:
            srcdir = self.__myhome
        cmd = 'tar xfv %s -C %s'% (self.path, srcdir)
        return bottools.Execute(cmd)

    def __get_dump(self, line):
        """ Internal method to collect a list of the contents of the tarball"""
        self.__dump.append('/'.join(line.strip().split('/')[1::]))

    def FindSourceType(self):
        """ Determine what type of slackbuild we need to generate for this
        application to build."""
        cmd = 'tar -tf %s'% self.path
        proc = bottools.Execute(cmd)
        proc.observer.add_callback(self.__get_dump)
        proc.run()

        if 'waf' in self.__dump:
            self.builder = 'waf'
        elif 'configure' in self.__dump:
            self.builder = 'default'
        elif 'autogen.sh' in self.__dump:
            self.builder = 'default'
        elif 'Makefile' in self.__dump:
            #FIXME: sbbuilder needs to accomodate sources with Makefile only
            self.builder = 'default --no-configure'
        elif 'CMakeLists.txt' in self.__dump:
            self.builder = 'cmake'
        elif 'setup.py' in self.__dump:
            self.builder = 'python'
        self.__dump = None
        return self.builder

class SourceURL(object):
    """ Source object created from a URL rather than a local path"""
    def __init__(self, app='',version='',srctype='default',link=''):
        self.app = app
        self.ver = version
        self.builder = srctype
        self.link = link

    def makeSlackBuild(self, buildno='1', packager=_packager, config=""):
        """ Generate the build script for this source """
        try:
            os.makedirs(_sources_home)
        except:
            pass
        try:
            os.chdir(_sources_home)
        except:
            raise MissingSourcesHomeError
        cm = 'sbbuilder --package=%s --version=%s --type=%s'% (self.app,
                self.ver, self.builder) + \
                ' --build=%s --user=%s --link=%s --configure_options="%s"'% (buildno,
                        packager, self.link, config)
        proc = bottools.Execute(cm)
        proc.run()
        if proc.popen.returncode > 0:
            # SB creation returned an error
            raise SlackBuildCreationError
        self.__myhome = os.path.join(_sources_home, self.app)
        self.srclocation = os.path.join(self.__myhome, self.ver, 'src')
        self.pkg = os.path.join(
                _sources_home, self.app, 'package_%s-%s'% (self.app, self.ver))
        sbpath = os.path.join(self.__myhome, self.ver, 'src', '%s.SlackBuild'% self.app)
        if os.path.exists(sbpath):
            return sbpath

        return None

    def install_pkg(self):
        pkgpath = glob.glob(
                os.path.join(
                    self.__myhome, self.ver,'%s-%s-*.t?z'% (
                        self.app, self.ver)))[0]
        if not pkgpath:
            raise PackageNotFoundError

        return bottools.Execute('installpkg %s'% pkgpath)


    def buildSlackBuild(self, config=""):
        """ Execute the build script generated by the class"""
        # Make sure we are at the correct location
        os.chdir(self.srclocation)
        os.environ['CONFIG_OPTIONS'] = config
        return bottools.Execute('sh %s.SlackBuild'% self.app)
        #return bottools.Execute('sh %s.SlackBuild'% self.app)
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.