# Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. """ Generate badges for the projects """ import os from itertools import chain from itertools import zip_longest from PIL import ImageFont from sphinx.util import logging import projects LOG = logging.getLogger(__name__) NUM_COL = 4 PADDING = 8 BADGE_SPACING = 4 COLOR_SCHEME = { "brightgreen": "#4c1", "green": "#97CA00", "yellow": "#dfb317", "yellowgreen": "#a4a61d", "orange": "#fe7d37", "red": "#e05d44", "blue": "#007ec6", "grey": "#555", "lightgrey": "#9f9f9f", } OPENSTACK_SVG = """OpenStack_Logo_Mark""" SVG_ROOT = """ This is a container for a set of OpenStack badges indicating the status and features of this project and its repository {svg} """ FLAT_BADGE_TEMPLATE = """ {left_text}:{right_text} {left_text} {left_text} {right_text} {right_text} """ def _badge(left_text, right_text, link=None, colorscheme='brightgreen'): font = ImageFont.truetype('DejaVuSans.ttf', 11) left_width = font.getsize(left_text)[0] + PADDING right_width = font.getsize(right_text)[0] + PADDING width = left_width + right_width data = { 'link': link or '', 'svg_x': 0, 'svg_y': 0, 'color': COLOR_SCHEME[colorscheme], 'width': width, 'left_width': left_width, 'left_text': left_text, 'left_x': left_width / 2, 'right_width': right_width, 'right_text': right_text, 'right_x': left_width + right_width / 2 - 1, } return data def _get_base_badges(): return [ _badge('openstack', 'community project', 'https://governance.openstack.org/tc/reference/projects/'), _badge('cii best practices', 'passing', 'https://bestpractices.coreinfrastructure.org/projects/246') ] def _organize_badges(base_badges): # Arrange badges in NUM_COL columns, filling the rest with width=0 badges ziped = list(zip_longest(*(iter(base_badges),) * NUM_COL, fillvalue={'width': 0})) result = [] # Calculate x,y for each badge, leaving BADGE_SPACING between them for line, group in enumerate(ziped): # Start a new line at x=25, after the openstack logo result.append([]) x = 25 for col, badge in enumerate(group): # Skip width=0 badges if badge['width'] == 0: break # Column width is the width of the largest badge in column col_width = max(ziped, key=lambda s: s[col]['width'])[col]['width'] badge['height'] = 20 badge['svg_y'] = (20 + BADGE_SPACING) * line badge['svg_x'] = x x += col_width + BADGE_SPACING result[line].append(badge) return result def _to_svg(badges): yield OPENSTACK_SVG for badge in badges: yield FLAT_BADGE_TEMPLATE.format(**badge) def _generate_teams_badges(app, exception=None): LOG.info('Generating team badges') all_teams = projects.get_project_data() files = [] badges_dir = os.path.join(app.outdir, 'badges') if not os.path.exists(badges_dir): os.mkdir(badges_dir) filename = os.path.join(badges_dir, 'project-unofficial.svg') svg_data = _badge('project', 'unofficial', colorscheme='red') svg = FLAT_BADGE_TEMPLATE.format(**svg_data) with open(filename, 'w', encoding='utf-8') as f: f.write(SVG_ROOT.format(height=20, width=106, svg=svg)) files.append(filename) for team, info in all_teams.items(): LOG.info('generating team badge for %s' % team) for name, deliverable in info['deliverables'].items(): badges = _organize_badges(_get_base_badges()) svg = '\n'.join(_to_svg(chain(*badges))) root_width = max([bdg_row[-1]['width'] + bdg_row[-1]['svg_x'] for bdg_row in badges]) root_height = badges[-1][0]['svg_y'] + badges[-1][0]['height'] for repo in deliverable.get('repos', []): repo_name = repo.split('/')[1] filename = os.path.join(badges_dir, '%s.svg' % projects.slugify(repo_name)) with open(filename, 'w') as f: f.write(SVG_ROOT.format(height=root_height, width=root_width, svg=svg)) files.append(filename) return files def setup(app): LOG.info('loading badges extension') app.connect('build-finished', _generate_teams_badges)