Exemple #1
0
class Updates(object):
    """ Run through the working directories and sites updating them. """

    def __init__(self):
        self.settings = Settings()
        self.install()
        self.utilities = Utils()
        self.working_dirs = self.settings.get('workingDir')
        self.single_site = ''
        self.alias_file = None
        if isinstance(self.working_dirs, str):
            self.working_dirs = [self.working_dirs]
        # by design, SingleSite setting only works with single working directory
        if len(self.working_dirs) == 1:
            self.single_site = self.settings.get('singleSite')

    def install(self):
        """ Basic Installation of Drupdates. """
        base_dir = self.settings.get('baseDir')
        backup_dir = self.settings.get('backupDir')
        dirs = [backup_dir, base_dir]
        for directory in dirs:
            Utils.check_dir(directory)
        current_dir = os.path.dirname(os.path.realpath(__file__))
        src = os.path.join(current_dir, "templates/settings.template")
        settings_file = os.path.join(Utils.check_dir(base_dir), 'settings.yaml')
        instructions_url = "http://drupdates.readthedocs.org/en/latest/setup/"
        if not os.path.isfile(settings_file):
            shutil.copy(src, settings_file)
            msg = "The Settings file {0} was created and needs updated.\n".format(settings_file)
            msg += "See {0} for instructions".format(instructions_url)
            print(msg)
            sys.exit(1)
        current_settings = open(settings_file, 'r')
        settings = yaml.load(current_settings)
        if 'repoDict' in settings and 'example' in settings['repoDict']['value']:
            msg = "The default Settings file, {0}, needs updated. \n ".format(settings_file)
            msg += "See {0} for instructions".format(instructions_url)
            print(msg)
            sys.exit(1)

    def run_updates(self):
        """ Drupdates main function. """
        if self.settings.get('debug'):
            self.utilities.write_debug_file()
        report = {}
        for current_working_dir in self.working_dirs:
            try:
                current_working_dir = Utils.check_dir(current_working_dir)
                self.utilities.load_dir_settings(current_working_dir)
                update = self.update_sites(current_working_dir)
                report[current_working_dir] = update
            except DrupdatesError as update_error:
                report[current_working_dir] = update_error.msg
                if update_error.level >= 30:
                    break
                else:
                    continue
        try:
            reporting = Reports()
        except DrupdatesError as reports_error:
            print("Reporting error: \n {0}".format(reports_error.msg))
            sys.exit(1)
        reporting.send(report)

    def update_sites(self, working_dir):
        """ Run updates for a working directory's sites. """
        report = {}
        self.aliases(working_dir)
        blacklist = self.settings.get('blacklist')
        sites = Repos().get()
        if self.single_site:
            sites = {self.single_site : sites[self.single_site]}
        for site_name, ssh in sites.items():
            if self.settings.get('verbose'):
                msg = "Drupdates is working on the site: {0} ...".format(site_name)
                print(msg)
            report[site_name] = {}
            if site_name in blacklist:
                continue
            self.utilities.load_dir_settings(working_dir)
            for phase in self.settings.get("drupdatesPhases"):
                mod = __import__('drupdates.' + phase['name'].lower(), fromlist=[phase])
                class_ = getattr(mod, phase['name'])
                instance = class_(site_name, ssh, working_dir)
                result = ''
                try:
                    call = getattr(instance, phase['method'])
                    result = call()
                except DrupdatesError as error:
                    result = error.msg
                    if error.level < 30:
                        break
                    if error.level >= 30:
                        msg = "Drupdates: fatal error\n Drupdates returned: {0}".format(result)
                        raise DrupdatesError(error.level, msg)
                finally:
                    report[site_name][phase['name']] = result
            self.settings.reset()

        self.delete_files()
        return report

    def aliases(self, working_dir):
        """ Build a Drush alias file in $HOME/.drush, with alises to be used later.

        Notes:
        The file name is controlled by the drushAliasFile settings
        All of the aliases will be prefixed with "drupdates" if the default file name
        is retained
        """

        alias_file_name = self.settings.get('drushAliasFile')
        drush_folder = os.path.join(expanduser('~'), '.drush')
        self.alias_file = os.path.join(drush_folder, alias_file_name)
        if not os.path.isdir(drush_folder):
            try:
                os.makedirs(drush_folder)
            except OSError as error:
                msg = "Could not create ~/.drush folder \n Error: {0}".format(error.strerror)
                raise DrupdatesError(30, msg)
        current_dir = os.path.dirname(os.path.realpath(__file__))
        # Symlink the Drush aliases file
        src = os.path.join(current_dir, "templates/aliases.template")
        doc = open(src)
        template = Template(doc.read())
        doc.close()
        try:
            filepath = open(self.alias_file, 'w')
        except OSError as error:
            msg = "Could not create {0} file\n Error: {1}".format(self.alias_file, error.strerror)
            raise DrupdatesError(30, msg)
        webroot_dir = self.settings.get('webrootDir')
        filepath.write(template.safe_substitute(path=working_dir,
                                                webroot=webroot_dir))

        filepath.close()

    def delete_files(self):
        """ Clean up files used by Drupdates. """
        if os.path.isfile(self.alias_file):
            try:
                os.remove(self.alias_file)
            except OSError as error:
                msg = "Clean-up error, couldn't remove {0}\n".format(self.alias_file)
                msg += "Error: {1}".format(error.strerror)
                print(msg)
        return True
Exemple #2
0
class Sitebuild(object):
    """ Build out the repository folder. """

    def __init__(self, site_name, ssh, working_dir):
        self.settings = Settings()
        self._site_name = site_name
        self.site_dir = os.path.join(working_dir, self._site_name)
        self.ssh = ssh
        self.utilities = Utils()
        self.si_files = copy.copy(self.settings.get('drushSiFiles'))

    def build(self):
        """ Core build method. """
        working_branch = self.settings.get('workingBranch')
        try:
            Utils.remove_dir(self.site_dir)
        except DrupdatesError as remove_error:
            raise DrupdatesBuildError(20, remove_error.msg)
        self.utilities.sys_commands(self, 'preBuildCmds')
        repository = Repo.init(self.site_dir)
        remote = git.Remote.create(repository, self._site_name, self.ssh)
        try:
            remote.fetch(working_branch, depth=1)
        except git.exc.GitCommandError as error:
            msg = "{0}: Could not checkout {1}. \n".format(self._site_name, working_branch)
            msg += "Error: {0}".format(error)
            raise DrupdatesBuildError(20, msg)
        git_repo = repository.git
        git_repo.checkout('FETCH_HEAD', b=working_branch)
        self.utilities.load_dir_settings(self.site_dir)
        self.standup_site()
        try:
            repo_status = Drush.call(['st'], self._site_name, True)
        except DrupdatesError as st_error:
            raise DrupdatesBuildError(20, st_error.msg)
        finally:
            self.file_cleanup()
        if not 'bootstrap' in repo_status:
            msg = "{0} failed to Stand-up properly after running drush qd".format(self._site_name)
            raise DrupdatesBuildError(20, msg)
        self.utilities.sys_commands(self, 'postBuildCmds')
        return "Site build for {0} successful".format(self._site_name)

    def standup_site(self):
        """ Using the drush core-quick-drupal (qd) command stand-up a Drupal site.

        This will:
        - Perform site install with sqlite.
        - If needed, build webroot from a make file.
        - Install any sub sites (ie multi-sites)
        - Ensure that all the files in the web root are writable.

        """
        qd_settings = self.settings.get('qdCmds')
        qd_cmds = copy.copy(qd_settings)
        backup_dir = Utils.check_dir(self.settings.get('backupDir'))
        qd_cmds += ['--backup-dir=' + backup_dir]
        try:
            qd_cmds.remove('--no-backup')
        except ValueError:
            pass
        if self.settings.get('useMakeFile'):
            make_file = self.utilities.find_make_file(self._site_name, self.site_dir)
            if make_file:
                qd_cmds += ['--makefile=' + make_file]
            else:
                msg = "Can't find make file in {0} for {1}".format(self.site_dir, self._site_name)
                raise DrupdatesBuildError(20, msg)
            if self.settings.get('buildSource') == 'make':
                qd_cmds.remove('--use-existing')
        try:
            Drush.call(qd_cmds, self._site_name)
            sub_sites = Drush.get_sub_site_aliases(self._site_name)
            for alias, data in sub_sites.items():
                Drush.call(qd_cmds, alias)
                # Add sub site settings.php to list of file_cleanup() files.
                sub_site_st = Drush.call(['st'], alias, True)
                self.si_files.append(sub_site_st['site'] + '/settings.php')
                self.si_files.append(sub_site_st['files'] + '/.htaccess')
                self.si_files.append(sub_site_st['site'])
        except DrupdatesError as standup_error:
            raise standup_error

    def file_cleanup(self):
        """ Drush sets the folder permissions for some file to be 0444, convert to 0777. """
        drush_dd = Drush.call(['dd', '@drupdates.' + self._site_name])
        site_webroot = drush_dd[0]
        for name in self.si_files:
            complete_name = os.path.join(site_webroot, name)
            if os.path.isfile(complete_name) or os.path.isdir(complete_name):
                try:
                    os.chmod(complete_name, 0o777)
                except OSError:
                    msg = "Couldn't change file permission for {0}".format(complete_name)
                    raise DrupdatesBuildError(20, msg)