blob: 2831d8b9b54e736ed6fd93263273a6885a49077b [file] [log] [blame]
#!/usr/bin/python
"""Build App Engine source package.
"""
import json
import optparse
import os
import shutil
import subprocess
import sys
import requests
import test_file_herder
USAGE = """%prog src_path dest_path
Build the GAE source code package.
src_path Path to the source code root directory.
dest_path Path to the root directory to push/deploy GAE from."""
def call_cmd_and_return_output_lines(cmd):
try:
process = subprocess.Popen(cmd, stdout=subprocess.PIPE)
output = process.communicate()[0]
return output.split('\n')
except OSError as e:
print str(e)
return []
def build_version_info_file(dest_path):
"""Build the version info JSON file."""
version_info = {
'gitHash': None,
'time': None,
'branch': None
}
lines = call_cmd_and_return_output_lines(['git', 'log', '-1'])
for line in lines:
if line.startswith('commit'):
version_info['gitHash'] = line.partition(' ')[2].strip()
elif line.startswith('Date'):
version_info['time'] = line.partition(':')[2].strip()
if version_info['gitHash'] is not None and version_info['time'] is not None:
break
lines = call_cmd_and_return_output_lines(['git', 'branch'])
for line in lines:
if line.startswith('*'):
version_info['branch'] = line.partition(' ')[2].strip()
break
try:
with open(dest_path, 'w') as f:
f.write(json.dumps(version_info))
except IOError as e:
print str(e)
# Copy pako zlib from node_modules to third_party/pako
def copyPako(dest_path):
dest_js_path = os.path.join(dest_path, 'third_party', 'pako')
os.makedirs(dest_js_path)
shutil.copy('node_modules/pako/dist/pako.min.js', dest_js_path)
# Download callstats, copy dependencies from node_modules for serving as
# static content on GAE.
def downloadCallstats():
print 'Downloading and copying callstats dependencies...'
path = 'out/app_engine/third_party/callstats/'
if os.path.exists(path):
shutil.rmtree(path)
os.makedirs(path)
urls = {
'callstats.min.js': 'https://api.callstats.io/static/callstats.min.js',
'sha.js': 'https://cdnjs.cloudflare.com/ajax/libs/jsSHA/1.5.0/sha.js'
}
for fileName in urls:
response = requests.get(urls[fileName])
if response.status_code == 200:
print 'Downloading %s to %s...' % (urls[fileName], path)
with open(path + fileName, 'w') as to_file:
to_file.write(response.text)
else:
raise NameError('Could not download: ' + filename + ' Error:' + \
str(response.status_code))
# Need to copy this from node_modules due to https://cdn.socket.io/ requires
# SNI extensions which is not supported in python 2.7.9 and we use 2.7.6.
deps = {'socket.io-client': 'socket.io.js'}
for dirpath, unused_dirnames, files in os.walk('node_modules'):
for subdir in deps:
for name in files:
if name.endswith(deps[subdir]):
print 'Copying %s' % deps[subdir]
shutil.copy(os.path.join(dirpath, name), path)
# Verify that files in |deps| has been copied else fail build.
for dirpath, unused_dirnames, files in os.walk(path):
for file_name in deps.values():
file_path = os.path.join(path, file_name)
if os.path.isfile(file_path):
print 'File found %s' % file_name
else:
raise NameError("Could not find: %s please try npm update/install."
% file_path)
def CopyApprtcSource(src_path, dest_path):
if os.path.exists(dest_path):
shutil.rmtree(dest_path)
os.makedirs(dest_path)
simply_copy_subdirs = ['bigquery', 'css', 'images', 'third_party']
for dirpath, unused_dirnames, files in os.walk(src_path):
for subdir in simply_copy_subdirs:
if dirpath.endswith(subdir):
shutil.copytree(dirpath, os.path.join(dest_path, subdir))
if dirpath.endswith('html'):
dest_html_path = os.path.join(dest_path, 'html')
os.makedirs(dest_html_path)
for name in files:
# Template files must be in the root directory.
if name.endswith('_template.html'):
shutil.copy(os.path.join(dirpath, name), dest_path)
else:
shutil.copy(os.path.join(dirpath, name), dest_html_path)
elif dirpath.endswith('app_engine'):
for name in files:
if (name.endswith('.py') and 'test' not in name
or name.endswith('.yaml')):
shutil.copy(os.path.join(dirpath, name), dest_path)
elif dirpath.endswith('js'):
for name in files:
# loopback.js and rtstats.js are not compiled by Closure
# and need to be copied separately.
if name in ['loopback.js', 'rtstats.js']:
dest_js_path = os.path.join(dest_path, 'js')
if not os.path.exists(dest_js_path):
os.makedirs(dest_js_path)
shutil.copy(os.path.join(dirpath, name), dest_js_path)
build_version_info_file(os.path.join(dest_path, 'version_info.json'))
def main():
parser = optparse.OptionParser(USAGE)
parser.add_option("-t", "--include-tests", action="store_true",
help='Also copy python tests to the out dir.')
options, args = parser.parse_args()
if len(args) != 2:
parser.error('Error: Exactly 2 arguments required.')
src_path, dest_path = args[0:2]
CopyApprtcSource(src_path, dest_path)
copyPako(dest_path)
downloadCallstats()
if options.include_tests:
app_engine_code = os.path.join(src_path, 'app_engine')
test_file_herder.CopyTests(os.path.join(src_path, 'app_engine'), dest_path)
if __name__ == '__main__':
sys.exit(main())