Skip to content

Instantly share code, notes, and snippets.

@gimmi
Last active December 19, 2015 10:59
Show Gist options
  • Save gimmi/5944681 to your computer and use it in GitHub Desktop.
Save gimmi/5944681 to your computer and use it in GitHub Desktop.
Python build script
import os, glob, shutil, subprocess, buildutil
framework_version = '4.0.30319'
build_configuration = 'Release'
build_platform = 'Any CPU'
project_version = '3.0.0'
prerelease = True
build_number = 0
nuget_package_source = 'https://nuget.org/api/v2/'
project_name = 'MyProject'
project_authors = 'myself'
project_description = 'MyProject'
def nuget_version():
ret = project_version
if prerelease:
ret += '-b%06d' % build_number
return ret
def bjoin(*args):
base_path = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
return os.path.join(base_path, *args)
def install_deps():
subprocess.check_call([bjoin('tools', 'NuGet.exe'), 'install', 'NUnit.Runners', '-Version', '2.6.2', '-ExcludeVersion', '-OutputDirectory', bjoin('tools'), '-Source', nuget_package_source])
for pkg_cfg in glob.glob('src/*/packages.config'):
subprocess.check_call([
bjoin('tools', 'NuGet.exe'),
'install', pkg_cfg,
'-OutputDirectory', bjoin('packages'),
'-Source', nuget_package_source
])
def assembly_info():
shared_assembly_info = """\
[assembly: System.Reflection.AssemblyProduct("{name}")]
[assembly: System.Reflection.AssemblyCopyright("")]
[assembly: System.Reflection.AssemblyTrademark("")]
[assembly: System.Reflection.AssemblyCompany("")]
[assembly: System.Reflection.AssemblyConfiguration("{cfg}")]
[assembly: System.Reflection.AssemblyVersion("{ver}.0")]
[assembly: System.Reflection.AssemblyFileVersion("{ver}.0")]
[assembly: System.Reflection.AssemblyInformationalVersion("{nuget_ver}")]
""".format(name=project_name, cfg=build_configuration, ver=project_version, nuget_ver=nuget_version())
with open(bjoin('src', 'SharedAssemblyInfo.cs'), 'w') as f:
f.write(shared_assembly_info)
def compile():
msbuild_path = os.path.join(os.environ['SystemRoot'], 'Microsoft.NET', 'Framework', 'v' + framework_version, 'MSBuild.exe')
subprocess.check_call([
msbuild_path, '/verbosity:minimal', '/nologo',
bjoin('src', project_name + '.sln'),
'/t:Rebuild',
'/p:Configuration=' + build_configuration +';Platform=' + build_platform
])
def test():
nunit_command = [
bjoin('tools', 'NUnit.Runners', 'tools', 'nunit-console.exe'),
'/nologo' ,
'/noresult' ,
'/framework=' + framework_version
]
nunit_command.extend(glob.glob('src/*/bin/' + build_configuration +'/*.Tests.dll'))
subprocess.check_call(nunit_command)
def pack():
out_dir = bjoin('out')
if os.path.exists(out_dir): shutil.rmtree(out_dir)
shutil.copytree(bjoin('src', project_name, 'bin', build_configuration), bjoin('out', 'nupkg', 'lib', 'net40'))
nuspec_content = """\
<?xml version="1.0"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>{id}</id>
<version>{version}</version>
<authors>{authors}</authors>
<owners>{authors}</owners>
<description>{description}</description>
</metadata>
</package>
""".format(id=project_name, version=nuget_version(), authors=project_authors, description=project_description)
nuspec_file = bjoin('out', 'nupkg', 'Package.nuspec')
with open(nuspec_file, 'w') as f:
f.write(nuspec_content)
subprocess.check_call([bjoin('tools', 'NuGet.exe'), 'pack', nuspec_file, '-Symbols', '-OutputDirectory', out_dir])
def publish():
nupkg_file = bjoin('out', project_name + '.' + nuget_version() + '.nupkg')
subprocess.check_call([bjoin('tools', 'NuGet.exe'), 'push', nupkg_file, '-Source', nuget_package_source])
if __name__ == '__main__':
buildutil.main()
import sys
ARGUMENT_CONVERTERS = {
str: lambda x: x,
int: lambda x: int(x),
bool: lambda x: x.lower() in ['true', 't', 'y', 'yes', '1']
}
def main():
build_module = __import__('__main__')
args = sys.argv[1:]
run(build_module, args, ironpython_cprint)
def run(build_module, args, cprint):
try:
task_names = parse_args(build_module, args)
dump_cfg(build_module, cprint)
for task_name in task_names:
cprint('Executing %s' % task_name, 'Cyan')
task = getattr(build_module, task_name)
task()
cprint('Build Succeeded!', 'Green')
except:
cprint('Build Failed!', 'Red')
raise
def parse_args(build_module, args):
arg_name = None
tasks = []
for arg in args:
if arg.startswith('--'):
arg_name = arg[2:]
elif arg_name:
arg_type = type(getattr(build_module, arg_name, ''))
arg_convrter = ARGUMENT_CONVERTERS[arg_type]
setattr(build_module, arg_name, arg_convrter(arg))
arg_name = None
else:
add_task(build_module, tasks, arg)
if not tasks:
add_task(build_module, tasks, 'default')
return tasks
def add_task(build_module, tasks, task_name):
task = getattr(build_module, task_name, None)
if type(task) is list:
for task_name in task:
add_task(build_module, tasks, task_name)
else:
tasks.append(task_name)
def dump_cfg(build_module, cprint):
names = [n for n in dir(build_module) if not n.startswith('_') and type(getattr(build_module, n)) in ARGUMENT_CONVERTERS]
if not names:
return
pad = max([len(x) for x in names])
for name in names:
cprint(name.rjust(pad) + ': ', 'White', '')
cprint(str(getattr(build_module, name)))
def ironpython_cprint(message, fg='Gray', end='\n'):
import System
System.Console.ForegroundColor = getattr(System.ConsoleColor, fg)
sys.stdout.write(message)
sys.stdout.write(end)
System.Console.ResetColor()
if __name__ == '__main__':
import os, importlib
build_path = os.path.abspath(sys.argv[1])
build_args = sys.argv[2:]
build_dir = os.path.dirname(build_path)
build_file = os.path.basename(build_path)
build_module_name, build_ext = os.path.splitext(build_file)
sys.path.insert(0, build_dir)
build_module = importlib.import_module(build_module_name)
run(build_module, build_args, ironpython_cprint)
@"%~dp0tools\NuGet.exe" install IronPython.Interpreter -Version 2.7.3 -Source https://nuget.org/api/v2/ -OutputDirectory "%~dp0tools" -NonInteractive -Verbosity quiet -ExcludeVersion
@"%~dp0tools\IronPython.Interpreter\tools\ipy.exe" -tt "%~dp0tools\build.py" %*
# ipy -m unittest discover
import unittest, buildutil
class TestModule:
pass
class TestBuildutil(unittest.TestCase):
def setUp(self):
self.sut = range(10)
self.module = TestModule()
self.cprint_out = []
def fake_cprint(self, message, fg='Gray', end='\n'):
self.cprint_out.append(message + end)
def get_out_lines(self):
out = ''.join(self.cprint_out)
out = out.split('\n')
return [x for x in out if x]
def test_should_parse_args(self):
self.module.int_option = 123
self.module.false_bool_option = False
self.module.true_bool_option = False
tasks = buildutil.parse_args(self.module, [
't1',
'--string_option', 'string_value',
't2',
'--int_option', '456',
't3',
'--false_bool_option', 'true',
't4',
'--true_bool_option', 'false'
])
self.assertEqual(tasks, ['t1', 't2', 't3', 't4'])
self.assertEqual(self.module.string_option, 'string_value')
self.assertEqual(self.module.int_option, 456)
self.assertTrue(self.module.false_bool_option)
self.assertFalse(self.module.true_bool_option)
def test_should_expand_list_of_tasks(self):
self.module.group1 = ['task2', 'task3']
tasks = buildutil.parse_args(self.module, ['task1', 'group1', 'task4'])
self.assertEqual(tasks, ['task1', 'task2', 'task3', 'task4'])
def test_return_default_task_when_no_task_passed(self):
self.module.default = ['task2', 'task3']
tasks = buildutil.parse_args(self.module, [])
self.assertEqual(tasks, ['task2', 'task3'])
def test_should_dump_cfg(self):
self.module.string_option = 'a value'
self.module.int_option = 123
self.module.bool_option = False
self.module._private_option = 'secret'
buildutil.dump_cfg(self.module, self.fake_cprint)
self.assertEqual(self.get_out_lines(), [
' bool_option: False',
' int_option: 123',
'string_option: a value'
])
def test_should_dump_empty_cfg(self):
buildutil.dump_cfg(self.module, self.fake_cprint)
self.assertEqual(self.get_out_lines(), [])
def test_should_execute_normally(self):
executed_tasks = []
self.module.task1 = lambda: executed_tasks.append('task1')
self.module.task2 = lambda: executed_tasks.append('task2')
buildutil.run(self.module, ['task1', 'task2', '--o1', 'v1', '--o2', 'v2'], self.fake_cprint)
self.assertEqual(executed_tasks, ['task1', 'task2'])
self.assertEqual('v1', self.module.o1)
self.assertEqual('v2', self.module.o2)
self.assertEqual(self.get_out_lines(), [
'o1: v1',
'o2: v2',
'Executing task1',
'Executing task2',
'Build Succeeded!',
])
def test_should_fail_execution(self):
def task1():
raise Exception("AHHH!!")
self.module.task1 = task1
with self.assertRaises(Exception) as cm:
buildutil.run(self.module, ['task1'], self.fake_cprint)
self.assertEqual(cm.exception.message, 'AHHH!!')
self.assertEqual(self.get_out_lines(), [
'Executing task1',
'Build Failed!',
])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment