Last active
December 19, 2015 10:59
-
-
Save gimmi/5944681 to your computer and use it in GitHub Desktop.
Python build script
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
*.pyc |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@"%~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" %* |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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