1#!/usr/bin/python
2#
3# Copyright (c) 2010 - 2013, Intel Corporation. All rights reserved.<BR>
4#
5# This program and the accompanying materials
6# are licensed and made available under the terms and conditions of the BSD License
7# which accompanies this distribution.  The full text of the license may be found at
8# http://opensource.org/licenses/bsd-license.php
9#
10# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12#
13
14import os
15import re
16import StringIO
17import subprocess
18import sys
19import zipfile
20
21is_unix = not sys.platform.startswith('win')
22
23if not is_unix:
24    print "This script currently only supports unix-like systems"
25    sys.exit(-1)
26
27if os.path.exists('OvmfPkgX64.dsc'):
28    os.chdir('..')
29
30if not os.path.exists(os.path.join('OvmfPkg', 'OvmfPkgX64.dsc')):
31    print "OvmfPkg/OvmfPkgX64.dsc doesn't exist"
32    sys.exit(-1)
33
34def run_and_capture_output(args, checkExitCode = True):
35    p = subprocess.Popen(args=args, stdout=subprocess.PIPE)
36    stdout = p.stdout.read()
37    ret_code = p.wait()
38    if checkExitCode:
39        assert ret_code == 0
40    return stdout
41
42gcc_version = run_and_capture_output(args=('gcc', '--version'))
43gcc_re = re.compile(r'\s*\S+\s+\([^\)]+?\)\s+(\d+(?:\.\d+)*)(?:\s+.*)?')
44mo = gcc_re.match(gcc_version)
45if not mo:
46    print "Unable to find GCC version"
47    sys.exit(-1)
48gcc_version = map(lambda n: int(n), mo.group(1).split('.'))
49
50if 'TOOLCHAIN' in os.environ:
51    TOOLCHAIN = os.environ['TOOLCHAIN']
52else:
53    assert(gcc_version[0] == 4)
54    minor = max(4, min(7, gcc_version[1]))
55    TOOLCHAIN = 'GCC4' + str(minor)
56
57def git_based_version():
58    dir = os.getcwd()
59    if not os.path.exists('.git'):
60        os.chdir('OvmfPkg')
61    stdout = run_and_capture_output(args=('git', 'log',
62                                          '-n', '1',
63                                          '--abbrev-commit'))
64    regex = re.compile(r'^\s*git-svn-id:\s+\S+@(\d+)\s+[0-9a-f\-]+$',
65                       re.MULTILINE)
66    mo = regex.search(stdout)
67    if mo:
68        version = 'r' + mo.group(1)
69    else:
70        version = stdout.split(None, 3)[1]
71    os.chdir(dir)
72    return version
73
74def svn_info():
75    dir = os.getcwd()
76    os.chdir('OvmfPkg')
77    stdout = run_and_capture_output(args=('svn', 'info'))
78    os.chdir(dir)
79    return stdout
80
81def svn_based_version():
82        buf = svn_info()
83        revision_re = re.compile('^Revision\:\s*([\da-f]+)$', re.MULTILINE)
84        mo = revision_re.search(buf)
85        assert(mo is not None)
86        return 'r' + mo.group(1)
87
88def get_revision():
89    if os.path.exists(os.path.join('OvmfPkg', '.svn')):
90        return svn_based_version()
91    else:
92        return git_based_version()
93
94revision = get_revision()
95
96newline_re = re.compile(r'(\n|\r\n|\r(?!\n))', re.MULTILINE)
97def to_dos_text(str):
98    return newline_re.sub('\r\n', str)
99
100def gen_build_info():
101    distro = run_and_capture_output(args=('lsb_release', '-sd')).strip()
102
103    machine = run_and_capture_output(args=('uname', '-m')).strip()
104
105    gcc_version_str = '.'.join(map(lambda v: str(v), gcc_version))
106
107    ld_version = run_and_capture_output(args=('ld', '--version'))
108    ld_version = ld_version.split('\n')[0].split()[-1]
109
110    iasl_version = run_and_capture_output(args=('iasl'), checkExitCode=False)
111    iasl_version = filter(lambda s: s.find(' version ') >= 0, iasl_version.split('\n'))[0]
112    iasl_version = iasl_version.split(' version ')[1].strip()
113
114    sb = StringIO.StringIO()
115    print >> sb, 'edk2:    ', revision
116    print >> sb, 'compiler: GCC', gcc_version_str, '(' + TOOLCHAIN + ')'
117    print >> sb, 'binutils:', ld_version
118    print >> sb, 'iasl:    ', iasl_version
119    print >> sb, 'system:  ', distro, machine.replace('_', '-')
120    return to_dos_text(sb.getvalue())
121
122def read_file(filename):
123    f = open(filename)
124    d = f.read()
125    f.close()
126    return d
127
128LICENSE = to_dos_text(
129'''This OVMF binary release is built from source code licensed under
130the BSD open source license.  The BSD license is documented at
131http://opensource.org/licenses/bsd-license.php, and a copy is
132shown below.
133
134One sub-component of the OVMF project is a FAT filesystem driver.  The FAT
135filesystem driver code is also BSD licensed, but the code license contains
136one additional term.  This license can be found at
137https://github.com/tianocore/tianocore.github.io/wiki/Edk2-fat-driver
138and a copy is shown below (following the normal BSD license).
139
140=== BSD license: START ===
141
142''')
143
144LICENSE += read_file(os.path.join('MdePkg', 'License.txt'))
145
146LICENSE += to_dos_text(
147'''
148=== BSD license: END ===
149
150=== FAT filesystem driver license: START ===
151
152''')
153
154LICENSE += read_file(os.path.join('FatBinPkg', 'License.txt'))
155
156LICENSE += to_dos_text(
157'''
158=== FAT filesystem driver license: END ===
159''')
160
161def build(arch):
162    args = (
163        'OvmfPkg/build.sh',
164        '-t', TOOLCHAIN,
165        '-a', arch,
166        '-b', 'RELEASE'
167        )
168    logname = 'build-%s.log' % arch
169    build_log = open(logname, 'w')
170    print 'Building OVMF for', arch, '(%s)' % logname, '...',
171    sys.stdout.flush()
172    p = subprocess.Popen(args=args, stdout=build_log, stderr=build_log)
173    ret_code = p.wait()
174    if ret_code == 0:
175        print '[done]'
176    else:
177        print '[error 0x%x]' % ret_code
178    return ret_code
179
180def create_zip(arch):
181    global build_info
182    filename = 'OVMF-%s-%s.zip' % (arch, revision)
183    print 'Creating', filename, '...',
184    sys.stdout.flush()
185    if os.path.exists(filename):
186        os.remove(filename)
187    zipf = zipfile.ZipFile(filename, 'w', zipfile.ZIP_DEFLATED)
188
189    zipf.writestr('BUILD_INFO', build_info)
190    zipf.writestr('LICENSE', LICENSE)
191    zipf.write(os.path.join('OvmfPkg', 'README'), 'README')
192    FV_DIR = os.path.join(
193        'Build',
194        'Ovmf' + arch.title(),
195        'RELEASE_' + TOOLCHAIN,
196        'FV'
197        )
198    zipf.write(os.path.join(FV_DIR, 'OVMF.fd'), 'OVMF.fd')
199    zipf.close()
200    print '[done]'
201
202build_info = gen_build_info()
203build('IA32')
204build('X64')
205create_zip('IA32')
206create_zip('X64')
207
208
209