Example #1
0
def upstream_revision_tests(project, revision, log=None):
    """ This function run upstream tests on all sources fonts in project.

        This mean that success (aka getting any result) should be occasional
        particular case. Because data and set of folders are changing during
        font development process.

        Args:
            project: A :class:`~bakery.models.Project` instance
            revision: Git revision

        Returns:
            A dict with serialized tests results formatted by `repr_testcase`.
    """
    param = {'login': project.login, 'id': project.id, 'revision': revision}

    _in = joinroot('%(login)s/%(id)s.in/' % project)
    _out_folder = joinroot('%(login)s/%(id)s.out/utests/' % param)
    _out_yaml = op.join(_out_folder, '%(revision)s.yaml' % param)

    # if op.exists(_out_yaml):
    #     return yaml.safe_load(open(_out_yaml, 'r'))

    if not op.exists(_out_folder):
        os.makedirs(_out_folder)

    result = {}
    os.chdir(_in)

    try:
        git_checkout(_in, revision)

        result[project.clone] = run_set(_in, 'upstream-repo', log=log)

        ufo_dirs, ttx_files, metadata_files = get_sources_lists(_in)

        for font in ufo_dirs:
            if op.exists(op.join(_in, font)):
                result[font] = run_set(op.join(_in, font), 'upstream', log=log)

        for metadata_path in metadata_files:
            result[metadata_path] = run_set(metadata_path, 'metadata', log=log)

        for font in ttx_files:
            if op.exists(op.join(_in, font)):
                result[font] = run_set(op.join(_in, font), 'upstream-ttx', log=log)

        l = open(_out_yaml, mode='w')
        l.write(yaml.safe_dump(result))
        l.close()

        return yaml.safe_load(open(_out_yaml, 'r'))
    except Exception, ex:
        if log:
            log.write('UPSTREAM: FAILED')
            log.write('Details: %s' % ex)
        return {}
Example #2
0
def generate_subsets_coverage_list(project, log=None):
    """ Generates available subsets from project sources.

        Method writes result to yaml file to avoid calling pyfontaine
        api each time.

        Args:
            project: A :class:`~bakery.project.models.Project` instance
            log: A :class:`~bakery.utils.RedisFd` instance

        Returns:
            Sorted subsets from prepared yaml file in tuple
            [(common_name, coverage),]

    """
    from .app import app
    if log:
        log.write('PyFontaine subsets with coverage values\n')

    _in = joinroot('%(login)s/%(id)s.in/' % project)
    ufo_dirs, ttx_files, _ = get_sources_lists(_in)

    _out_yaml = op.join(app.config['DATA_ROOT'],
                        '%(login)s/%(id)s.out/fontaine.yml' % project)
    if op.exists(_out_yaml):
        return sorted(yaml.safe_load(open(_out_yaml, 'r')).items())

    if not op.exists(op.dirname(_out_yaml)):
        os.makedirs(op.dirname(_out_yaml), log=log)

    source_fonts_paths = []
    # `get_sources_list` returns list of paths relative to root.
    # To complete to absolute paths use python os.path.join method
    # on root and path
    for path in ufo_dirs + ttx_files:
        source_fonts_paths.append(op.join(_in, path))
    subsets = get_subsets_coverage_data(source_fonts_paths, log)

    contents = yaml.safe_dump(subsets)

    yamlf = codecs.open(_out_yaml, mode='w', encoding="utf-8")
    yamlf.write(contents)
    yamlf.close()

    return sorted(yaml.safe_load(open(_out_yaml, 'r')).items())
Example #3
0
def project_git_sync(project):
    """ Sync git repo, or download it if it doesn't yet exist.

    Args:
        project: A :class:`~bakery.models.Project` instance
        log: A :class:`~bakery.utils.RedisFd` instance
    """
    from bakery.app import db, app
    project.is_ready = False
    db.session.add(project)
    db.session.commit()
    db.session.refresh(project)

    client = redis.StrictRedis()

    _in = joinroot('%(login)s/%(id)s.in/' % project)
    _out = joinroot('%(login)s/%(id)s.out/' % project)
    if not op.exists(_out):
        os.makedirs(_out)

    try:
        os.remove(op.join(_out, 'fontaine.yml'))
    except OSError:
        pass

    try:
        os.remove(op.join(_out, 'upstream.log'))
    except OSError:
        pass

    log = RedisFd(op.join(_out, 'upstream.log'))
    # Create the incoming repo directory (_in) if it doesn't exist
    if not op.exists(_in):
        os.makedirs(op.join(app.config['DATA_ROOT'], _in), log=log)

    # Update _in if it already exists with a .git directory
    from git import Repo, InvalidGitRepositoryError
    try:
        repo = Repo(_in)
        log.write('$ git reset --hard\n')
        log.write(repo.git.reset(hard=True) + '\n')
        log.write('$ git clean --force\n')
        repo.git.clean(force=True)
        log.write('$ git pull origin master\n')
        repo.remotes.origin.pull()
    except InvalidGitRepositoryError:
        # clone the repository
        # log.write('Copying Git Repository\n', prefix='### ')
        try:
            # TODO in the future, to validate the URL string use
            # http://schacon.github.io/git/git-ls-remote.html
            # http://stackoverflow.com/questions/9610131/how-to-check-the-validity-of-a-remote-git-repository-url
            prun(('git clone --progress --depth=100'
                  ' --branch=master %(clone)s .') % project, cwd=_in, log=log)
        except:
            # if the clone action didn't work, just copy it
            # if this is a file URL, copy the files, and set up
            # the _in directory as a git repo
            if project.clone[:7] == "file://":
                # cp recursively, keeping all attributes, not following
                # symlinks, not deleting existing files, verbosely
                prun('cp -a %(clone)s .' % project, cwd=_in, log=log)
                #
                prun('git init .', cwd=_in, log=log)
                prun('git add *', cwd=_in, log=log)
                msg = "Initial commit made automatically by Font Bakery"
                prun('git commit -a -m "%s"' % msg, cwd=_in, log=log)
            else:
                raise
        # Now we have it, create an initial project state
        finally:
            config = project.config

    generate_subsets_coverage_list(project, log=log)

    revision = prun("git rev-parse --short HEAD", cwd=_in).strip()
    upstream_revision_tests(project, revision, log=log)

    log.write('End: Repository is ready. Please Setup\n', prefix='### ')
    # set project state as ready after sync is done
    project.is_ready = True
    db.session.add(project)
    db.session.commit()

    import json
    client.publish('global:%s' % project.login,
                   json.dumps({'type': 'UPSTREAMFINISHED',
                               'project_id': project.id}))