# 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, izip_longest from PIL import ImageFont import projects PADDING = 8 BASE_TAGS_URL = 'http://governance.openstack.org/reference/tags/' COLOR_SCHEME = { "brightgreen": "#4c1", "green": "#97CA00", "yellow": "#dfb317", "yellowgreen": "#a4a61d", "orange": "#fe7d37", "red": "#e05d44", "blue": "#007ec6", "grey": "#555", "lightgrey": "#9f9f9f", } 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 _generate_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 _generate_tag_badges(tags): badges = [] badges.append(_generate_badge('project', 'official')) for tag in tags: # NOTE(flaper87): will submit other patches to make these # tags consistent with the rest. if tag in ['starter-kit:compute', 'tc-approved-release']: group, tname = 'tc', tag else: group, tname = tag.split(':') link = BASE_TAGS_URL + '%s.html' % tag.replace(':', '_') badges.append(_generate_badge(group, tname, link, colorscheme='blue')) return badges def _organize_badges(badges): sbadges = sorted(badges, key=lambda badge: badge['width']) # NOTE(flaper87): 4 is the number of columns ziped = list(izip_longest(*(iter(sbadges),) * 4)) result = [] for y, group in enumerate(ziped): result.append([]) col_x = 0 for x, badge in enumerate(group): # NOTE(flaper87): izip_longest fills the # empty slots with None. We don't care about # those. if badge is None: break width_badge = ziped[-1][x] if width_badge is None: if len(ziped) > 1: width_badge = ziped[-2][x] else: width_badge = badge badge['height'] = 20 badge['svg_y'] = (20 + 4) * y # NOTE(flaper87): 3 is just an extra padding in case there are two badges # with the same width in the same row badge['svg_x'] = col_x col_x += width_badge['width'] + 3 result[y].append(badge) return result def _to_svg(badges): for badge in badges: yield FLAT_BADGE_TEMPLATE.format(**badge).encode('utf-8') def _generate_teams_badges(app): 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 = _generate_badge('project', 'unofficial', colorscheme='red') svg = FLAT_BADGE_TEMPLATE.format(**svg_data).encode('utf-8') with open(filename, 'w') as f: f.write(SVG_ROOT.format(height=20, width=106, svg=svg)) files.append(filename) for team, info in all_teams.items(): app.info('generating team badge for %s' % team) for name, deliverable in info['deliverables'].items(): tags = info.get('tags', []) + deliverable.get('tags', []) badges = _organize_badges(_generate_tag_badges(tags)) svg = '\n'.join(_to_svg(chain(*badges))) root_width = badges[-1][-1]['svg_x'] + badges[-1][-1]['width'] 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): app.info('loading badges extension') _generate_teams_badges(app)