mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2024-11-15 05:47:56 -07:00
d5d60c6e64
Allows us to migrate off of printf specifiers and have more type-safe formatting facilities. It also allows for custom type support as well. fmt is also on track to have part of it standardized within C++2a, so this will also lessen the transitional work necessary later on by allowing new code to use it. This simply adds the library but doesn't do anything with it yet.
262 lines
8.8 KiB
Python
Executable File
262 lines
8.8 KiB
Python
Executable File
#!/usr/bin/env python
|
|
|
|
"""Manage site and releases.
|
|
|
|
Usage:
|
|
manage.py release [<branch>]
|
|
manage.py site
|
|
"""
|
|
|
|
from __future__ import print_function
|
|
import datetime, docopt, errno, fileinput, json, os
|
|
import re, requests, shutil, sys, tempfile
|
|
from contextlib import contextmanager
|
|
from distutils.version import LooseVersion
|
|
from subprocess import check_call
|
|
|
|
|
|
class Git:
|
|
def __init__(self, dir):
|
|
self.dir = dir
|
|
|
|
def call(self, method, args, **kwargs):
|
|
return check_call(['git', method] + list(args), **kwargs)
|
|
|
|
def add(self, *args):
|
|
return self.call('add', args, cwd=self.dir)
|
|
|
|
def checkout(self, *args):
|
|
return self.call('checkout', args, cwd=self.dir)
|
|
|
|
def clean(self, *args):
|
|
return self.call('clean', args, cwd=self.dir)
|
|
|
|
def clone(self, *args):
|
|
return self.call('clone', list(args) + [self.dir])
|
|
|
|
def commit(self, *args):
|
|
return self.call('commit', args, cwd=self.dir)
|
|
|
|
def pull(self, *args):
|
|
return self.call('pull', args, cwd=self.dir)
|
|
|
|
def push(self, *args):
|
|
return self.call('push', args, cwd=self.dir)
|
|
|
|
def reset(self, *args):
|
|
return self.call('reset', args, cwd=self.dir)
|
|
|
|
def update(self, *args):
|
|
clone = not os.path.exists(self.dir)
|
|
if clone:
|
|
self.clone(*args)
|
|
return clone
|
|
|
|
|
|
def clean_checkout(repo, branch):
|
|
repo.clean('-f', '-d')
|
|
repo.reset('--hard')
|
|
repo.checkout(branch)
|
|
|
|
|
|
class Runner:
|
|
def __init__(self, cwd):
|
|
self.cwd = cwd
|
|
|
|
def __call__(self, *args, **kwargs):
|
|
kwargs['cwd'] = kwargs.get('cwd', self.cwd)
|
|
check_call(args, **kwargs)
|
|
|
|
|
|
def create_build_env():
|
|
"""Create a build environment."""
|
|
class Env:
|
|
pass
|
|
env = Env()
|
|
|
|
# Import the documentation build module.
|
|
env.fmt_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
sys.path.insert(0, os.path.join(env.fmt_dir, 'doc'))
|
|
import build
|
|
|
|
env.build_dir = 'build'
|
|
env.versions = build.versions
|
|
|
|
# Virtualenv and repos are cached to speed up builds.
|
|
build.create_build_env(os.path.join(env.build_dir, 'virtualenv'))
|
|
|
|
env.fmt_repo = Git(os.path.join(env.build_dir, 'fmt'))
|
|
return env
|
|
|
|
|
|
@contextmanager
|
|
def rewrite(filename):
|
|
class Buffer:
|
|
pass
|
|
buffer = Buffer()
|
|
if not os.path.exists(filename):
|
|
buffer.data = ''
|
|
yield buffer
|
|
return
|
|
with open(filename) as f:
|
|
buffer.data = f.read()
|
|
yield buffer
|
|
with open(filename, 'w') as f:
|
|
f.write(buffer.data)
|
|
|
|
|
|
fmt_repo_url = 'git@github.com:fmtlib/fmt'
|
|
|
|
|
|
def update_site(env):
|
|
env.fmt_repo.update(fmt_repo_url)
|
|
|
|
doc_repo = Git(os.path.join(env.build_dir, 'fmtlib.github.io'))
|
|
doc_repo.update('git@github.com:fmtlib/fmtlib.github.io')
|
|
|
|
for version in env.versions:
|
|
clean_checkout(env.fmt_repo, version)
|
|
target_doc_dir = os.path.join(env.fmt_repo.dir, 'doc')
|
|
# Remove the old theme.
|
|
for entry in os.listdir(target_doc_dir):
|
|
path = os.path.join(target_doc_dir, entry)
|
|
if os.path.isdir(path):
|
|
shutil.rmtree(path)
|
|
# Copy the new theme.
|
|
for entry in ['_static', '_templates', 'basic-bootstrap', 'bootstrap',
|
|
'conf.py', 'fmt.less']:
|
|
src = os.path.join(env.fmt_dir, 'doc', entry)
|
|
dst = os.path.join(target_doc_dir, entry)
|
|
copy = shutil.copytree if os.path.isdir(src) else shutil.copyfile
|
|
copy(src, dst)
|
|
# Rename index to contents.
|
|
contents = os.path.join(target_doc_dir, 'contents.rst')
|
|
if not os.path.exists(contents):
|
|
os.rename(os.path.join(target_doc_dir, 'index.rst'), contents)
|
|
# Fix issues in reference.rst/api.rst.
|
|
for filename in ['reference.rst', 'api.rst']:
|
|
pattern = re.compile('doxygenfunction.. (bin|oct|hexu|hex)$', re.M)
|
|
with rewrite(os.path.join(target_doc_dir, filename)) as b:
|
|
b.data = b.data.replace('std::ostream &', 'std::ostream&')
|
|
b.data = re.sub(pattern, r'doxygenfunction:: \1(int)', b.data)
|
|
b.data = b.data.replace('std::FILE*', 'std::FILE *')
|
|
b.data = b.data.replace('unsigned int', 'unsigned')
|
|
b.data = b.data.replace('operator""_', 'operator"" _')
|
|
# Fix a broken link in index.rst.
|
|
index = os.path.join(target_doc_dir, 'index.rst')
|
|
with rewrite(index) as b:
|
|
b.data = b.data.replace(
|
|
'doc/latest/index.html#format-string-syntax', 'syntax.html')
|
|
# Build the docs.
|
|
html_dir = os.path.join(env.build_dir, 'html')
|
|
if os.path.exists(html_dir):
|
|
shutil.rmtree(html_dir)
|
|
include_dir = env.fmt_repo.dir
|
|
if LooseVersion(version) >= LooseVersion('5.0.0'):
|
|
include_dir = os.path.join(include_dir, 'include', 'fmt')
|
|
elif LooseVersion(version) >= LooseVersion('3.0.0'):
|
|
include_dir = os.path.join(include_dir, 'fmt')
|
|
import build
|
|
build.build_docs(version, doc_dir=target_doc_dir,
|
|
include_dir=include_dir, work_dir=env.build_dir)
|
|
shutil.rmtree(os.path.join(html_dir, '.doctrees'))
|
|
# Create symlinks for older versions.
|
|
for link, target in {'index': 'contents', 'api': 'reference'}.items():
|
|
link = os.path.join(html_dir, link) + '.html'
|
|
target += '.html'
|
|
if os.path.exists(os.path.join(html_dir, target)) and \
|
|
not os.path.exists(link):
|
|
os.symlink(target, link)
|
|
# Copy docs to the website.
|
|
version_doc_dir = os.path.join(doc_repo.dir, version)
|
|
try:
|
|
shutil.rmtree(version_doc_dir)
|
|
except OSError as e:
|
|
if e.errno != errno.ENOENT:
|
|
raise
|
|
shutil.move(html_dir, version_doc_dir)
|
|
|
|
|
|
def release(args):
|
|
env = create_build_env()
|
|
fmt_repo = env.fmt_repo
|
|
|
|
branch = args.get('<branch>')
|
|
if branch is None:
|
|
branch = 'master'
|
|
if not fmt_repo.update('-b', branch, fmt_repo_url):
|
|
clean_checkout(fmt_repo, branch)
|
|
|
|
# Convert changelog from RST to GitHub-flavored Markdown and get the
|
|
# version.
|
|
changelog = 'ChangeLog.rst'
|
|
changelog_path = os.path.join(fmt_repo.dir, changelog)
|
|
import rst2md
|
|
changes, version = rst2md.convert(changelog_path)
|
|
cmakelists = 'CMakeLists.txt'
|
|
for line in fileinput.input(os.path.join(fmt_repo.dir, cmakelists),
|
|
inplace=True):
|
|
prefix = 'set(FMT_VERSION '
|
|
if line.startswith(prefix):
|
|
line = prefix + version + ')\n'
|
|
sys.stdout.write(line)
|
|
|
|
# Update the version in the changelog.
|
|
title_len = 0
|
|
for line in fileinput.input(changelog_path, inplace=True):
|
|
if line.decode('utf-8').startswith(version + ' - TBD'):
|
|
line = version + ' - ' + datetime.date.today().isoformat()
|
|
title_len = len(line)
|
|
line += '\n'
|
|
elif title_len:
|
|
line = '-' * title_len + '\n'
|
|
title_len = 0
|
|
sys.stdout.write(line)
|
|
|
|
# Add the version to the build script.
|
|
script = os.path.join('doc', 'build.py')
|
|
script_path = os.path.join(fmt_repo.dir, script)
|
|
for line in fileinput.input(script_path, inplace=True):
|
|
m = re.match(r'( *versions = )\[(.+)\]', line)
|
|
if m:
|
|
line = '{}[{}, \'{}\']\n'.format(m.group(1), m.group(2), version)
|
|
sys.stdout.write(line)
|
|
|
|
fmt_repo.checkout('-B', 'release')
|
|
fmt_repo.add(changelog, cmakelists, script)
|
|
fmt_repo.commit('-m', 'Update version')
|
|
|
|
# Build the docs and package.
|
|
run = Runner(fmt_repo.dir)
|
|
run('cmake', '.')
|
|
run('make', 'doc', 'package_source')
|
|
update_site(env)
|
|
|
|
# Create a release on GitHub.
|
|
fmt_repo.push('origin', 'release')
|
|
params = {'access_token': os.getenv('FMT_TOKEN')}
|
|
r = requests.post('https://api.github.com/repos/fmtlib/fmt/releases',
|
|
params=params,
|
|
data=json.dumps({'tag_name': version,
|
|
'target_commitish': 'release',
|
|
'body': changes, 'draft': True}))
|
|
if r.status_code != 201:
|
|
raise Exception('Failed to create a release ' + str(r))
|
|
id = r.json()['id']
|
|
uploads_url = 'https://uploads.github.com/repos/fmtlib/fmt/releases'
|
|
package = 'fmt-{}.zip'.format(version)
|
|
r = requests.post(
|
|
'{}/{}/assets?name={}'.format(uploads_url, id, package),
|
|
headers={'Content-Type': 'application/zip'},
|
|
params=params, data=open('build/fmt/' + package, 'rb'))
|
|
if r.status_code != 201:
|
|
raise Exception('Failed to upload an asset ' + str(r))
|
|
|
|
|
|
if __name__ == '__main__':
|
|
args = docopt.docopt(__doc__)
|
|
if args.get('release'):
|
|
release(args)
|
|
elif args.get('site'):
|
|
update_site(create_build_env())
|