blob: 6951320515e626dd376c2860e0ad615ff5133ddb [file] [log] [blame]
#!/usr/bin/env python3
# Copyright 2020 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Ebuild function generator to migrate src_install into GN.
Default values follow the default values of ebuild (see manpage of ebuild).
https://dev.gentoo.org/~zmedico/portage/doc/man/ebuild.5.html
"""
import os
VALID_INSTALL_TYPES = ('bin', 'ins', 'lib.a', 'lib.so', 'sbin')
class EbuildFunctionError(Exception):
"""The base exception for ebuild_function."""
class InvalidInstallTypeError(EbuildFunctionError):
"""Invalid type exception that is raised when install type is invalid."""
def __init__(self):
message = f'install_type must be {", ".join(VALID_INSTALL_TYPES)}'
super().__init__(message)
def generate(sources, install_path=None, outputs=None, symlinks=None,
recursive=False, options=None, command_type=None):
"""Generates commandlines for installing files using a ebuild function.
Args:
sources: A list of source files to be installed.
install_path: A string of path to install into. When both install_path
and symlinks are specified, it joins a install_path to symlinks.
When command_type is "executable", "shared_library" or
"static_library", install_path must end with "bin", "sbin" or
"lib".
outputs: A list of new file names to be installed as. If not specified,
original file names are used.
symlinks: A list of new symbolic links to be created. If specified,
installation command becomes "dosym" and args except for sources
are ignored.
recursive: A boolean if you install them recursively. This is only
available when command_type and symlinks are not specified.
options: A string to be passed to xxopts. This is only available when
command_type and symlinks are not specified.
command_type: A string of where is the config defined.
"executable", "shared_library", "static_library" and None are only
allowed to be specified.
The generated command depends on command_type.
executable: dobin, dosbin, newbin, newsbin
shared_library: dolib.so, newlib.so
static_library: dolib.a, newlib.a
None: doins, newins, dosym
Returns:
A list of commandlines correspond to given args.
It can generate "doins", "dobin", "dosbin", "dolib.a", "dolib.so" and
"dosym". When "outputs" is specified, it generates new-command of those
except for "dosym".
doins:
[
['insinto', 'path/to/install'],
['insopts', '-m0644'],
['doins', 'sources[0]', 'sources[1]', ...],
]
dobin):
[
['into', 'path/to/install'],
['dobin', 'sources[0]', 'sources[1]', ...],
]
dosym:
[
['dosym', 'sources[0]', 'path/to/symlink[0]'],
['dosym', 'sources[1]', 'path/to/symlink[1]'],
...
]
dolib.a and dolib.so is the same as dobin.
When "outputs" are specified, installation commands change to multiple
commands of "newxxx" like dosym.
"""
if not command_type:
if not symlinks:
install_type = 'ins'
else:
install_type = 'sym'
if install_path:
outputs = [os.path.join(install_path, symlink)
for symlink in symlinks]
else:
outputs = symlinks
elif command_type == 'executable':
install_path, install_type = os.path.split(install_path)
assert install_type in ('bin', 'sbin'), (
'install_path must end in bin or sbin in an executable target')
elif command_type == 'shared_library':
install_path, lib = os.path.split(install_path)
assert lib == 'lib', ('install_path must end in lib in a shared_library'
' target')
install_type = 'lib.so'
elif command_type == 'static_library':
install_path, lib = os.path.split(install_path)
assert lib == 'lib', ('install_path must end in lib in a static_library'
' target')
install_type = 'lib.a'
else:
raise AssertionError('unknown type. type must be executable,'
' shared_library or static_library')
cmd_list = option_cmd(install_type, install_path, options)
cmd_list += install(install_type, sources, outputs, recursive)
return cmd_list
def sym_install(sources, symlinks):
"""Generates "dosym" commandlines.
Args:
sources: A list of source files of symbolic links.
symlinks: A list of symbolic links to be created.
Returns:
A list of commandlines of "dosym".
[
['dosym', 'sources[0]', 'symlinks[0]'],
['dosym', 'sources[1]', 'symlinks[1]'],
...
]
"""
assert len(sources) == len(symlinks), ('the number of symlinks must be the'
' same as sources')
return [['dosym', source, symlink]
for source, symlink in zip(sources, symlinks)]
def option_cmd(install_type, install_path='', options=None):
"""Generates commandlines of options appropriate for the |install_type|.
Args:
install_type: A string of a suffix of an installation command.
install_path: A string of path to be installed into. This is passed to
"xxxinto" commands.
options: A string of options of installation. This is available only
when install_type == "ins". This is passed to "xxxopts".
Returns:
A list of commandlines for specifying options.
doins options (install_type == "ins"):
[
['insinto', 'path/to/install'],
['insopts', '-m0644'],
]
dobin, dosbin, dolib.so, dolib.a options:
[
['into', 'path/to/install']
]
"""
if install_type == 'ins':
return [
['insinto', install_path or '/'],
['insopts', options or '-m0644'],
]
if install_type in VALID_INSTALL_TYPES:
return [['into', install_path or '/usr']]
return []
def install(install_type, sources, outputs=None, recursive=False):
"""Generates commandlines for installation.
When |outputs| is specified, it generates new command.
Args:
install_type: A string of a suffix of an installation command.
sources: A list of source files to be installed.
outputs: A list of new file names to be installed as. If not specified,
original file names are used.
recursive: A boolean if you install them recursively. This is available
only when install_type == "ins" and outputs are not specified.
Returns:
A list of commandlines for installation.
"""
if install_type == 'sym':
return sym_install(sources, outputs)
if not outputs:
return do_command(install_type, sources, recursive)
return new_command(install_type, sources, outputs)
def do_command(install_type, sources, recursive=False):
"""Generates commandlines of do-command.
Args:
install_type: A string of a suffix of an installation command.
"ins", "bin", "sbin", "lib.so" and "lib.a" are allowed.
sources: A list of source files to be installed.
recursive: A boolean if you install them recursively. This is available
only when install_type == "ins".
Returns:
A list of commandlines for installation.
[
['dobin', 'sources[0]', 'sources[1]', ...]
]
Especially, when install_type == "ins" and recursive == true:
[
['doins', '-r', 'sources[0]', 'sources[1]', ...]
]
"""
if install_type not in VALID_INSTALL_TYPES:
raise InvalidInstallTypeError()
recursive_opts = []
if install_type == 'ins' and recursive:
recursive_opts = ['-r']
return [['do%s' % install_type] + recursive_opts + sources]
def new_command(install_type, sources, outputs):
"""Generates commandlines of new-command.
Args:
install_type: A string of a suffix of an installation command.
"ins", "bin", "sbin", "lib.so" and "lib.a" are allowed.
sources: A list of source files to be installed.
outputs: A list of new file names to be installed as.
Returns:
A list of commandlines for installation.
[
['newins', 'sources[0]', 'outputs[0]'],
['newins', 'sources[1]', 'outputs[1]'],
...
]
"""
if install_type not in VALID_INSTALL_TYPES:
raise InvalidInstallTypeError()
assert len(sources) == len(outputs), ('the number of outputs must be the'
' same as sources')
return [['new%s' % install_type, source, output]
for source, output in zip(sources, outputs)]