Refactor release scripts, automatically update Wandbox on release

This commit is contained in:
Martin Hořeňovský 2017-08-24 21:59:06 +02:00
parent 6c09b45a20
commit dee61df274
6 changed files with 217 additions and 160 deletions

View File

@ -10,117 +10,119 @@ import string
from glob import glob
from scriptCommon import catchPath
from releaseCommon import Version
def generate(v):
includesParser = re.compile( r'\s*#\s*include\s*"(.*)"' )
guardParser = re.compile( r'\s*#.*(TWOBLUECUBES_)?CATCH_.*_INCLUDED')
defineParser = re.compile( r'\s*#define\s+(TWOBLUECUBES_)?CATCH_.*_INCLUDED')
ifParser = re.compile( r'\s*#ifndef (TWOBLUECUBES_)?CATCH_.*_INCLUDED')
endIfParser = re.compile( r'\s*#endif // (TWOBLUECUBES_)?CATCH_.*_INCLUDED')
ifImplParser = re.compile( r'\s*#ifdef CATCH_CONFIG_RUNNER' )
commentParser1 = re.compile( r'^\s*/\*')
commentParser2 = re.compile( r'^ \*')
blankParser = re.compile( r'^\s*$')
includesParser = re.compile( r'\s*#\s*include\s*"(.*)"' )
guardParser = re.compile( r'\s*#.*(TWOBLUECUBES_)?CATCH_.*_INCLUDED')
defineParser = re.compile( r'\s*#define\s+(TWOBLUECUBES_)?CATCH_.*_INCLUDED')
ifParser = re.compile( r'\s*#ifndef (TWOBLUECUBES_)?CATCH_.*_INCLUDED')
endIfParser = re.compile( r'\s*#endif // (TWOBLUECUBES_)?CATCH_.*_INCLUDED')
ifImplParser = re.compile( r'\s*#ifdef CATCH_CONFIG_RUNNER' )
commentParser1 = re.compile( r'^\s*/\*')
commentParser2 = re.compile( r'^ \*')
blankParser = re.compile( r'^\s*$')
seenHeaders = set([])
rootPath = os.path.join( catchPath, 'include/' )
outputPath = os.path.join( catchPath, 'single_include/catch.hpp' )
seenHeaders = set([])
rootPath = os.path.join( catchPath, 'include/' )
outputPath = os.path.join( catchPath, 'single_include/catch.hpp' )
globals = {
'includeImpl' : True,
'ifdefs' : 0,
'implIfDefs' : -1
}
includeImpl = True
for arg in sys.argv[1:]:
arg = string.lower(arg)
if arg == "noimpl":
includeImpl = False
print( "Not including impl code" )
else:
print( "\n** Unrecognised argument: " + arg + " **\n" )
exit(1)
# ensure that the output directory exists (hopefully no races)
outDir = os.path.dirname(outputPath)
if not os.path.exists(outDir):
os.makedirs(outDir)
out = open( outputPath, 'w' )
ifdefs = 0
implIfDefs = -1
def write( line ):
if includeImpl or implIfDefs == -1:
out.write( line )
def insertCpps():
dirs = [os.path.join( rootPath, s) for s in ['', 'internal', 'reporters']]
cppFiles = []
for dir in dirs:
cppFiles += glob(os.path.join(dir, '*.cpp'))
for fname in cppFiles:
dir, name = fname.rsplit(os.path.sep, 1)
dir += os.path.sep
parseFile(dir, name)
def parseFile( path, filename ):
global ifdefs
global implIfDefs
f = open( os.path.join(path, filename), 'r' )
blanks = 0
write( "// start {0}\n".format( filename ) )
for line in f:
if '// ~*~* CATCH_CPP_STITCH_PLACE *~*~' in line:
insertCpps()
continue
elif ifParser.match( line ):
ifdefs = ifdefs + 1
elif endIfParser.match( line ):
ifdefs = ifdefs - 1
if ifdefs == implIfDefs:
implIfDefs = -1
m = includesParser.match( line )
if m:
header = m.group(1)
headerPath, sep, headerFile = header.rpartition( "/" )
if not headerFile in seenHeaders:
if headerFile != "tbc_text_format.h" and headerFile != "clara.h":
seenHeaders.add( headerFile )
if headerPath == "internal" and path.endswith("internal/"):
headerPath = ""
sep = ""
if os.path.exists( path + headerPath + sep + headerFile ):
parseFile( path + headerPath + sep, headerFile )
else:
parseFile( rootPath + headerPath + sep, headerFile )
for arg in sys.argv[1:]:
arg = string.lower(arg)
if arg == "noimpl":
globals['includeImpl'] = False
print( "Not including impl code" )
else:
if ifImplParser.match(line):
implIfDefs = ifdefs
if (not guardParser.match( line ) or defineParser.match( line ) ) and not commentParser1.match( line )and not commentParser2.match( line ):
if blankParser.match( line ):
blanks = blanks + 1
else:
blanks = 0
if blanks < 2 and not defineParser.match(line):
write( line.rstrip() + "\n" )
write( '// end {}\n'.format(filename) )
print( "\n** Unrecognised argument: " + arg + " **\n" )
exit(1)
v = Version()
out.write( "/*\n" )
out.write( " * Catch v{0}\n".format( v.getVersionString() ) )
out.write( " * Generated: {0}\n".format( datetime.datetime.now() ) )
out.write( " * ----------------------------------------------------------\n" )
out.write( " * This file has been merged from multiple headers. Please don't edit it directly\n" )
out.write( " * Copyright (c) {} Two Blue Cubes Ltd. All rights reserved.\n".format( datetime.date.today().year ) )
out.write( " *\n" )
out.write( " * Distributed under the Boost Software License, Version 1.0. (See accompanying\n" )
out.write( " * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n" )
out.write( " */\n" )
out.write( "#ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED\n" )
out.write( "#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED\n" )
# ensure that the output directory exists (hopefully no races)
outDir = os.path.dirname(outputPath)
if not os.path.exists(outDir):
os.makedirs(outDir)
out = open( outputPath, 'w' )
parseFile( rootPath, 'catch.hpp' )
def write( line ):
if globals['includeImpl'] or globals['implIfDefs'] == -1:
out.write( line )
out.write( "#endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED\n\n" )
def insertCpps():
dirs = [os.path.join( rootPath, s) for s in ['', 'internal', 'reporters']]
cppFiles = []
for dir in dirs:
cppFiles += glob(os.path.join(dir, '*.cpp'))
for fname in cppFiles:
dir, name = fname.rsplit(os.path.sep, 1)
dir += os.path.sep
parseFile(dir, name)
print ("Generated single include for Catch v{0}\n".format( v.getVersionString() ) )
def parseFile( path, filename ):
f = open( os.path.join(path, filename), 'r' )
blanks = 0
write( "// start {0}\n".format( filename ) )
for line in f:
if '// ~*~* CATCH_CPP_STITCH_PLACE *~*~' in line:
insertCpps()
continue
elif ifParser.match( line ):
globals['ifdefs'] += 1
elif endIfParser.match( line ):
globals['ifdefs'] -= 1
if globals['ifdefs'] == globals['implIfDefs']:
globals['implIfDefs'] = -1
m = includesParser.match( line )
if m:
header = m.group(1)
headerPath, sep, headerFile = header.rpartition( "/" )
if not headerFile in seenHeaders:
if headerFile != "tbc_text_format.h" and headerFile != "clara.h":
seenHeaders.add( headerFile )
if headerPath == "internal" and path.endswith("internal/"):
headerPath = ""
sep = ""
if os.path.exists( path + headerPath + sep + headerFile ):
parseFile( path + headerPath + sep, headerFile )
else:
parseFile( rootPath + headerPath + sep, headerFile )
else:
if ifImplParser.match(line):
globals['implIfDefs'] = globals['ifdefs']
if (not guardParser.match( line ) or defineParser.match( line ) ) and not commentParser1.match( line )and not commentParser2.match( line ):
if blankParser.match( line ):
blanks = blanks + 1
else:
blanks = 0
if blanks < 2 and not defineParser.match(line):
write( line.rstrip() + "\n" )
write( '// end {}\n'.format(filename) )
out.write( "/*\n" )
out.write( " * Catch v{0}\n".format( v.getVersionString() ) )
out.write( " * Generated: {0}\n".format( datetime.datetime.now() ) )
out.write( " * ----------------------------------------------------------\n" )
out.write( " * This file has been merged from multiple headers. Please don't edit it directly\n" )
out.write( " * Copyright (c) {} Two Blue Cubes Ltd. All rights reserved.\n".format( datetime.date.today().year ) )
out.write( " *\n" )
out.write( " * Distributed under the Boost Software License, Version 1.0. (See accompanying\n" )
out.write( " * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n" )
out.write( " */\n" )
out.write( "#ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED\n" )
out.write( "#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED\n" )
parseFile( rootPath, 'catch.hpp' )
out.write( "#endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED\n\n" )
out.close()
print ("Generated single include for Catch v{0}\n".format( v.getVersionString() ) )
if __name__ == '__main__':
from releaseCommon import Version
generate(Version())

View File

@ -1,13 +1,10 @@
#!/usr/bin/env python
from __future__ import print_function
from releaseCommon import Version
import releaseCommon
v = Version()
v = releaseCommon.Version()
v.incrementMajorVersion()
v.updateVersionFile()
v.updateReadmeFile()
v.updateConanFile()
v.updateConanTestFile()
releaseCommon.performUpdates(v)
print( "Updated Version.hpp, README and Conan to v{0}".format( v.getVersionString() ) )

View File

@ -1,13 +1,10 @@
#!/usr/bin/env python
from __future__ import print_function
from releaseCommon import Version
import releaseCommon
v = Version()
v = releaseCommon.Version()
v.incrementMinorVersion()
v.updateVersionFile()
v.updateReadmeFile()
v.updateConanFile()
v.updateConanTestFile()
releaseCommon.performUpdates(v)
print( "Updated Version.hpp, README and Conan to v{0}".format( v.getVersionString() ) )

View File

@ -1,13 +1,10 @@
#!/usr/bin/env python
from __future__ import print_function
from releaseCommon import Version
import releaseCommon
v = Version()
v = releaseCommon.Version()
v.incrementPatchNumber()
v.updateVersionFile()
v.updateReadmeFile()
v.updateConanFile()
v.updateConanTestFile()
releaseCommon.performUpdates(v)
print( "Updated Version.hpp, README and Conan to v{0}".format( v.getVersionString() ) )

View File

@ -6,6 +6,8 @@ import re
import string
from scriptCommon import catchPath
import generateSingleHeader
import updateWandbox
versionParser = re.compile( r'(\s*static\sVersion\sversion)\s*\(\s*(.*)\s*,\s*(.*)\s*,\s*(.*)\s*,\s*\"(.*)\"\s*,\s*(.*)\s*\).*' )
rootPath = os.path.join( catchPath, 'include/' )
@ -76,44 +78,59 @@ class Version:
for line in lines:
f.write( line + "\n" )
def updateReadmeFile(self):
downloadParser = re.compile( r'<a href=\"https://github.com/philsquared/Catch/releases/download/v\d+\.\d+\.\d+/catch.hpp\">' )
f = open( readmePath, 'r' )
lines = []
for line in f:
def updateReadmeFile(version):
downloadParser = re.compile( r'<a href=\"https://github.com/philsquared/Catch/releases/download/v\d+\.\d+\.\d+/catch.hpp\">' )
success, wandboxLink = updateWandbox.uploadFiles()
if not success:
print('Error when uploading to wandbox: {}'.format(wandboxLink))
exit(1)
f = open( readmePath, 'r' )
lines = []
for line in f:
lines.append( line.rstrip() )
f.close()
f = open( readmePath, 'w' )
for line in lines:
line = downloadParser.sub( r'<a href="https://github.com/philsquared/Catch/releases/download/v{0}/catch.hpp">'.format(version.getVersionString()) , line)
if '[![Try online](https://img.shields.io/badge/try-online-blue.svg)]' in line:
line = '[![Try online](https://img.shields.io/badge/try-online-blue.svg)]({0})'.format(wandboxLink)
f.write( line + "\n" )
def updateConanFile(version):
conanParser = re.compile( r' version = "\d+\.\d+\.\d+.*"')
f = open( conanPath, 'r' )
lines = []
for line in f:
m = conanParser.match( line )
if m:
lines.append( ' version = "{0}"'.format(format(version.getVersionString())) )
else:
lines.append( line.rstrip() )
f.close()
f = open( readmePath, 'w' )
for line in lines:
line = downloadParser.sub( r'<a href="https://github.com/philsquared/Catch/releases/download/v{0}/catch.hpp">'.format(self.getVersionString()) , line)
f.write( line + "\n" )
f.close()
f = open( conanPath, 'w' )
for line in lines:
f.write( line + "\n" )
def updateConanFile(self):
conanParser = re.compile( r' version = "\d+\.\d+\.\d+.*"')
f = open( conanPath, 'r' )
lines = []
for line in f:
m = conanParser.match( line )
if m:
lines.append( ' version = "{0}"'.format(format(self.getVersionString())) )
else:
lines.append( line.rstrip() )
f.close()
f = open( conanPath, 'w' )
for line in lines:
f.write( line + "\n" )
def updateConanTestFile(version):
conanParser = re.compile( r' requires = \"Catch\/\d+\.\d+\.\d+.*@%s\/%s\" % \(username, channel\)')
f = open( conanTestPath, 'r' )
lines = []
for line in f:
m = conanParser.match( line )
if m:
lines.append( ' requires = "Catch/{0}@%s/%s" % (username, channel)'.format(format(version.getVersionString())) )
else:
lines.append( line.rstrip() )
f.close()
f = open( conanTestPath, 'w' )
for line in lines:
f.write( line + "\n" )
def updateConanTestFile(self):
conanParser = re.compile( r' requires = \"Catch\/\d+\.\d+\.\d+.*@%s\/%s\" % \(username, channel\)')
f = open( conanTestPath, 'r' )
lines = []
for line in f:
m = conanParser.match( line )
if m:
lines.append( ' requires = "Catch/{0}@%s/%s" % (username, channel)'.format(format(self.getVersionString())) )
else:
lines.append( line.rstrip() )
f.close()
f = open( conanTestPath, 'w' )
for line in lines:
f.write( line + "\n" )
def performUpdates(version):
# First update version file, so we can regenerate single header and
# have it ready for upload to wandbox, when updating readme
version.updateVersionFile()
generateSingleHeader.generate(version)
updateReadmeFile(version)
updateConanFile(version)
updateConanTestFile(version)

47
scripts/updateWandbox.py Normal file
View File

@ -0,0 +1,47 @@
#!/usr/bin/env python
import json
import os
import urllib2
from scriptCommon import catchPath
def upload(options):
request = urllib2.Request('http://melpon.org/wandbox/api/compile.json')
request.add_header('Content-Type', 'application/json')
response = urllib2.urlopen(request, json.dumps(options))
return json.loads(response.read())
main_file = '''
#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file
#include "catch.hpp"
unsigned int Factorial( unsigned int number ) {
return number <= 1 ? number : Factorial(number-1)*number;
}
TEST_CASE( "Factorials are computed", "[factorial]" ) {
REQUIRE( Factorial(1) == 1 );
REQUIRE( Factorial(2) == 2 );
REQUIRE( Factorial(3) == 6 );
REQUIRE( Factorial(10) == 3628800 );
}
'''
def uploadFiles():
response = upload({
'compiler': 'gcc-head',
'code': main_file,
'codes': [{
'file': 'catch.hpp',
'code': open(os.path.join(catchPath, 'single_include', 'catch.hpp')).read()
}],
'options': 'c++11,cpp-no-pedantic,boost-nothing',
'compiler-option-raw': '-DCATCH_CONFIG_FAST_COMPILE',
'save': True
})
if 'status' in response and not 'compiler_error' in response:
return True, response['url']
else:
return False, response