2017-02-20 09:35:34 +00:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
|
|
# This program is free software; you can redistribute it and/or modify
|
|
|
|
# it under the terms of the GNU General Public License as published by
|
|
|
|
# the Free Software Foundation; version 2 of the License.
|
|
|
|
#
|
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
# GNU Library General Public License for more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU General Public License
|
|
|
|
# along with this program; if not, see <https://gnu.org/licenses/>.
|
|
|
|
|
|
|
|
from kobo import shortcuts
|
|
|
|
import os
|
|
|
|
import productmd
|
|
|
|
import tempfile
|
2017-09-21 07:29:53 +00:00
|
|
|
from six.moves import shlex_quote
|
2017-02-20 09:35:34 +00:00
|
|
|
|
|
|
|
from pungi import util
|
|
|
|
from pungi.phases.buildinstall import tweak_configs
|
|
|
|
from pungi.wrappers import iso
|
|
|
|
|
|
|
|
|
|
|
|
def sh(log, cmd, *args, **kwargs):
|
2017-09-21 07:29:53 +00:00
|
|
|
log.info('Running: %s', ' '.join(shlex_quote(x) for x in cmd))
|
2017-09-15 07:42:33 +00:00
|
|
|
ret, out = shortcuts.run(cmd, *args, universal_newlines=True, **kwargs)
|
2017-02-20 09:35:34 +00:00
|
|
|
if out:
|
|
|
|
log.debug('%s', out)
|
|
|
|
return ret, out
|
|
|
|
|
|
|
|
|
|
|
|
def get_lorax_dir(default='/usr/share/lorax'):
|
|
|
|
try:
|
2017-09-15 07:42:33 +00:00
|
|
|
_, out = shortcuts.run(['python3', '-c' 'import pylorax; print(pylorax.find_templates())'],
|
|
|
|
universal_newlines=True)
|
2017-02-20 09:35:34 +00:00
|
|
|
return out.strip()
|
|
|
|
except Exception:
|
|
|
|
return default
|
|
|
|
|
|
|
|
|
|
|
|
def as_bool(arg):
|
|
|
|
if arg == 'true':
|
|
|
|
return True
|
|
|
|
elif arg == 'false':
|
|
|
|
return False
|
|
|
|
else:
|
|
|
|
return arg
|
|
|
|
|
|
|
|
|
|
|
|
def get_arch(log, iso_dir):
|
|
|
|
di_path = os.path.join(iso_dir, '.discinfo')
|
|
|
|
if os.path.exists(di_path):
|
|
|
|
di = productmd.discinfo.DiscInfo()
|
|
|
|
di.load(di_path)
|
|
|
|
log.info('Detected bootable ISO for %s (based on .discinfo)', di.arch)
|
|
|
|
return di.arch
|
|
|
|
|
|
|
|
ti_path = os.path.join(iso_dir, '.treeinfo')
|
|
|
|
if os.path.exists(ti_path):
|
|
|
|
ti = productmd.treeinfo.TreeInfo()
|
|
|
|
ti.load(ti_path)
|
|
|
|
log.info('Detected bootable ISO for %s (based on .treeinfo)', ti.tree.arch)
|
|
|
|
return ti.tree.arch
|
|
|
|
|
|
|
|
# There is no way to tell the architecture of an ISO file without guessing.
|
|
|
|
# Let's print a warning and continue with assuming unbootable ISO.
|
|
|
|
|
|
|
|
log.warning('Failed to detect arch for ISO, assuming unbootable one.')
|
|
|
|
log.warning('If this is incorrect, use the --force-arch option.')
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|
def run(log, opts):
|
|
|
|
# mount source iso
|
|
|
|
log.info('Mounting %s', opts.source)
|
|
|
|
target = os.path.abspath(opts.target)
|
|
|
|
|
|
|
|
with util.temp_dir(prefix='patch-iso-') as work_dir:
|
|
|
|
with iso.mount(opts.source) as source_iso_dir:
|
|
|
|
util.copy_all(source_iso_dir, work_dir)
|
|
|
|
|
|
|
|
# Make everything writable
|
|
|
|
for root, dirs, files in os.walk(work_dir):
|
|
|
|
for name in files:
|
|
|
|
os.chmod(os.path.join(root, name), 0o640)
|
|
|
|
for name in dirs:
|
|
|
|
os.chmod(os.path.join(root, name), 0o755)
|
|
|
|
|
|
|
|
# volume id is copied from source iso unless --label is specified
|
|
|
|
volume_id = opts.volume_id or iso.get_volume_id(opts.source)
|
|
|
|
|
|
|
|
# create graft points from mounted source iso + overlay dir
|
|
|
|
graft_points = iso.get_graft_points([work_dir, opts.dir])
|
|
|
|
# if ks.cfg is detected, patch syslinux + grub to use it
|
|
|
|
if 'ks.cfg' in graft_points:
|
|
|
|
log.info('Adding ks.cfg to boot configs')
|
|
|
|
tweak_configs(work_dir, volume_id, graft_points['ks.cfg'])
|
|
|
|
|
|
|
|
arch = opts.force_arch or get_arch(log, work_dir)
|
|
|
|
|
|
|
|
with tempfile.NamedTemporaryFile(prefix='graft-points-') as graft_file:
|
|
|
|
iso.write_graft_points(graft_file.name, graft_points,
|
|
|
|
exclude=["*/TRANS.TBL", "*/boot.cat"])
|
|
|
|
|
|
|
|
# make the target iso bootable if source iso is bootable
|
|
|
|
boot_args = input_charset = None
|
|
|
|
if arch:
|
|
|
|
boot_args = iso.get_boot_options(
|
|
|
|
arch, os.path.join(get_lorax_dir(), 'config_files/ppc'))
|
|
|
|
input_charset = 'utf-8' if 'ppc' not in arch else None
|
|
|
|
# Create the target ISO
|
|
|
|
mkisofs_cmd = iso.get_mkisofs_cmd(target, None,
|
|
|
|
volid=volume_id,
|
|
|
|
exclude=["./lost+found"],
|
|
|
|
graft_points=graft_file.name,
|
|
|
|
input_charset=input_charset,
|
|
|
|
boot_args=boot_args)
|
|
|
|
sh(log, mkisofs_cmd, workdir=work_dir)
|
|
|
|
|
|
|
|
# isohybrid support
|
|
|
|
if arch in ["x86_64", "i386"]:
|
|
|
|
isohybrid_cmd = iso.get_isohybrid_cmd(target, arch)
|
|
|
|
sh(log, isohybrid_cmd)
|
|
|
|
|
|
|
|
supported = as_bool(opts.supported or iso.get_checkisomd5_data(opts.source)['Supported ISO'])
|
|
|
|
# implantmd5 + supported bit (use the same as on source iso, unless
|
|
|
|
# overriden by --supported option)
|
|
|
|
isomd5sum_cmd = iso.get_implantisomd5_cmd(target, supported)
|
|
|
|
sh(log, isomd5sum_cmd)
|