blob: 9cbde586d7e4d9813a23f2195a3b14b3c7103105 [file] [log] [blame]
#!/usr/bin/python
#
# Copyright (C) 2015 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Merge packages into the target image."""
from __future__ import print_function
import argparse
import errno
import glob
import os
import shutil
import sys
def makedirs(path):
"""Create all the dirs for |path| ignoring already existing errors."""
try:
os.makedirs(path)
except OSError as e:
if e.errno != errno.EEXIST:
raise
def unlink(path):
"""Delete |path| ignoring missing paths."""
try:
os.unlink(path)
except OSError as e:
if e.errno != errno.ENOENT:
raise
def load_contents(pkg, root, filter=None):
"""Read the CONTENTS file for |pkg| from |root|."""
if not filter:
filter = lambda x: True
ret = []
contents = os.path.join(root, 'var', 'db', 'pkg', pkg + '-*', 'CONTENTS')
files = glob.glob(contents)
if not files:
raise Exception('No packages found matching %s' % pkg)
with open(files[0]) as f:
for line in f.read().splitlines():
line = line.strip()
if not line:
continue
typ, data = line.split(' ', 1)
if typ == 'obj':
path, _hash, _mtime = data.rsplit(' ', 2)
if filter(path):
ret.append(('obj', path))
elif typ == 'sym':
source, target = data.split(' -> ', 1)
target, _mtime = target.rsplit(' ', 1)
if filter(source):
ret.append(('sym', source, target))
elif typ == 'dir':
pass
else:
raise Exception('Unhandled entry: %s' % line)
return ret
def ignore_files(path):
"""Figure out which files we actually care about."""
if path.startswith('/usr/share/doc'):
return False
elif path.startswith('/usr/share/gtk-doc'):
return False
elif path.startswith('/usr/share/info'):
return False
elif path.startswith('/usr/share/man'):
return False
elif path.startswith('/usr/include'):
return False
elif path.startswith('/usr/bin') and path.endswith('-config'):
return False
elif path.startswith('/usr/lib'):
if path.endswith('.a'):
return False
elif path.endswith('.pc'):
return False
return True
def merge(pkg, input_root, output_root, make_root, verbose=0):
"""Merge |pkg| from |input_root| to |output_root|."""
print('Merging %s ' % pkg, end='')
if verbose:
print('from %s to %s' % (input_root, output_root))
# TODO: Grab a lock for |pkg|.
# First get the file listing to merge.
contents = load_contents(pkg, input_root, filter=ignore_files)
# Now actually merge them.
for entry in contents:
if entry[0] == 'obj':
path = entry[1].lstrip('/')
output = os.path.join(output_root, path)
if verbose:
print('>>> %s' % path)
else:
print('.', end='')
makedirs(os.path.dirname(output))
shutil.copy2(os.path.join(input_root, path), output)
elif entry[0] == 'sym':
path = entry[1].lstrip('/')
target = entry[2]
output = os.path.join(output_root, path)
if verbose:
print('>>> %s -> %s' % (path, target))
else:
print('.', end='')
unlink(output)
makedirs(os.path.dirname(output))
os.symlink(target, output)
else:
raise Exception('Unhandled entry: %r' % entry)
make_target = os.path.join(make_root, pkg + '.emerge')
makedirs(os.path.dirname(make_target))
open(make_target, 'w')
if not verbose:
print('')
def get_parser():
"""Return a command line parser."""
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('-p', '--package', action='append', required=True,
dest='packages',
help='Merge these package(s)')
parser.add_argument('--input-root', type=str, required=True,
help='Where to read the packages')
parser.add_argument('--output-root', type=str, required=True,
help='Where to write the packages')
parser.add_argument('--make-root', type=str, required=True,
help='Where make writes state files for rules')
parser.add_argument('-v', '--verbose', action='count',
help='Make output more verbose')
return parser
def main(argv):
parser = get_parser()
opts = parser.parse_args(argv)
for pkg in opts.packages:
merge(pkg, opts.input_root, opts.output_root, opts.make_root,
verbose=opts.verbose)
if __name__ == '__main__':
main(sys.argv[1:])