Exemple #1
0
    def filetype(self, filename, parent_type = ''):
        ''' Determine filetype for the given file.'''
        if self.__types:

            OUT.debug('Returning file type', 7)

            return self.__types.filetype(filename, parent_type)
Exemple #2
0
    def remove(self, entry):
        '''
        Decide whether to delete something - and then go ahead and do so

        Just like portage, we only remove files that have not changed
        from when we installed them.  If the timestamp or checksum is
        different, we leave the file in place.

        Inputs

          entry    - file/dir/sym to remove
        '''

        OUT.debug('Trying to remove file', 6)

        # okay, deal with the file | directory | symlink

        removeable = self.__content.get_canremove(entry)

        if not removeable:

            # Remove directory or file.

            # Report if we are only pretending
            if self.__p:
                OUT.info('    pretending to remove: ' + entry)

            # try to remove the entry
            try:
                entry_type = self.__content.etype(entry)
                if self.__content.etype(entry) == 'dir':
                    # its a directory -> rmdir
                    if not self.__p:
                        os.rmdir(entry)
                else:
                    # its a file -> unlink
                    if not self.__p:
                        os.unlink(entry)
            except:
                # Report if there is a problem
                OUT.notice('!!!      '
                           + self.__content.epath(entry))
                return

            if self.__v and not self.__p:
                # Report successful deletion

                OUT.notice('<<< ' + entry_type + ' '
                           * (5 - len(entry_type))
                           + self.__content.epath(entry))

            self.__content.delete(entry)

            return True

        else:

            OUT.notice(removeable)

            return False
Exemple #3
0
    def read(self):
        ''' Read the contents of the dot config file.'''
        dotconfig = self.__dot_config()

        OUT.debug('Checking for dotconfig ', 6)

        if not self.has_dotconfig():
            raise Exception('Cannot read file ' + dotconfig)

        tokens = shlex.shlex(open(dotconfig))

        while True:
            a = tokens.get_token()
            b = tokens.get_token()
            c = tokens.get_token()

            OUT.debug('Reading token', 8)

            if (a in self.__tokens and
                b == '=' and c):

                if c[0] == '"':
                    c = c[1:]

                if c[-1] == '"':
                    c = c[:-1]

                self.__data[a] = c

            else:
                break
Exemple #4
0
    def read(self,
             config_owned  = 'config-files',
             server_owned  = 'server-owned-files',
             virtual_files = 'virtual',
             default_dirs  = 'default-owned'):
        '''
        Initialize the type cache.
        '''
        import WebappConfig.filetype

        server_files = []
        config_files = []

        if os.access(self.appdir() + '/' + config_owned, os.R_OK):
            flist = open(self.appdir() + '/' + config_owned)
            config_files = flist.readlines()

            OUT.debug('Identified config-protected files.', 7)

            flist.close()

        if os.access(self.appdir() + '/' + server_owned, os.R_OK):
            flist = open(self.appdir() + '/' + server_owned)
            server_files = flist.readlines()

            OUT.debug('Identified server-owned files.', 7)

            flist.close()

        self.__types = WebappConfig.filetype.FileType(config_files,
                                                      server_files,
                                                      virtual_files,
                                                      default_dirs)
Exemple #5
0
    def listunused(self, db):
        '''
        Outputs a list of what has not been installed so far
        '''

        packages = self.list_locations()

        if not packages:
            OUT.die('No packages found!')

        keys = sorted(packages)

        OUT.debug('Check for unused web applications', 7)

        for i in keys:

            db.set_category(packages[i][0])
            db.set_package (packages[i][1])
            db.set_version (packages[i][2])

            if not db.has_installs():
                if packages[i][0]:
                    OUT.notice(packages[i][0] + '/' + packages[i][1] + '-' + packages[i][2])
                else:
                    OUT.notice(packages[i][1] + '-' + packages[i][2])
Exemple #6
0
    def read(self,
             config_owned='config-files',
             server_owned='server-owned-files',
             virtual_files='virtual',
             default_dirs='default-owned'):
        '''
        Initialize the type cache.
        '''
        import WebappConfig.filetype

        server_files = []
        config_files = []

        if os.access(self.appdir() + '/' + config_owned, os.R_OK):
            flist = open(self.appdir() + '/' + config_owned)
            config_files = flist.readlines()

            OUT.debug('Identified config-protected files.', 7)

            flist.close()

        if os.access(self.appdir() + '/' + server_owned, os.R_OK):
            flist = open(self.appdir() + '/' + server_owned)
            server_files = flist.readlines()

            OUT.debug('Identified server-owned files.', 7)

            flist.close()

        self.__types = WebappConfig.filetype.FileType(config_files,
                                                      server_files,
                                                      virtual_files,
                                                      default_dirs)
Exemple #7
0
    def packageavail(self):
        '''
        Check to see whether the given package has been installed or not.

        These checks are carried out by using wrapper.py to facilitate
        distribution independant handling of the task.

        Outputs:
            0       - on success
            1       - package not found
            2       - no package to find
            3       - package isn't webapp-config compatible          '
        '''

        OUT.debug('Verifying package ' + self.package_name(), 6)

        # package_installed() does not handle "/PN" correctly
        package = self.pn

        if self.category:
            package = self.category + '/' + self.pn

        # not using self.package_name() here as we don't need pvr
            return 1

        # unfortunately, just because a package has been installed, it
        # doesn't mean that the package itself is webapp-compatible
        #
        # we need to check that the package has an entry in the
        # application repository

        if not self.appdb():
            return 3
        else:
            return 0
Exemple #8
0
    def packageavail(self):
        '''
        Check to see whether the given package has been installed or not.

        These checks are carried out by using wrapper.py to facilitate
        distribution independant handling of the task.

        Outputs:
            0       - on success
            1       - package not found
            2       - no package to find
            3       - package isn't webapp-config compatible          '
        '''

        OUT.debug('Verifying package ' + self.package_name(), 6)

        # package_installed() does not handle "/PN" correctly
        package = self.pn

        if self.category:
            package = self.category + '/' + self.pn

            # not using self.package_name() here as we don't need pvr
            return 1

        # unfortunately, just because a package has been installed, it
        # doesn't mean that the package itself is webapp-compatible
        #
        # we need to check that the package has an entry in the
        # application repository

        if not self.appdb():
            return 3
        else:
            return 0
Exemple #9
0
    def listunused(self, db):
        '''
        Outputs a list of what has not been installed so far
        '''

        packages = self.list_locations()

        if not packages:
            OUT.die('No packages found!')

        keys = sorted(packages)

        OUT.debug('Check for unused web applications', 7)

        for i in keys:

            db.set_category(packages[i][0])
            db.set_package(packages[i][1])
            db.set_version(packages[i][2])

            if not db.has_installs():
                if packages[i][0]:
                    OUT.notice(packages[i][0] + '/' + packages[i][1] + '-' +
                               packages[i][2])
                else:
                    OUT.notice(packages[i][1] + '-' + packages[i][2])
Exemple #10
0
    def dirtype(self, directory):
        ''' Determine filetype for the given directory.'''
        if self.__types:

            OUT.debug('Returning directory type', 7)

            return self.__types.dirtype(directory)
Exemple #11
0
    def filetype(self, filename):
        ''' Determine filetype for the given file.'''
        if self.__types:

            OUT.debug('Returning file type', 7)

            return self.__types.filetype(filename)
Exemple #12
0
    def dirtype(self, directory, parent_type = ''):
        ''' Determine filetype for the given directory.'''
        if self.__types:

            OUT.debug('Returning directory type', 7)

            return self.__types.dirtype(directory, parent_type)
Exemple #13
0
    def show_postinst(self, server = None):
        '''
        Display any post-installation instructions, if there are any.
        '''

        OUT.debug('Running show_postinst', 6)

        self.show_post(filename = 'postinst-en.txt', ptype = 'install', server = server)
Exemple #14
0
    def show_postupgrade(self, server = None):
        '''
        Display any post-upgrade instructions, if there are any.
        '''

        OUT.debug('Running show_postupgrade', 6)

        self.show_post(filename = 'postupgrade-en.txt', ptype = 'upgrade', server = server)
Exemple #15
0
    def remove(self, entry):
        '''
        Decide whether to delete something - and then go ahead and do so

        Just like portage, we only remove files that have not changed
        from when we installed them.  If the timestamp or checksum is
        different, we leave the file in place.

        Inputs

          entry    - file/dir/sym to remove
        '''

        OUT.debug('Trying to remove file', 6)

        # okay, deal with the file | directory | symlink

        removeable = self.__content.get_canremove(entry)

        if not removeable:

            # Remove directory or file.

            # Report if we are only pretending
            if self.__p:
                OUT.info('    pretending to remove: ' + entry)

            # try to remove the entry
            try:
                entry_type = self.__content.etype(entry)
                if self.__content.etype(entry) == 'dir':
                    # its a directory -> rmdir
                    if not self.__p:
                        os.rmdir(entry)
                else:
                    # its a file -> unlink
                    if not self.__p:
                        os.unlink(entry)
            except:
                # Report if there is a problem
                OUT.notice('!!!      ' + self.__content.epath(entry))
                return

            if self.__v and not self.__p:
                # Report successful deletion

                OUT.notice('<<< ' + entry_type + ' ' * (5 - len(entry_type)) +
                           self.__content.epath(entry))

            self.__content.delete(entry)

            return True

        else:

            OUT.notice(removeable)

            return False
Exemple #16
0
    def show_postupgrade(self, server=None):
        '''
        Display any post-upgrade instructions, if there are any.
        '''

        OUT.debug('Running show_postupgrade', 6)

        self.show_post(filename='postupgrade-en.txt',
                       ptype='upgrade',
                       server=server)
Exemple #17
0
    def show_postinst(self, server=None):
        '''
        Display any post-installation instructions, if there are any.
        '''

        OUT.debug('Running show_postinst', 6)

        self.show_post(filename='postinst-en.txt',
                       ptype='install',
                       server=server)
Exemple #18
0
    def clean(self):

        self.file_behind_flag = False

        OUT.debug('Basic server clean', 7)

        self.file_behind_flag |= self.__del.remove_files()

        self.file_behind_flag |= self.__del.remove_dirs()

        OUT.info('Any files or directories listed above must be removed b'
                 'y hand')

        # okay, let's finish off
        #
        # we don't need the contents file anymore

        self.file_behind_flag |= not self.__content.kill()

        # right - we need to run the hook scripts now
        # if they fail, we don't actually care

        # run the hooks

        self.__ebuild.run_hooks('clean', self)

        # do we need the dotconfig file?
        #
        # if the .webapp file is the only one in the dir, we believe
        # that we can remove it

        self.__dotconfig.kill()

        # is the installation directory empty?

        if not os.listdir(self.__destd) and os.path.isdir(self.__destd):
            if not self.__p:
                os.rmdir(self.__destd)
        else:
            OUT.notice('--- ' + self.__destd)

        # update the list of installs

        self.__db.remove(self.__destd)

        # Remove the selinux module

        if self.__selinux is not None:
            self.__selinux.remove_module()

        # did we leave anything behind?

        if self.file_behind_flag:
            OUT.warn('Remove whatever is listed above by hand')
Exemple #19
0
    def remove_files(self):
        '''
        It is time to remove the files that we installed originally.
        '''

        OUT.debug('Trying to remove files', 6)

        success = [self.remove(i) for i in self.__content.get_files()]

        # Tell the caller if anything was left behind

        return all(success)
Exemple #20
0
    def remove_files(self):
        '''
        It is time to remove the files that we installed originally.
        '''

        OUT.debug('Trying to remove files', 6)

        success = [self.remove(i) for i in self.__content.get_files()]

        # Tell the caller if anything was left behind

        return all(success)
Exemple #21
0
    def packagename(self):
        ''' Retrieve the package name from the values specified in the dot
        config file'''

        OUT.debug('Trying to retrieve package name', 6)

        if 'WEB_PN' in list(self.__data.keys()) and 'WEB_PVR' in list(self.__data.keys()):
            if 'WEB_CATEGORY' in list(self.__data.keys()):
                return self.__data['WEB_CATEGORY'] + '/' + \
                    self.__data['WEB_PN'] + '-' + self.__data['WEB_PVR']
            else:
                return self.__data['WEB_PN'] + '-' + self.__data['WEB_PVR']
        return ''
Exemple #22
0
    def has_dotconfig(self):
        ''' Return True if the install location already has a dotconfig
        file.'''
        dotconfig = self.__dot_config()

        OUT.debug('Verifying path', 7)

        if not os.path.isfile(dotconfig):
            return False

        if not os.access(dotconfig, os.R_OK):
            return False

        return True
Exemple #23
0
    def packageavail(self):
        '''
        Check to see whether the given package has been installed or not.

        These checks are carried out by using wrapper.py to facilitate
        distribution independant handling of the task.

        Outputs:
            0       - on success
            1       - package not found
            2       - no package to find
            3       - package isn't webapp-config compatible          '

        >>> import os.path
        >>> here = os.path.dirname(os.path.realpath(__file__))

        Does not exist:

        >>> a = WebappSource(root = here + '/tests/testfiles/share-webapps',
        ...             category='www-apps',package='nothere', version='1',pm='portage')
        >>> a.packageavail()
        1

        Incompatible cannot be tested since that would require a
        oackage (including version number) that is installed on
        all systems.
        '''

        OUT.debug('Verifying package ' + self.package_name(), 6)

        # package_installed() does not handle "/PN" correctly
        package = self.pn

        if self.category:
            package = self.category + '/' + self.pn

        # not using self.package_name() here as we don't need pvr
        if not wrapper.package_installed(package, self.pm):
            return 1

        # unfortunately, just because a package has been installed, it
        # doesn't mean that the package itself is webapp-compatible
        #
        # we need to check that the package has an entry in the
        # application repository

        if not self.appdb():
            return 3
        else:
            return 0
Exemple #24
0
    def clean(self):

        self.file_behind_flag = False

        OUT.debug('Basic server clean', 7)

        self.file_behind_flag |= self.__del.remove_files()

        self.file_behind_flag |= self.__del.remove_dirs()

        OUT.info('Any files or directories listed above must be removed b'
                 'y hand')

        # okay, let's finish off
        #
        # we don't need the contents file anymore

        self.file_behind_flag |= not self.__content.kill()

        # right - we need to run the hook scripts now
        # if they fail, we don't actually care

        # run the hooks

        self.__ebuild.run_hooks('clean', self)

        # do we need the dotconfig file?
        #
        # if the .webapp file is the only one in the dir, we believe
        # that we can remove it

        self.__dotconfig.kill()

        # is the installation directory empty?

        if not os.listdir(self.__destd) and os.path.isdir(self.__destd):
            if not self.__p:
                os.rmdir(self.__destd)
        else:
            OUT.notice('--- ' + self.__destd)

        # update the list of installs

        self.__db.remove(self.__destd)

        # did we leave anything behind?

        if self.file_behind_flag:
            OUT.warn('Remove whatever is listed above by hand')
Exemple #25
0
    def add(self, installdir, user, group):
        '''
        Add a record to the list of virtual installs.

        installdir - the installation directory
        '''

        if not installdir:
            OUT.die('The installation directory must be specified!')

        if not str(user):
            OUT.die('Please specify a valid user!')

        if not str(group):
            OUT.die('Please specify a valid group!')

        OUT.debug('Adding install record', 6)

        dbpath = self.appdb()

        if not dbpath:
            OUT.die('No package specified!')

        if not self.__p and not os.path.isdir(os.path.dirname(dbpath)):
            os.makedirs(os.path.dirname(dbpath), self.__dir_perm(0o755))

        fd = None

        if not self.__p:
            fd = os.open(dbpath,
                         os.O_WRONLY | os.O_APPEND | os.O_CREAT,
                         self.__file_perm(0o600))

        entry = str(int(time.time())) + ' ' + str(user) + ' ' + str(group)\
            + ' ' + installdir + '\n'

        OUT.debug('New record', 7)

        if not self.__p:
            os.write(fd, (entry).encode('utf-8'))
            os.close(fd)
        else:
            OUT.info('Pretended to append installation ' + installdir)
            OUT.info('Entry:\n' + entry)
Exemple #26
0
    def add(self, installdir, user, group):
        '''
        Add a record to the list of virtual installs.

        installdir - the installation directory
        '''

        if not installdir:
            OUT.die('The installation directory must be specified!')

        if not str(user):
            OUT.die('Please specify a valid user!')

        if not str(group):
            OUT.die('Please specify a valid group!')

        OUT.debug('Adding install record', 6)

        dbpath = self.appdb()

        if not dbpath:
            OUT.die('No package specified!')

        if not self.__p and not os.path.isdir(os.path.dirname(dbpath)):
            os.makedirs(os.path.dirname(dbpath), self.__dir_perm(0o755))

        fd = None

        if not self.__p:
            fd = os.open(dbpath, os.O_WRONLY | os.O_APPEND | os.O_CREAT,
                         self.__file_perm(0o600))

        entry = str(int(time.time())) + ' ' + str(user) + ' ' + str(group)\
            + ' ' + installdir + '\n'

        OUT.debug('New record', 7)

        if not self.__p:
            os.write(fd, (entry).encode('utf-8'))
            os.close(fd)
        else:
            OUT.info('Pretended to append installation ' + installdir)
            OUT.info('Entry:\n' + entry)
Exemple #27
0
    def list_locations(self):
        ''' List all available db files.'''

        OUT.debug('Retrieving hierarchy locations', 6)

        dbpath = self.appdb()

        if dbpath and os.path.isfile(dbpath):
            return {dbpath: [self.category, self.pn, self.pvr]}

        if dbpath and not os.path.isfile(dbpath):
            OUT.debug(
                'Package "' + self.package_name() +
                '" not listed in the hierarchy (file "' + dbpath +
                ' is missing)!', 8)
            return {}

        locations = {}
        packages = []

        if self.pn:
            packages.append(os.path.join(self.root, self.pn))
            if self.category:
                packages.append(os.path.join(self.root, self.category,
                                             self.pn))
        else:
            packages.extend(
                os.path.join(self.root, m) for m in os.listdir(self.root))
            for i in packages:
                if os.path.isdir(i):
                    packages.extend(os.path.join(i, m) for m in os.listdir(i))

        for i in packages:

            OUT.debug('Checking package', 8)

            if os.path.isdir(i):

                OUT.debug('Checking version', 8)

                versions = os.listdir(i)

                for j in versions:
                    appdir = os.path.join(i, j)
                    location = os.path.join(appdir, self.dbfile)
                    if (os.path.isdir(appdir) and os.path.isfile(location)):
                        pn = os.path.basename(i)
                        cat = os.path.basename(os.path.split(i)[0])
                        if cat == "webapps":
                            cat = ""
                        locations[location] = [cat, pn, j]

        return locations
Exemple #28
0
    def get_protectedname(self,
                          destination,
                          filename):
        '''
        Woh.  Somewhere, we've decided that we're trying to overwrite a file
        that we really want to save.  So, we need a new name for the file that
        we want to install - which is where we come in.

        NOTE:
          The filename that we produce is compatible with Gentoo's
          etc-update tool.  This is deliberate.

        Inputs:
          destination -  the directory that the file is being installed into
          filename    - the original name of the file
        '''

        my_file    = os.path.basename(filename)
        my_filedir = destination + '/' + os.path.dirname(filename)

        # find the highest numbered protected file that already
        # exists, and increment it by one

        entries = os.listdir(my_filedir)

        OUT.debug('Identifying possible file number', 7)

        numbers = []
        prefix  = self.protect_prefix
        rep = re.compile(prefix.replace('.','\.') + '(\d{4})_')

        for i in entries:
            rem = rep.match(i)
            if rem:
                numbers.append(int(rem.group(1)))

        if numbers:
            max_n = max(numbers) + 1
        else:
            max_n = 0

        return  my_filedir + '/%s%.4d_%s' % (prefix, max_n, my_file)
Exemple #29
0
    def list_locations(self):
        ''' List all available db files.'''

        OUT.debug('Retrieving hierarchy locations', 6)

        dbpath = self.appdb()

        if dbpath and os.path.isfile(dbpath):
            return {dbpath : [ self.category, self.pn, self.pvr]}

        if dbpath and not os.path.isfile(dbpath):
            OUT.debug('Package "' + self.package_name()
                      + '" not listed in the hierarchy (file "'
                      + dbpath + ' is missing)!', 8)
            return {}

        locations = {}
        packages  = []

        if self.pn:
            packages.append(os.path.join(self.root, self.pn))
            if self.category:
                packages.append(os.path.join(self.root, self.category, self.pn))
        else:
            packages.extend(os.path.join(self.root, m) for m in os.listdir(self.root))
            for i in packages:
                if os.path.isdir(i):
                    packages.extend(os.path.join(i,m) for m in os.listdir(i))

        for i in packages:

            OUT.debug('Checking package', 8)

            if os.path.isdir(i):

                OUT.debug('Checking version', 8)

                versions = os.listdir(i)

                for j in versions:
                    appdir = os.path.join(i,j)
                    location = os.path.join( appdir, self.dbfile)
                    if (os.path.isdir(appdir) and
                        os.path.isfile(location)):
                            pn = os.path.basename(i)
                            cat = os.path.basename(os.path.split(i)[0])
                            if cat == "webapps":
                                cat = ""
                            locations[location] = [ cat, pn, j ]

        return locations
Exemple #30
0
    def kill(self):
        ''' Remove the dot config file.'''

        empty = self.is_empty()

        OUT.debug('Trying to removing .webapp file', 7)

        if not empty:
            if not self.__p:
                try:
                    os.unlink(self.__dot_config())
                except:
                    OUT.warn('Failed to remove '
                             + self.__dot_config() + '!')
                    return False
            else:
                OUT.info('Would have removed ' + self.__dot_config())
            return True
        else:
            OUT.notice('--- ' + empty)
            return False
Exemple #31
0
    def get_protectedname(self, destination, filename):
        '''
        Woh.  Somewhere, we've decided that we're trying to overwrite a file
        that we really want to save.  So, we need a new name for the file that
        we want to install - which is where we come in.

        NOTE:
          The filename that we produce is compatible with Gentoo's
          etc-update tool.  This is deliberate.

        Inputs:
          destination -  the directory that the file is being installed into
          filename    - the original name of the file
        '''

        my_file = os.path.basename(filename)
        my_filedir = destination + '/' + os.path.dirname(filename)

        # find the highest numbered protected file that already
        # exists, and increment it by one

        entries = os.listdir(my_filedir)

        OUT.debug('Identifying possible file number', 7)

        numbers = []
        prefix = self.protect_prefix
        rep = re.compile(prefix.replace('.', '\.') + '(\d{4})_')

        for i in entries:
            rem = rep.match(i)
            if rem:
                numbers.append(int(rem.group(1)))

        if numbers:
            max_n = max(numbers) + 1
        else:
            max_n = 0

        return my_filedir + '/%s%.4d_%s' % (prefix, max_n, my_file)
Exemple #32
0
    def __init__(self,
                 config_owned,
                 server_owned,
                 server_owned_r,
                 virtual_files = 'virtual',
                 default_dirs  = 'default-owned'):
        '''
        Populates the cache with the file types as provided by the
        ebuild.
        '''

        self.__cache = {}

        # Validity of entries are checked by the command line parser
        self.__virtual_files = virtual_files
        self.__default_dirs  = default_dirs

        # populate cache
        for i in config_owned:

            OUT.debug('Adding config-owned file', 8)

            self.__cache[self.__fix(i)] = 'config-owned'

        for i in server_owned:

            if self.__fix(i) in self.__cache.keys():

                OUT.debug('Adding config-server-owned file', 8)

                self.__cache[self.__fix(i)] = 'config-server-owned'

            else:

                OUT.debug('Adding server-owned file', 8)

                self.__cache[self.__fix(i)] = 'server-owned'

        for i in server_owned_r:

            if self.__fix(i) in self.__cache.keys():

                OUT.die('{} is a the same time recursively server-owned and {}: This case is not supported.'.format(self.__fix(i), self.__cache[self.__fix(i)]))

            else :

                OUT.debug('Adding recursively server-owned file', 8)

                self.__cache[self.__fix(i).strip()] = 'server-owned-dir'
Exemple #33
0
    def run_hooks(self, type, server):
        '''
        Run the hook scripts - if there are any
        '''

        if self.config.pretend():
            return

        sandbox = Sandbox(self.config)

        # save list of environment variables to set
        env_map = self.run_vars(server)

        if os.path.isdir(self.__hooksd):
            for x in os.listdir(self.__hooksd):

                if (os.path.isfile(self.__hooksd + '/' + x) and
                    os.access(self.__hooksd + '/' + x, os.X_OK)):

                    OUT.debug('Running hook script', 7)

                    sandbox.spawn(self.__hooksd + '/' + x + ' ' + type, env_map)
Exemple #34
0
    def show_post(self, filename, ptype, server=None):
        '''
        Display one of the post files.
        '''

        post_file = self.__sourced + '/' + filename

        OUT.debug('Check for instruction file', 7)

        if not os.path.isfile(post_file):
            return

        self.run_vars(server)

        post_instructions = open(post_file).readlines()

        OUT.debug('Read post instructions', 7)

        post = [
            '',
            '=================================================================',
            'POST-' + ptype.upper() + ' INSTRUCTIONS',
            '=================================================================',
            ''
        ]

        for i in post_instructions:
            i = i.replace('"', '\\"')
            post.append(os.popen('echo -n "' + i + '"\n').read()[:-1])

        post = post + [
            '',
            '=================================================================',
            ''
        ]

        for i in post:
            OUT.notice(i)
Exemple #35
0
    def run_hooks(self, type, server):
        '''
        Run the hook scripts - if there are any
        '''

        if self.config.pretend():
            return

        sandbox = Sandbox(self.config)

        # save list of environment variables to set
        env_map = self.run_vars(server)

        if os.path.isdir(self.__hooksd):
            for x in os.listdir(self.__hooksd):

                if (os.path.isfile(self.__hooksd + '/' + x)
                        and os.access(self.__hooksd + '/' + x, os.X_OK)):

                    OUT.debug('Running hook script', 7)

                    sandbox.spawn(self.__hooksd + '/' + x + ' ' + type,
                                  env_map)
Exemple #36
0
    def read(self,
             config_owned    = 'config-files',
             server_owned    = 'server-owned-files',
             server_owned_r  = 'server-owned-dirs',
             virtual_files   = 'virtual',
             default_dirs    = 'default-owned'):
        '''
        Initialize the type cache.

        >>> import os.path
        >>> here = os.path.dirname(os.path.realpath(__file__))
        >>> a = WebappSource(root=here + '/tests/testfiles/share-webapps',
        ...             category='', package='horde', version='3.0.5')

        >>> a.read()
        >>> a.filetype('test1')
        'config-owned'

        >>> a.filetype('test2')
        'server-owned'

        '''
        import WebappConfig.filetype

        self.server_files = []
        self.server_dirs  = [] 
        config_files = []

        if os.access(self.appdir() + '/' + config_owned, os.R_OK):
            flist = open(self.appdir() + '/' + config_owned)
            config_files = flist.readlines()

            OUT.debug('Identified config-protected files.', 7)

            flist.close()

        if os.access(self.appdir() + '/' + server_owned, os.R_OK):
            flist = open(self.appdir() + '/' + server_owned)
            self.server_files = flist.readlines()

            OUT.debug('Identified server-owned files.', 7)

            flist.close()

        if os.access(self.appdir() + '/' + server_owned_r, os.R_OK):
            flist = open(self.appdir() + '/' + server_owned_r)
            self.server_dirs = flist.readlines()

            OUT.debug('Identified server-owned directories.', 7)

            flist.close()

        self.__types = WebappConfig.filetype.FileType(config_files,
                                                      self.server_files,
                                                      self.server_dirs,
                                                      virtual_files,
                                                      default_dirs)
Exemple #37
0
    def show_post(self, filename, ptype, server = None):
        '''
        Display one of the post files.
        '''

        post_file =  self.__sourced + '/' + filename

        OUT.debug('Check for instruction file', 7)

        if not os.path.isfile(post_file):
            return

        self.run_vars(server)

        post_instructions = open(post_file).readlines()

        OUT.debug('Read post instructions', 7)

        post = [
            '',
            '=================================================================',
            'POST-' + ptype.upper() + ' INSTRUCTIONS',
            '=================================================================',
            '']

        for i in post_instructions:
            i = i.replace('"', '\\"')
            post.append(os.popen('echo -n "' + i + '"\n').read()[:-1])

        post = post + [
            '',
            '=================================================================',
            '']

        for i in post:
            OUT.notice(i)
Exemple #38
0
    def mkdir(self, directory, current_type):
        '''
        Create a directory with the correct ownership and permissions.

        directory   - name of the directory
        '''
        src_dir = self.__sourced + '/' + directory
        dst_dir = self.__destd + '/' + directory

        OUT.debug('Creating directory', 6)

        # some special cases
        #
        # these should be triggered only if we are trying to install
        # a webapp into a directory that already has files and dirs
        # inside it

        if os.path.exists(dst_dir) and not os.path.isdir(dst_dir):
            # something already exists with the same name
            #
            # in theory, this should automatically remove symlinked
            # directories

            OUT.warn('    ' + dst_dir + ' already exists, but is not a di'
                     'rectory - removing')
            if not self.__p:
                os.unlink(dst_dir)

        dirtype = self.__ws.dirtype(src_dir, current_type)

        OUT.debug('Checked directory type', 8)

        (user, group, perm) = self.__perm['dir'][dirtype]

        dsttype = 'dir'

        if not os.path.isdir(dst_dir):

            OUT.debug('Creating directory', 8)

            if not self.__p:
                os.makedirs(dst_dir, perm(0o755))

                os.chown(dst_dir,
                         user,
                         group)

        self.__content.add(dsttype,
                           dirtype,
                           self.__destd,
                           directory,
                           directory,
                           self.__relative)

        return dirtype
Exemple #39
0
    def mkdir(self, directory):
        '''
        Create a directory with the correct ownership and permissions.

        directory   - name of the directory
        '''
        src_dir = self.__sourced + '/' + directory
        dst_dir = self.__destd + '/' + directory

        OUT.debug('Creating directory', 6)

        # some special cases
        #
        # these should be triggered only if we are trying to install
        # a webapp into a directory that already has files and dirs
        # inside it

        if os.path.exists(dst_dir) and not os.path.isdir(dst_dir):
            # something already exists with the same name
            #
            # in theory, this should automatically remove symlinked
            # directories

            OUT.warn('    ' + dst_dir + ' already exists, but is not a di'
                     'rectory - removing')
            if not self.__p:
                os.unlink(dst_dir)

        dirtype = self.__ws.dirtype(src_dir)

        OUT.debug('Checked directory type', 8)

        (user, group, perm) = self.__perm['dir'][dirtype]

        dsttype = 'dir'

        if not os.path.isdir(dst_dir):

            OUT.debug('Creating directory', 8)

            if not self.__p:
                os.makedirs(dst_dir, perm(0o755))

                os.chown(dst_dir, user, group)

        self.__content.add(dsttype, dirtype, self.__destd, directory,
                           directory, self.__relative)
Exemple #40
0
    def mkdirs(self, directory = '', current_type = ''):
        '''
        Create a set of directories

        Inputs

        directory   - the directory within the source hierarchy
        '''

        sd = self.__sourced + '/' + directory
        real_dir = re.compile('/+').sub('/',
                self.__ws.appdir()
                + '/' + self.__sourced
                + '/' + directory)

        OUT.debug('Creating directories', 6)

        if not self.__ws.source_exists(sd):

            OUT.warn(self.__ws.package_name()
                     + ' does not install any files from '
                     + real_dir + '; skipping')
            return

        OUT.info('    Installing from ' + real_dir)

        for i in self.__ws.get_source_directories(sd):

            OUT.debug('Handling directory', 7)

            # create directory first
            next_type = self.mkdir(directory + '/' + i, current_type)

            # then recurse into the directory
            self.mkdirs(directory + '/' + i, next_type)

        for i in self.__ws.get_source_files(sd):

            OUT.debug('Handling file', 7)

            # handle the file
            self.mkfile(directory + '/' + i, current_type)
Exemple #41
0
    def mkdirs(self, directory=''):
        '''
        Create a set of directories

        Inputs

        directory   - the directory within the source hierarchy
        '''

        sd = self.__sourced + '/' + directory
        real_dir = re.compile('/+').sub(
            '/',
            self.__ws.appdir() + '/' + self.__sourced + '/' + directory)

        OUT.debug('Creating directories', 6)

        if not self.__ws.source_exists(sd):

            OUT.warn(self.__ws.package_name() +
                     ' does not install any files from ' + real_dir +
                     '; skipping')
            return

        OUT.info('    Installing from ' + real_dir)

        for i in self.__ws.get_source_directories(sd):

            OUT.debug('Handling directory', 7)

            # create directory first
            self.mkdir(directory + '/' + i)

            # then recurse into the directory
            self.mkdirs(directory + '/' + i)

        for i in self.__ws.get_source_files(sd):

            OUT.debug('Handling file', 7)

            # handle the file
            self.mkfile(directory + '/' + i)
Exemple #42
0
    def __init__(self,
                 config_owned,
                 server_owned,
                 virtual_files = 'virtual',
                 default_dirs  = 'default-owned'):
        '''
        Populates the cache with the file types as provided by the
        ebuild.
        '''

        self.__cache = {}

        # Validity of entries are checked by the command line parser
        self.__virtual_files = virtual_files
        self.__default_dirs  = default_dirs

        # populate cache
        for i in config_owned:

            OUT.debug('Adding config-owned file', 8)

            self.__cache[self.__fix(i)] = 'config-owned'

        for i in server_owned:

            if self.__fix(i) in list(self.__cache.keys()):

                OUT.debug('Adding config-server-owned file', 8)

                self.__cache[self.__fix(i)] = 'config-server-owned'

            else:

                OUT.debug('Adding server-owned file', 8)

                self.__cache[self.__fix(i)] = 'server-owned'
Exemple #43
0
    def remove(self, installdir):
        '''
        Remove a record from the list of virtual installs.

        installdir - the installation directory
        '''
        if not installdir:
            OUT.die('The installation directory must be specified!')

        dbpath = self.appdb()

        if not dbpath:
            OUT.die('No package specified!')

        if not os.access(dbpath, os.R_OK):
            OUT.warn('Unable to read the install database ' + dbpath)
            return

        # Read db file
        fdb = open(dbpath)
        entries = fdb.readlines()
        fdb.close()

        newentries = []
        found = False

        for i in entries:

            j = i.strip().split(' ')

            if j:

                if len(j) != 4:

                    # Remove invalid entry
                    OUT.warn('Invalid line "' + i.strip() + '" remo'
                             'ved from the database file!')
                elif j[3] != installdir:

                    OUT.debug('Keeping entry', 7)

                    # Keep valid entry
                    newentries.append(i.strip())

                elif j[3] == installdir:

                    # Remove entry, indicate found
                    found = True

        if not found:
            OUT.warn('Installation at "' +  installdir + '" could not be '
                     'found in the database file. Check the entries in "'
                     + dbpath + '"!')

        if not self.__p:
            installs = open(dbpath, 'w')
            installs.write('\n'.join(newentries) + '\n')
            installs.close()
            if not self.has_installs():
                os.unlink(dbpath)
        else:
            OUT.info('Pretended to remove installation ' + installdir)
            OUT.info('Final DB content:\n' + '\n'.join(newentries) + '\n')
Exemple #44
0
    def install(self, upgrade = False):

        self.config_protected_dirs = []

        OUT.debug('Basic server install', 7)

        # The root of the virtual install location needs to exist

        if not os.path.isdir(self.__destd) and not self.__p:

            OUT.debug('Directory missing', 7)

            dir = self.__destd
            dirs = []

            while dir != '/':
                dirs.insert(0, dir)
                dir = os.path.dirname(dir)

            a = self.__perm['dir']['install-owned'][2]('0755')
            OUT.debug('Strange')

            # Create the directories
            for i in dirs:
                if not os.path.isdir(i):
                    os.mkdir(i)
                    os.chmod(i, 
                             self.__perm['dir']['install-owned'][2]('0755'))
                    os.chown(i,
                             self.__perm['dir']['install-owned'][0],
                             self.__perm['dir']['install-owned'][1])

                if self.__v:
                    OUT.info('  Creating installation directory: '
                             + i)

        # Create the handler for installing

        self.__flags['relative'] = True

        wa = WebappAdd(self.__sourced,
                       self.__destd,
                       self.__perm,
                       self.__handler,
                       self.__flags)

        self.__add = wa

        OUT.info('Installing ' + self.__ws.package_name() + '...')

        # we need to create the directories to place our files in
        # and we need to copy in the files

        OUT.info('  Creating required directories', 1)
        OUT.info('  Linking in required files', 1)
        OUT.info('    This can take several minutes for larger apps', 1)

        self.__add.mkdirs()

        self.config_protected_dirs += self.__add.config_protected_dirs

        # Create the second handler for installing the root files

        self.__flags['relative'] = False

        wa = WebappAdd(self.__hostroot,
                       self.__vhostroot,
                       self.__perm,
                       self.__handler,
                       self.__flags)

        self.__add = wa

        self.__add.mkdirs()

        self.config_protected_dirs += self.__add.config_protected_dirs

        OUT.info('  Files and directories installed', 1)

        self.__dotconfig.write(self.__ws.category,
                               self.__ws.pn,
                               self.__ws.pvr,
                               self.__flags['host'],
                               self.__flags['orig'],
                               str(self.__perm['file']['config-owned'][0])
                               + ':' + str(self.__perm['file']['config-owned'][1]),)

        self.__db.add(self.__destd,
                      self.__perm['file']['config-owned'][0],
                      self.__perm['file']['config-owned'][1])

        # run the hooks

        self.__ebuild.run_hooks('install', self)

        # show the post-installation instructions

        if not upgrade:
            self.__ebuild.show_postinst(self)
        else:
            self.__ebuild.show_postupgrade(self)

        # to finish, we need to tell the user if they need to run
        # etc-update or not

        if self.config_protected_dirs:

            # work out whether this directory is part of the
            # CONFIG_PROTECT list or not

            self.__protect.how_to_update(self.config_protected_dirs)

        self.__content.write()

        # and we're done

        OUT.info('Install completed - success', 1)
Exemple #45
0
    def remove(self, installdir):
        '''
        Remove a record from the list of virtual installs.

        installdir - the installation directory
        '''
        if not installdir:
            OUT.die('The installation directory must be specified!')

        dbpath = self.appdb()

        if not dbpath:
            OUT.die('No package specified!')

        if not os.access(dbpath, os.R_OK):
            OUT.warn('Unable to read the install database ' + dbpath)
            return

        # Read db file
        fdb = open(dbpath)
        entries = fdb.readlines()
        fdb.close()

        newentries = []
        found = False

        for i in entries:

            j = i.strip().split(' ')

            if j:

                if len(j) != 4:

                    # Remove invalid entry
                    OUT.warn('Invalid line "' + i.strip() + '" remo'
                             'ved from the database file!')
                elif j[3] != installdir:

                    OUT.debug('Keeping entry', 7)

                    # Keep valid entry
                    newentries.append(i.strip())

                elif j[3] == installdir:

                    # Remove entry, indicate found
                    found = True

        if not found:
            OUT.warn('Installation at "' + installdir + '" could not be '
                     'found in the database file. Check the entries in "' +
                     dbpath + '"!')

        if not self.__p:
            installs = open(dbpath, 'w')
            installs.write('\n'.join(newentries) + '\n')
            installs.close()
            if not self.has_installs():
                os.unlink(dbpath)
        else:
            OUT.info('Pretended to remove installation ' + installdir)
            OUT.info('Final DB content:\n' + '\n'.join(newentries) + '\n')
Exemple #46
0
    def add(self, dsttype, ctype, destination, path, real_path, relative=True):
        '''
        Add an entry to the contents file.

        Just like Portage, when we install an app, we create a contents
        file to say what we installed and when.  We use this contents
        file to help us safely remove & upgrade apps.

        CONTENTS file format:

        <what> <rel> <type> <filename> <timestamp> <sum> [<optional>]

        where

        <what>      is one of dir|sym|file|hardlink

        <rel>       is 1 for relative filenames, 0 for absolute
                        filenames

        <type>      is one of
                        server-owned|default-owned|config-owned|virtual

        <timestamp> is the timestamp when the file was installed

        <sum>       is the md5sum of the file
                        (this is 0 for directories and symlinks)

        <filename>      is the actual name of the file we have installed

        <optional>      is additional data that depends upon <what>

        NOTE:
            Filenames used to be on the end of the line.  This made
                the old bash version more complicated, and
                prone to failure. So I have moved the filename into the
                middle of the line. -- Stuart

        Portage uses absolute names for its files, dirs, and symlinks.
        We do not.
        In theory, you can move a directory containing a web-based app,
        and

        a) the app itself will not break, and
        b) webapp-config will still work on that directory
           for upgrades and cleans.

        Position-independence *is* a design constraint that all future
        changes to this script need to honour.

        Inputs:

          dsttype     - type to add (one of dir|sym|file|hardlink)
          ctype       - internal webapp-config type
                      - (server-owned | config-owned | virtual)
          destination - install dir (normally $G_INSTALLDIR)
          path        - filename inside 'destination'
          real_path   - for config-protected files realpath =! path
                        (and this is important for md5)
          relative    - 1 for storing a relative filename, 0 otherwise
        '''

        OUT.debug('Adding entry to content dictionary', 6)

        # Build the full path that we use as index in the contents list
        while path[0] == '/':
            path = path[1:]
        while destination[-1] == '/':
            destination = destination[:-1]

        entry = destination + '/' + path

        # special case - we don't add entries for '.'

        if os.path.basename(entry) == '.':
            return

        if (not self.__p and not os.path.islink(entry) and
            (not os.path.exists(entry) or not os.access(entry, os.R_OK))):
            OUT.warn('Cannot access file ' + entry + ' to add it as'
                     ' installation content. This should not happen!')
            return

        allowed_types = {
            'file': ['file', self.file_md5, self.file_null],
            'hardlink': ['file', self.file_md5, self.file_null],
            'dir': ['dir', self.file_zero, self.file_null],
            'sym': ['sym', self.file_zero, self.file_link],
        }

        if not dsttype in list(allowed_types.keys()):
            OUT.die('Oops, webapp-config bug. "dsttype" is ' + dsttype)

        # Generate handler for file attributes
        a = allowed_types[dsttype]

        # For absolute entries the path must match the entry
        if not relative:
            path = entry

        OUT.debug('Adding entry', 7)

        # report if pretending
        if self.__p:

            OUT.info('    pretending to add: ' + ' '.join(
                [dsttype, str(int(relative)), ctype, '"' + path + '"']))
        else:

            # Only the path is enclosed in quotes, NOT the link targets
            self.__content[entry] = [
                a[0],
                str(int(relative)), ctype, '"' + path + '"',
                self.file_time(entry), a[1](real_path), a[2](entry)
            ]

            if self.__v:
                msg = path
                if msg[0] == "/":
                    msg = self.__root + msg
                    msg = self.__re.sub('/', msg)
                OUT.notice('>>> ' + a[0] + ' ' * (4 - len(a[0])) + ' ('  \
                           + ctype + ') ' + msg)
Exemple #47
0
    def get_canremove(self, entry):
        '''
        Determines if an entry can be removed.

        Returns a string if the entry may not be removed. The
        string will describe the reason why the entry should
        not be removed.

        In case the entry can be removed nothing will be
        returned.
        '''

        OUT.debug('Checking if the file can be removed', 6)

        # Path not found.
        # Cannot remove -> return False
        if not os.path.exists(entry) and not os.path.islink(entry):

            OUT.debug('Did not find the file.', 7)

            return '!found ' + self.epath(entry)

        entry_type = self.etype(entry)

        if entry_type == 'sym':
            # Should be a link but is not.
            if not os.path.islink(entry):
                return '!sym ' + self.epath(entry)

            # Expected link location does not match with
            # current target.
            # this results in leaving broken symlinks behind
            # if self.file_link(entry) != self.etarget(entry):
            #     return '!target ' + self.epath(entry)

        if entry_type == 'file':

            # Expected file, path is not a file
            if not os.path.isfile(entry):
                return '!file ' + self.epath(entry)

            # This is config protected. Do not remove!
            #if self.eowner(entry)[0:6] == 'config':
            #    return '!cfgpro ' + self.epath(entry)

            # Modification time does not match. Refuse to remove.
            if self.file_time(entry) != self.etime(entry):
                return '!time ' + self.epath(entry)

            # Content has different hash. Do not remove.
            if self.file_md5(entry) != self.emd5(entry):
                return '!sum ' + self.epath(entry)

        if entry_type == 'dir':

            # Expected directory, path is not a directory.
            if not os.path.isdir(entry):
                return '!dir ' + self.epath(entry)

            # the rules are simple
            #
            # if the directory is empty, it can go
            # if the directory is not empty, it cannot go

            # get a directory listing

            entry_list = os.listdir(entry)

            # Support for ignoring file. Currently only needed
            # to enable doctests in the subversion repository
            if self.ignore:
                entry_list = [i for i in entry_list if not i in self.ignore]

            OUT.debug('Remaining files', 7)

            # Directory not empty
            # Cannot remove -> return False
            if entry_list:
                return '!empty ' + self.epath(entry)
Exemple #48
0
    def run_vars(self, server = None):
        '''
        This function exports the necessary variables to the shell
        environment so that they are accessible within the shell scripts
        and/or files provided by the ebuild.
        '''

        v_root = self.get_config('vhost_root')
        v_cgi  = self.get_config('g_cgibindir')
        v_conf = self.get_config('vhost_config_dir')
        v_err  = v_root + '/' + self.get_config('my_errorsbase')
        v_icon = v_root + '/' + self.get_config('my_iconsbase')

        g_inst = self.get_config('g_installdir')
        g_htd  = self.get_config('g_htdocsdir')
        g_orig = self.get_config('g_orig_installdir')

        vsu = None
        vsg = None
        if server:
            vsu = pwd.getpwuid(server.vhost_server_uid)[0]
            vsg = grp.getgrgid(server.vhost_server_gid)[0]

        OUT.debug('Exporting variables', 7)

        export_map = {'MY_HOSTROOTDIR'     : None,
                      'MY_HTDOCSDIR'       : None,
                      'MY_CGIBINDIR'       : None,
                      'MY_INSTALLDIR'      : g_inst,
                      'MY_ICONSDIR'        : None,
                      'MY_SERVERCONFIGDIR' : None,
                      'MY_ERRORSDIR'       : None,
                      'MY_SQLSCRIPTSDIR'   : None,
                      'VHOST_ROOT'         : None,
                      'VHOST_HTDOCSDIR'    : g_htd,
                      'VHOST_CGIBINDIR'    : v_cgi,
                      'VHOST_CONFDIR'      : v_conf,
                      'VHOST_ERRORSDIR'    : v_err,
                      'VHOST_ICONSDIR'     : v_icon,
                      'VHOST_HOSTNAME'     : None,
                      'VHOST_SERVER'       : None,
                      'VHOST_APPDIR'       : g_orig,
                      'VHOST_CONFIG_UID'   : None,
                      'VHOST_CONFIG_GID'   : None,
                      'VHOST_SERVER_UID'   : vsu,
                      'VHOST_SERVER_GID'   : vsg,
                      'VHOST_DEFAULT_UID'  : None,
                      'VHOST_DEFAULT_GID'  : None,
                      'VHOST_PERMS_SERVEROWNED_DIR'  : None,
                      'VHOST_PERMS_SERVEROWNED_FILE' : None,
                      'VHOST_PERMS_CONFIGOWNED_DIR'  : None,
                      'VHOST_PERMS_CONFIGOWNED_FILE' : None,
                      'VHOST_PERMS_DEFAULTOWNED_DIR' : None,
                      'VHOST_PERMS_VIRTUALOWNED_FILE': None,
                      'VHOST_PERMS_INSTALLDIR'       : None,
                      'ROOT'                         : self.__root,
                      'PN' : None,
                      'PVR': None}

        result = {}
        for i in list(export_map.keys()):

            value = export_map[i]

            if not value:
                value = self.get_config(i.lower())

            os.putenv(i, str(value))
            result[i] = str(value)

        return result
Exemple #49
0
    def read(self):
        '''
        Reads the contents database.
        '''

        dbpath = self.appdb()

        if not dbpath or not os.access(dbpath, os.R_OK):
            OUT.die('Content file ' + dbpath + ' is missing or not accessibl'
                    'e!')

        content = open(dbpath).readlines()

        for i in content:

            i = i.strip()

            rfn = re.compile('"(.*)"')
            rfs = rfn.search(i)
            if not rfs:
                ok = False
            else:
                fn = rfs.group(1)
                i = rfn.sub('', i)
                line_split = i.split(' ')
                line_split[3] = fn

                OUT.debug('Adding content line', 10)

                ok = True

                if len(line_split) < 6:
                    ok = False
                    OUT.warn('Content file ' + dbpath + ' has an invalid line'
                             ':\n' + i + '\nNot enough entries.')

                if ok and not line_split[0] in ['file', 'sym', 'dir']:
                    ok = False
                    OUT.warn('Content file ' + dbpath + ' has an invalid line'
                             ':\n' + i + '\nInvalid file type: ' +
                             line_split[0])

                if ok and not line_split[1] in ['0', '1']:
                    ok = False
                    OUT.warn('Content file ' + dbpath + ' has an invalid line'
                             ':\n' + i + '\nInvalid relative flag: ' +
                             line_split[1])

                if ok and not line_split[2] in [
                        'virtual',
                        'server-owned',
                        'config-owned',
                        'default-owned',
                        'config-server-owned',
                        # Still need that in case an
                        # application was installed
                        # with w-c-1.11
                        'root-owned'
                ]:
                    ok = False
                    OUT.warn('Content file ' + dbpath + ' has an invalid line'
                             ':\n' + i + '\nInvalid owner: ' + line_split[2])

                if ok and line_split[0] == 'sym' and len(line_split) == 6:
                    OUT.warn('Content file ' + dbpath + ' has an invalid line'
                             ':\n' + i + '\nMissing link target! ')

                if len(line_split) == 6:
                    line_split.append('')

                # I think this could happen if the link target contains
                # spaces
                # -- wrobel
                if len(line_split) > 7:
                    line_split = line_split[0:6]                         \
                                 + [' '.join(line_split[6:])]

            if ok:
                if line_split[1] == '0':
                    self.__content[line_split[3]] = line_split
                else:
                    self.__content[self.__installdir + '/' +
                                   line_split[3]] = line_split

            else:
                OUT.warn('Invalid line in content file (' + i + '). Ignor'
                         'ing!')
Exemple #50
0
    def run_vars(self, server=None):
        '''
        This function exports the necessary variables to the shell
        environment so that they are accessible within the shell scripts
        and/or files provided by the ebuild.
        '''

        v_root = self.get_config('vhost_root')
        v_cgi = self.get_config('g_cgibindir')
        v_conf = self.get_config('vhost_config_dir')
        v_err = v_root + '/' + self.get_config('my_errorsbase')
        v_icon = v_root + '/' + self.get_config('my_iconsbase')

        g_inst = self.get_config('g_installdir')
        g_htd = self.get_config('g_htdocsdir')
        g_orig = self.get_config('g_orig_installdir')

        vsu = None
        vsg = None
        if server:
            vsu = pwd.getpwuid(server.vhost_server_uid)[0]
            vsg = grp.getgrgid(server.vhost_server_gid)[0]

        OUT.debug('Exporting variables', 7)

        export_map = {
            'MY_HOSTROOTDIR': None,
            'MY_HTDOCSDIR': None,
            'MY_CGIBINDIR': None,
            'MY_INSTALLDIR': g_inst,
            'MY_ICONSDIR': None,
            'MY_SERVERCONFIGDIR': None,
            'MY_ERRORSDIR': None,
            'MY_SQLSCRIPTSDIR': None,
            'VHOST_ROOT': None,
            'VHOST_HTDOCSDIR': g_htd,
            'VHOST_CGIBINDIR': v_cgi,
            'VHOST_CONFDIR': v_conf,
            'VHOST_ERRORSDIR': v_err,
            'VHOST_ICONSDIR': v_icon,
            'VHOST_HOSTNAME': None,
            'VHOST_SERVER': None,
            'VHOST_APPDIR': g_orig,
            'VHOST_CONFIG_UID': None,
            'VHOST_CONFIG_GID': None,
            'VHOST_SERVER_UID': vsu,
            'VHOST_SERVER_GID': vsg,
            'VHOST_DEFAULT_UID': None,
            'VHOST_DEFAULT_GID': None,
            'VHOST_PERMS_SERVEROWNED_DIR': None,
            'VHOST_PERMS_SERVEROWNED_FILE': None,
            'VHOST_PERMS_CONFIGOWNED_DIR': None,
            'VHOST_PERMS_CONFIGOWNED_FILE': None,
            'VHOST_PERMS_DEFAULTOWNED_DIR': None,
            'VHOST_PERMS_VIRTUALOWNED_FILE': None,
            'VHOST_PERMS_INSTALLDIR': None,
            'ROOT': self.__root,
            'PN': None,
            'PVR': None
        }

        result = {}
        for i in list(export_map.keys()):

            value = export_map[i]

            if not value:
                value = self.get_config(i.lower())

            os.putenv(i, str(value))
            result[i] = str(value)

        return result
Exemple #51
0
    def get_canremove(self, entry):
        '''
        Determines if an entry can be removed.

        Returns a string if the entry may not be removed. The
        string will describe the reason why the entry should
        not be removed.

        In case the entry can be removed nothing will be
        returned.

        >>> import os.path
        >>> here = os.path.dirname(os.path.realpath(__file__))

        Trying to remove the contents:

        >>> a = Contents(here + '/tests/testfiles/contents/app/',
        ...              package = 'test', version = '1.0')
        >>> a.read()
        >>> a.ignore += ['.svn']
        >>> for i in a.get_directories():
        ...     a.get_canremove(i)
        '!dir test7'
        '!empty dir1'

        >>> for i in a.get_files():
        ...     a.get_canremove(i)
        '!time test2'
        '!time test4'
        '!found test6'
        '!sym dir3'
        '!file dir4'

        # Disabled 
        #'!target test3'

        '''

        OUT.debug('Checking if the file can be removed', 6)

        # Path not found.
        # Cannot remove -> return False
        if not os.path.exists(entry) and not os.path.islink(entry):

            OUT.debug('Did not find the file.', 7)

            return '!found ' + self.epath(entry)

        entry_type = self.etype(entry)

        if entry_type == 'sym':
            # Should be a link but is not.
            if not os.path.islink(entry):
                return '!sym ' + self.epath(entry)

            # Expected link location does not match with
            # current target.
            # this results in leaving broken symlinks behind
            # if self.file_link(entry) != self.etarget(entry):
            #     return '!target ' + self.epath(entry)

        if entry_type == 'file':

            # Expected file, path is not a file
            if not os.path.isfile(entry):
                return '!file ' + self.epath(entry)

            # This is config protected. Do not remove!
            #if self.eowner(entry)[0:6] == 'config':
            #    return '!cfgpro ' + self.epath(entry)

            # Modification time does not match. Refuse to remove.
            if self.file_time(entry) != self.etime(entry):
                return '!time ' + self.epath(entry)

            # Content has different hash. Do not remove.
            if self.file_md5(entry) != self.emd5(entry):
                return '!sum ' + self.epath(entry)

        if entry_type == 'dir':

            # Expected directory, path is not a directory.
            if not os.path.isdir(entry):
                return '!dir ' + self.epath(entry)

            # the rules are simple
            #
            # if the directory is empty, it can go
            # if the directory is not empty, it cannot go

            # get a directory listing

            entry_list = os.listdir(entry)

            # Support for ignoring file. Currently only needed
            # to enable doctests in the subversion repository
            if self.ignore:
                entry_list = [i for i in  entry_list
                              if not i in self.ignore]

            OUT.debug('Remaining files', 7)

            # Directory not empty
            # Cannot remove -> return False
            if entry_list:
                return '!empty ' + self.epath(entry)
Exemple #52
0
    def get_protectedname(self,
                          destination,
                          filename):
        '''
        Woh.  Somewhere, we've decided that we're trying to overwrite a file
        that we really want to save.  So, we need a new name for the file that
        we want to install - which is where we come in.

        NOTE:
          The filename that we produce is compatible with Gentoo's
          etc-update tool.  This is deliberate.

        Inputs:
          destination -  the directory that the file is being installed into
          filename    - the original name of the file

        Let's test the code on some examples:

        >>> import os.path
        >>> here = os.path.dirname(os.path.realpath(__file__))

        >>> a = Protection('','horde','3.0.5','portage')
        >>> a.get_protectedname(here + '/tests/testfiles/protect/empty',
        ...                     'test')#doctest: +ELLIPSIS
        '.../tests/testfiles/protect/empty//._cfg0000_test'

        >>> a.get_protectedname(here + '/tests/testfiles/protect/simple',
        ...                     'test')#doctest: +ELLIPSIS
        '.../tests/testfiles/protect/simple//._cfg0001_test'

        >>> a.get_protectedname(here + '/tests/testfiles/protect/complex',
        ...                     'test')#doctest: +ELLIPSIS
        '.../tests/testfiles/protect/complex//._cfg0801_test'

        '''

        my_file    = os.path.basename(filename)
        my_filedir = destination + '/' + os.path.dirname(filename)

        # find the highest numbered protected file that already
        # exists, and increment it by one

        entries = os.listdir(my_filedir)

        OUT.debug('Identifying possible file number', 7)

        numbers = []
        prefix  = self.protect_prefix
        rep = re.compile(prefix.replace('.','\.') + '(\d{4})_')

        for i in entries:
            rem = rep.match(i)
            if rem:
                numbers.append(int(rem.group(1)))

        if numbers:
            max_n = max(numbers) + 1
        else:
            max_n = 0

        return  my_filedir + '/%s%.4d_%s' % (prefix, max_n, my_file)
Exemple #53
0
    def install(self, upgrade=False):

        self.config_protected_dirs = []

        OUT.debug('Basic server install', 7)

        # The root of the virtual install location needs to exist

        if not os.path.isdir(self.__destd) and not self.__p:

            OUT.debug('Directory missing', 7)

            dir = self.__destd
            dirs = []

            while dir != EPREFIX + '/':
                dirs.insert(0, dir)
                dir = os.path.dirname(dir)

            a = self.__perm['dir']['install-owned'][2]('0755')
            OUT.debug('Strange')

            # Create the directories
            for i in dirs:
                if not os.path.isdir(i):
                    os.mkdir(i)
                    os.chmod(i, self.__perm['dir']['install-owned'][2]('0755'))
                    os.chown(i, self.__perm['dir']['install-owned'][0],
                             self.__perm['dir']['install-owned'][1])

                if self.__v:
                    OUT.info('  Creating installation directory: ' + i)

        # Create the handler for installing

        self.__flags['relative'] = True

        wa = WebappAdd(self.__sourced, self.__destd, self.__perm,
                       self.__handler, self.__flags)

        self.__add = wa

        OUT.info('Installing ' + self.__ws.package_name() + '...')

        # we need to create the directories to place our files in
        # and we need to copy in the files

        OUT.info('  Creating required directories', 1)
        OUT.info('  Linking in required files', 1)
        OUT.info('    This can take several minutes for larger apps', 1)

        self.__add.mkdirs()

        self.config_protected_dirs += self.__add.config_protected_dirs

        # Create the second handler for installing the root files

        self.__flags['relative'] = False

        wa = WebappAdd(self.__hostroot, self.__vhostroot, self.__perm,
                       self.__handler, self.__flags)

        self.__add = wa

        self.__add.mkdirs()

        self.config_protected_dirs += self.__add.config_protected_dirs

        OUT.info('  Files and directories installed', 1)

        self.__dotconfig.write(
            self.__ws.category,
            self.__ws.pn,
            self.__ws.pvr,
            self.__flags['host'],
            self.__flags['orig'],
            str(self.__perm['file']['config-owned'][0]) + ':' +
            str(self.__perm['file']['config-owned'][1]),
        )

        self.__db.add(self.__destd, self.__perm['file']['config-owned'][0],
                      self.__perm['file']['config-owned'][1])

        # run the hooks

        self.__ebuild.run_hooks('install', self)

        # show the post-installation instructions

        if not upgrade:
            self.__ebuild.show_postinst(self)
        else:
            self.__ebuild.show_postupgrade(self)

        # to finish, we need to tell the user if they need to run
        # etc-update or not

        if self.config_protected_dirs:

            # work out whether this directory is part of the
            # CONFIG_PROTECT list or not

            self.__protect.how_to_update(self.config_protected_dirs)

        self.__content.write()

        # and we're done

        OUT.info('Install completed - success', 1)
Exemple #54
0
    def mkfile(self, filename):
        '''
        This is what we are all about.  No more games - lets take a file
        from the master image of the web-based app, and make it available
        inside the install directory.

        filename    - name of the file

        '''

        OUT.debug('Creating file', 6)

        dst_name = self.__destd + '/' + filename
        file_type = self.__ws.filetype(self.__sourced + '/' + filename)

        OUT.debug('File type determined', 7)

        # are we overwriting an existing file?

        OUT.debug('Check for existing file', 7)

        if os.path.exists(dst_name):

            OUT.debug('File in the way!', 7)

            my_canremove = True

            # o-oh - we're going to be overwriting something that already
            # exists

            # If we are upgrading, check if the file can be removed
            if self.__u:
                my_canremove = self.__remove.remove(self.__destd, filename)
            # Config protected file definitely cannot be removed
            elif file_type[0:6] == 'config':
                my_canremove = False

            if not my_canremove:
                # not able to remove the file
                #           or
                # file is config-protected

                dst_name = self.__protect.get_protectedname(
                    self.__destd, filename)
                OUT.notice('^o^ hiding ' + filename)
                self.config_protected_dirs.append(self.__destd + '/' +
                                                  os.path.dirname(filename))

                OUT.debug('Hiding config protected file', 7)

            else:

                # it's a file we do not know about - so get rid
                # of it anyway
                #
                # this behaviour here *is* by popular request
                # personally, I'm not comfortable with it -- Stuart

                if not self.__p:
                    if os.path.isdir(dst_name):
                        os.rmdir(dst_name)
                    else:
                        os.unlink(dst_name)
                else:
                    OUT.info('    would have removed "' + dst_name + '" s'
                             'ince it is in the way for the current instal'
                             'l. It should not be present in that location'
                             '!')

        # if we get here, we can get on with the business of making
        # the file available

        (user, group, perm) = self.__perm['file'][file_type]
        my_contenttype = ''

        src_name = self.__ws.appdir() + '/' + self.__sourced + '/' + filename

        # Fix the paths
        src_name = re.compile('/+').sub('/', src_name)
        dst_name = re.compile('/+').sub('/', dst_name)

        OUT.debug('Creating File', 7)

        # this is our default file type
        #
        # we link in (soft and hard links are supported)
        # if we're allowed to
        #
        # some applications (/me points at PHP scripts)
        # won't run if symlinked in.
        # so we now support copying files in too
        #
        # default behaviour is to hard link (if we can), and
        # to copy if we cannot
        #
        # if the user wants symlinks, then the user has to
        # use the new '--soft' option

        if file_type == 'virtual' or os.path.islink(src_name):

            if self.__link_type == 'soft':
                try:

                    OUT.debug('Trying to softlink', 8)

                    if not self.__p:
                        if self.__v:
                            print("\n>>> SOFTLINKING FILE: ")
                            print(">>> Source: " + src_name +
                                  "\n>>> Destination: " + dst_name + "\n")
                        os.symlink(src_name, dst_name)

                    my_contenttype = 'sym'

                except Exception as e:

                    if self.__v:
                        OUT.warn('Failed to softlink (' + str(e) + ')')

            elif self.__link_type == 'copy':
                try:

                    OUT.debug('Trying to copy files directly', 8)

                    if not self.__p:
                        if self.__v:
                            print("\n>>> COPYING FILE: ")
                            print(">>> Source: " + src_name +
                                  "\n>>> Destination: " + dst_name + "\n")
                        shutil.copy(src_name, dst_name)

                    my_contenttype = 'file'

                except Exception as e:

                    if self.__v:
                        OUT.warn('Failed to copy (' + str(e) + ')')

            elif os.path.islink(src_name):
                try:

                    OUT.debug('Trying to copy symlink', 8)

                    if not self.__p:
                        if self.__v:
                            print("\n>>> SYMLINK COPY: ")
                            print(">>> Source: " + src_name +
                                  "\n>>> Destination: " + dst_name + "\n")
                        os.symlink(os.readlink(src_name), dst_name)

                    my_contenttype = 'sym'

                except Exception as e:

                    if self.__v:
                        OUT.warn('Failed copy symlink (' + str(e) + ')')

            else:
                try:

                    OUT.debug('Trying to hardlink', 8)

                    if not self.__p:
                        if self.__v:
                            print("\n>>> HARDLINKING FILE: ")
                            print(">>> Source: " + src_name +
                                  "\n>>> Destination: " + dst_name + "\n")
                        os.link(src_name, dst_name)

                    my_contenttype = 'file'

                except Exception as e:

                    if self.__v:
                        OUT.warn('Failed to hardlink (' + str(e) + ')')

        if not my_contenttype:

            if not self.__p:
                if self.__v:
                    print("\n>>> COPYING FILE: ")
                    print(">>> Source: " + src_name + "\n>>> Destination: " +
                          dst_name + "\n")
                shutil.copy(src_name, dst_name)
            my_contenttype = 'file'

        if not self.__p and not os.path.islink(src_name):

            old_perm = os.stat(src_name)[stat.ST_MODE] & 511

            os.chown(dst_name, user, group)

            os.chmod(dst_name, perm(old_perm))

        self.__content.add(my_contenttype, file_type, self.__destd, filename,
                           dst_name, self.__relative)