def listservers(): OUT.notice('\n'.join(['apache', 'lighttpd', 'cherokee', 'nginx', 'gatling']))
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)
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)
def get_root(config): '''Returns the $ROOT variable''' if config.config.get('USER', 'package_manager') == "portage": try: import portage except ImportError as e: OUT.die("Portage libraries not found, quitting:\n%s" % e) return portage.settings['ROOT'] elif config.config.get('USER', 'package_manager') == "paludis": cat = config.maybe_get('cat') pn = config.maybe_get('pn') if cat and pn: cmd="cave print-id-environment-variable -b --format '%%v\n' --variable-name ROOT %s/%s" % (cat,pn) fi, fo, fe = os.popen3(cmd) fi.close() result_lines = fo.readlines() fo.close() fe.close() if result_lines[0].strip(): return result_lines[0].strip() else: return '/' else: return '/' else: OUT.die("Unknown package manager: " + pm)
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)
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
def filetype(self, filename): ''' Determine filetype for the given file.''' if self.__types: OUT.debug('Returning file type', 7) return self.__types.filetype(filename)
def dirisconfigprotected(self, installdir): ''' Traverses the path of parent directories for the given install dir and checks if any matches the list of config protected files. >>> a = Protection('','horde','3.0.5','portage') Add a virtual config protected directory: >>> a.config_protect += ' /my/strange/htdocs/' >>> a.dirisconfigprotected('/my/strange/htdocs/where/i/installed/x') True >>> a.dirisconfigprotected('/my/strange/htdocs/where/i/installed/x/') True >>> a.config_protect += ' /my/strange/htdocs' >>> a.dirisconfigprotected('/my/strange/htdocs/where/i/installed/x') True >>> a.dirisconfigprotected('/my/strange/htdocs/where/i/installed/x/') True >>> a.config_protect += ' bad_user /my/strange/htdocs' >>> a.dirisconfigprotected('/my/bad_user/htdocs/where/i/installed/x') False >>> a.dirisconfigprotected('/my/strange/htdocs/where/i/installed/x/') True >>> a.dirisconfigprotected('/') False ''' my_master = [] for i in self.config_protect.split(' '): if i[0] == '/': if i[-1] == '/': my_master.append(i[:-1]) else: my_master.append(i) if installdir[0] != '/': OUT.die('BUG! Don\'t call this with a relative path.') if installdir[-1] == '/': my_dir = installdir[:-1] else: my_dir = installdir while my_dir: if my_dir == '.' or my_dir == '/': return False for x in my_master: if my_dir == x: return True my_dir = os.path.dirname(my_dir) # nope, the directory isn't config-protected at this time return False
def how_to_update(self, dirs): ''' Instruct the user how to update the application. ''' my_command = self.update_command directories = [] for i in dirs: present = False if directories: for j in directories: if (i == j[:len(i)] or j == i[:len(j)]): present = True break if not present: directories.append(i) my_command_list = '' for i in directories: if not self.dirisconfigprotected(i): my_command_list += 'CONFIG_PROTECT="' + i + '" ' + my_command + '\n' if not my_command_list: my_command_list = my_command OUT.warn( 'One or more files have been config protected\nTo comple' 'te your install, you need to run the following command(s):\n\n' + my_command_list)
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)
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
def how_to_update(self, dirs): ''' Instruct the user how to update the application. ''' my_command = self.update_command directories = [] for i in dirs: present = False if directories: for j in directories: if (i == j[:len(i)] or j == i[:len(j)]): present = True break if not present: directories.append(i) my_command_list = '' for i in directories: if not self.dirisconfigprotected(i): my_command_list += 'CONFIG_PROTECT="' + i + '" ' + my_command + '\n' if not my_command_list: my_command_list = my_command OUT.warn('One or more files have been config protected\nTo comple' 'te your install, you need to run the following command(s):\n\n' + my_command_list)
def test_add_rm(self): OUT.color_off() db = WebappDB(root='/'.join((HERE, 'testfiles', 'webapps')), pretend=True, package='horde', version='3.0.5') # Test adding: db.add('/'.join(('/screwy', 'wonky', 'foobar', 'horde', 'hierarchy')), user='******', group='me') output = sys.stdout.getvalue().split('\n') self.assertEqual(output[0], '* Pretended to append installation '\ '/screwy/wonky/foobar/horde/hierarchy') # Test deleting a webapp that is actually in the database: db.remove('/'.join(('/var', 'www', 'localhost', 'htdocs', 'horde'))) output = sys.stdout.getvalue().split('\n') self.assertEqual(output[6], '* ') # And now test deleting one that isn't: db.remove('/'.join( ('/screwy', 'wonky', 'foobar', 'horde', 'hierarchy'))) output = sys.stdout.getvalue().split('\n') self.assertEqual(output[11], '* 1124612110 root root '\ '/var/www/localhost/htdocs/horde')
def dirtype(self, directory): ''' Determine filetype for the given directory.''' if self.__types: OUT.debug('Returning directory type', 7) return self.__types.dirtype(directory)
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
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)
def test_read_corrupt(self): contents = Contents('/'.join((HERE, 'testfiles', 'contents')), package = 'test', version = '1.1') OUT.color_off() contents.read() output = sys.stdout.getvalue().split('\n') self.assertEqual(output[12], '* Not enough entries.')
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)
def __init__(self, directories, permissions, handler, flags, pm): if self.dep and not self.supported(pm): print(self.dep) OUT.die('Your configuration file sets the server type "' + self.name + '"\nbut the corresponding package does not seem to be ' 'installed!\nPlease "emerge ' + self.dep + '" or correct ' 'your settings.') try: self.set_server_user() except KeyError: OUT.die('The user for the server type "' + self.name + '" does not exist!') self.__sourced = directories['source'] self.__destd = directories['destination'] self.__hostroot = directories['hostroot'] self.__vhostroot = directories['vhostroot'] # + server owned if permissions['file']['server-owned'][0] == 0: permissions['file']['server-owned'][0] = self.vhost_server_uid permissions['dir']['server-owned'][0] = self.vhost_server_uid if permissions['file']['server-owned'][1] == 0: permissions['file']['server-owned'][1] = self.vhost_server_gid permissions['dir']['server-owned'][1] = self.vhost_server_gid # and config owned directories have server gid permissions['dir']['config-owned'][1] = self.vhost_server_gid # allows server and config owned permissions['file']['config-server-owned'][ 1] = self.vhost_server_gid permissions['dir']['config-server-owned'][ 1] = self.vhost_server_gid self.__perm = permissions self.__handler = handler self.__flags = flags self.__ws = handler['source'] self.__content = handler['content'] self.__protect = handler['protect'] self.__dotconfig = handler['dotconfig'] self.__ebuild = handler['ebuild'] self.__db = handler['db'] self.__v = flags['verbose'] self.__p = flags['pretend'] wd = WebappRemove(self.__content, self.__v, self.__p) handler['removal'] = wd self.__del = wd # Set by the install function self.__add = None
def test_add(self): loc = '/'.join((HERE, 'testfiles', 'contents', 'app')) contents = Contents(loc, package='test', version='1.0') OUT.color_off() contents.add('file', 'config_owned', destination=loc, path='/test1', real_path=loc + '/test1', relative=True) # Now trigger an error by adding a file that doesn't exist! contents.add('file', 'config_owned', destination=loc, path='/test0', real_path=loc + '/test0', relative=True) output = sys.stdout.getvalue().strip('\n') self.assertTrue('WebappConfig/tests/testfiles/contents/app/test0 to '\ 'add it as installation content. This should not '\ 'happen!' in output) # Test adding hardlinks: contents.add('hardlink', 'config_owned', destination=loc, path='/test2', real_path=loc + '/test2', relative=True) self.assertTrue( 'file 1 config_owned "test2" ' in contents.entry(loc + '/test2')) # Test adding dirs: contents.add('dir', 'default_owned', destination=loc, path='/dir1', real_path=loc + '/dir1', relative=True) self.assertTrue( 'dir 1 default_owned "dir1" ' in contents.entry(loc + '/dir1')) # Test adding symlinks: contents.add('sym', 'virtual', destination=loc, path='/test3', real_path=loc + '/test3', relative=True) self.assertTrue('sym 1 virtual "test3" ' in contents.entry(loc + '/test3')) # Printing out the db after adding these entries: contents.db_print() output = sys.stdout.getvalue().split('\n') self.assertTrue('file 1 config_owned "test1" ' in output[1])
def listservers(): OUT.notice('\n'.join(['apache', 'lighttpd', 'cherokee', 'nginx', 'gatling', 'hiawatha', 'tracd',]))
def test_read_corrupt(self): contents = Contents('/'.join((HERE, 'testfiles', 'contents')), package='test', version='1.1') OUT.color_off() contents.read() output = sys.stdout.getvalue().split('\n') self.assertEqual(output[12], '* Not enough entries.')
def db_print(self): ''' Print all enties of the contents file.''' entries = self.get_sorted_files() values = [] for i in entries: # Fix relative entry s = self.__content[i] s[1] = str(int(s[1])) values.append(' '.join(s)) OUT.notice('\n'.join(values))
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)
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)
def listservers(): OUT.notice('\n'.join([ 'apache', 'lighttpd', 'cherokee', 'nginx', 'gatling', 'tracd', ]))
def test_add_pretend(self): loc = '/'.join((HERE, 'testfiles', 'contents', 'app')) contents = Contents(loc, package = 'test', version = '1.0', pretend = True) OUT.color_off() contents.add('file', 'config_owned', destination = loc, path = '/test1', real_path = loc + '/test1', relative = True) output = sys.stdout.getvalue().strip('\n') self.assertEqual(output, '* pretending to add: file 1 config_owned "test1"')
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)
def test_remove_files(self): OUT.color_off() contents = Contents('/'.join((HERE, 'testfiles', 'contents', 'app2')), package = 'test', version = '1.0', pretend = True) contents.read() webrm = WebappRemove(contents, True, True) webrm.remove_files() output = sys.stdout.getvalue().split('\n') self.assertEqual(output[3], '* pretending to remove: ' + '/'.join((HERE, 'testfiles', 'contents', 'app2', 'test3')))
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 ''
def want_category(config): '''Check if the package manager requires category info Portage: optional Paludis: mandatory ''' if config.config.get('USER', 'package_manager') == "portage": return elif config.config.get('USER', 'package_manager') == "paludis": if not config.config.has_option('USER', 'cat'): OUT.die("Package name must be in the form CAT/PN") else: OUT.die("Unknown package manager: " + pm)
def test_write(self): contents = Contents('/'.join((HERE, 'testfiles', 'contents')), package = 'test', version = '1.0', pretend = True) OUT.color_off() contents.read() contents.write() output = sys.stdout.getvalue().split('\n') expected = '* Would have written content file ' + '/'.join((HERE, 'testfiles', 'contents', '.webapp-test-1.0!')) self.assertEqual(output[0], expected)
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
def test_remove_files(self): OUT.color_off() contents = Contents('/'.join((HERE, 'testfiles', 'contents', 'app2')), package='test', version='1.0', pretend=True) contents.read() webrm = WebappRemove(contents, True, True) webrm.remove_files() output = sys.stdout.getvalue().split('\n') self.assertEqual( output[3], '* pretending to remove: ' + '/'.join( (HERE, 'testfiles', 'contents', 'app2', 'test3')))
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])
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])
def test_add_pretend(self): loc = '/'.join((HERE, 'testfiles', 'contents', 'app')) contents = Contents(loc, package='test', version='1.0', pretend=True) OUT.color_off() contents.add('file', 'config_owned', destination=loc, path='/test1', real_path=loc + '/test1', relative=True) output = sys.stdout.getvalue().strip('\n') self.assertEqual( output, '* pretending to add: file 1 config_owned "test1"')
def test_list_installs(self): OUT.color_off() db = WebappDB(root = '/'.join((HERE, 'testfiles', 'webapps'))) db.listinstalls() output = sys.stdout.getvalue().split('\n') self.assertEqual(output[1], '/var/www/localhost/htdocs/horde') # Now test the verbosity: db = WebappDB(root = '/'.join((HERE, 'testfiles', 'webapps')), verbose = True) db.listinstalls() output = sys.stdout.getvalue().split('\n') self.assertEqual(output[5], '* Installs for horde-3.0.5')
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
def test_list_installs(self): OUT.color_off() db = WebappDB(root='/'.join((HERE, 'testfiles', 'webapps'))) db.listinstalls() output = sys.stdout.getvalue().split('\n') self.assertEqual(output[1], '/var/www/localhost/htdocs/horde') # Now test the verbosity: db = WebappDB(root='/'.join((HERE, 'testfiles', 'webapps')), verbose=True) db.listinstalls() output = sys.stdout.getvalue().split('\n') self.assertEqual(output[5], '* Installs for horde-3.0.5')
def test_write(self): contents = Contents('/'.join((HERE, 'testfiles', 'contents')), package='test', version='1.0', pretend=True) OUT.color_off() contents.read() contents.write() output = sys.stdout.getvalue().split('\n') expected = '* Would have written content file ' + '/'.join( (HERE, 'testfiles', 'contents', '.webapp-test-1.0!')) self.assertEqual(output[0], expected)
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'
def kill(self): ''' Remove the contents file.''' if not self.__p: try: dbpath = self.appdb() self.check_installdir() os.unlink(dbpath) self.__content = {} return True except: OUT.warn('Failed to remove ' + self.appdb() + '!') return False else: OUT.info('Would have removed ' + self.appdb()) return True
def write(self, category, package, version, host, original_installdir, user_group): ''' Output the .webapp file, that tells us in future what has been installed into this directory. ''' self.__data['WEB_CATEGORY'] = category self.__data['WEB_PN'] = package self.__data['WEB_PVR'] = version self.__data['WEB_INSTALLEDBY'] = pwd.getpwuid(os.getuid())[0] self.__data['WEB_INSTALLEDDATE'] = strftime('%Y-%m-%d %H:%M:%S') self.__data['WEB_INSTALLEDFOR'] = user_group self.__data['WEB_HOSTNAME'] = host self.__data['WEB_INSTALLDIR'] = original_installdir info = ['# ' + self.__file, '# config file for this copy of ' + package + '-' + version, '#', '# automatically created by Gentoo\'s webapp-config', '# do NOT edit this file by hand', '',] for i in self.__tokens: info.append(i + '="' + self.__data[i] + '"') if not self.__p: try: fd = os.open(self.__dot_config(), os.O_WRONLY | os.O_CREAT, self.__perm(0o600)) os.write(fd, ('\n'.join(info)).encode('utf-8')) os.close(fd) except Exception as e: OUT.die('Unable to write to ' + self.__dot_config() + '\nError was: ' + str(e)) else: OUT.info('Would have written the following information into ' + self.__dot_config() + ':\n' + '\n'.join(info))
def dirtype(self, directory, parent_type = ''): ''' Inputs: directory - the directory that we need a decision about parent_type - the type of the parent directory returns one of these: server-owned - dir needs to be owned by the webserver user config-owned - dir needs to be owned by the config user config-server-owned - Both the previous cases at the same time server-owned-dir - Directory that contains file/dirs to be owned by the webserver user default-owned - we need a local copy, owned by root NOTE: Use get_filetype(filename) for files NOTE: the user can use --default-dirs on the command-line to change what type default directories are really reported as ''' # remove any whitespace and trailing / directory = self.__fix(directory) # check the cache if directory in self.__cache.keys(): # Check if parent type is recursive if parent_type == 'server-owned-dir': new_type = self.__cache[directory] if new_type == 'config-owned': OUT.die('This version does not support config dirs') if new_type == server-owned: OUT.warn('Configuration error: {} is marked server-owned two times'.format(filename)) return 'server-owned-dir' return self.__cache[directory] # Check if parent type is recursive if parent_type == 'server-owned-dir': return 'server-owned-dir' # unspecified directories are default-owned return self.__default_dirs
def filetype(self, filename, parent_type = ''): ''' Inputs: filename - the file that we need a decision about parent_type - the type of the parent directory returns one of these: server-owned - file needs to be owned by the webserver user (and needs to be a local copy) config-owned - file needs to be owned by the config user (and needs to be a local copy) config-server-owned - Both the previous cases at the same time virtual - we do not need a local copy of the file NOTE: Use get_dirtype(directory) for directories NOTE: the user can use --virtual-files on the command-line to change what type virtual files are really reported as ''' # remove any whitespace and trailing / filename = self.__fix(filename) # check the cache if filename in self.__cache.keys(): # Check if parent type is recursive if parent_type == 'server-owned-dir': new_type = self.__cache[filename] if new_type == 'config-owned': return 'config-server-owned' if new_type == 'server-owned': OUT.warn('Configuration error: {} is marked server-owned twice'.format(filename)) return 'server-owned' return self.__cache[filename] # Check if parent type is recursive if parent_type == 'server-owned-dir': return 'server-owned' # unspecified file (and thus virtual) return self.__virtual_files
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
def test_how_to_update(self): OUT.color_off() pro = Protection('', 'horde', '3.0.5', 'portage') strange_htdocs = '/'.join( ('/my', 'strange', 'htdocs', 'where', 'i', 'installed', 'x')) pro.how_to_update([strange_htdocs]) output = sys.stdout.getvalue().split('\n') self.assertEqual( output[3], '* CONFIG_PROTECT="' + strange_htdocs + '" etc-update') # Adding a virtual config protected directory: i = strange_htdocs.replace('/where/i/instaled/x', '') pro.config_protect += ' ' + i pro.how_to_update([strange_htdocs]) output = sys.stdout.getvalue().split('\n') self.assertEqual(output[8], '* etc-update')
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)