# Compress man pages in ${mandir} and info pages in ${infodir} 
 | 
# 
 | 
# 1. The doc will be compressed to gz format by default. 
 | 
# 
 | 
# 2. It will automatically correct the compressed doc which is not 
 | 
# in ${DOC_COMPRESS} but in ${DOC_COMPRESS_LIST} to the format 
 | 
# of ${DOC_COMPRESS} policy 
 | 
# 
 | 
# 3. It is easy to add a new type compression by editing 
 | 
# local.conf, such as: 
 | 
# DOC_COMPRESS_LIST:append = ' abc' 
 | 
# DOC_COMPRESS = 'abc' 
 | 
# DOC_COMPRESS_CMD[abc] = 'abc compress cmd ***' 
 | 
# DOC_DECOMPRESS_CMD[abc] = 'abc decompress cmd ***' 
 | 
  
 | 
# All supported compression policy 
 | 
DOC_COMPRESS_LIST ?= "gz xz bz2" 
 | 
  
 | 
# Compression policy, must be one of ${DOC_COMPRESS_LIST} 
 | 
DOC_COMPRESS ?= "gz" 
 | 
  
 | 
# Compression shell command 
 | 
DOC_COMPRESS_CMD[gz] ?= 'gzip -v -9 -n' 
 | 
DOC_COMPRESS_CMD[bz2] ?= "bzip2 -v -9" 
 | 
DOC_COMPRESS_CMD[xz] ?= "xz -v" 
 | 
  
 | 
# Decompression shell command 
 | 
DOC_DECOMPRESS_CMD[gz] ?= 'gunzip -v' 
 | 
DOC_DECOMPRESS_CMD[bz2] ?= "bunzip2 -v" 
 | 
DOC_DECOMPRESS_CMD[xz] ?= "unxz -v" 
 | 
  
 | 
PACKAGE_PREPROCESS_FUNCS += "package_do_compress_doc compress_doc_updatealternatives" 
 | 
python package_do_compress_doc() { 
 | 
    compress_mode = d.getVar('DOC_COMPRESS') 
 | 
    compress_list = (d.getVar('DOC_COMPRESS_LIST') or '').split() 
 | 
    if compress_mode not in compress_list: 
 | 
        bb.fatal('Compression policy %s not supported (not listed in %s)\n' % (compress_mode, compress_list)) 
 | 
  
 | 
    dvar = d.getVar('PKGD') 
 | 
    compress_cmds = {} 
 | 
    decompress_cmds = {} 
 | 
    for mode in compress_list: 
 | 
        compress_cmds[mode] = d.getVarFlag('DOC_COMPRESS_CMD', mode) 
 | 
        decompress_cmds[mode] = d.getVarFlag('DOC_DECOMPRESS_CMD', mode) 
 | 
  
 | 
    mandir = os.path.abspath(dvar + os.sep + d.getVar("mandir")) 
 | 
    if os.path.exists(mandir): 
 | 
        # Decompress doc files which format is not compress_mode 
 | 
        decompress_doc(mandir, compress_mode, decompress_cmds) 
 | 
        compress_doc(mandir, compress_mode, compress_cmds) 
 | 
  
 | 
    infodir = os.path.abspath(dvar + os.sep + d.getVar("infodir")) 
 | 
    if os.path.exists(infodir): 
 | 
        # Decompress doc files which format is not compress_mode 
 | 
        decompress_doc(infodir, compress_mode, decompress_cmds) 
 | 
        compress_doc(infodir, compress_mode, compress_cmds) 
 | 
} 
 | 
  
 | 
def _get_compress_format(file, compress_format_list): 
 | 
    for compress_format in compress_format_list: 
 | 
        compress_suffix = '.' + compress_format 
 | 
        if file.endswith(compress_suffix): 
 | 
            return compress_format 
 | 
  
 | 
    return '' 
 | 
  
 | 
# Collect hardlinks to dict, each element in dict lists hardlinks 
 | 
# which points to the same doc file. 
 | 
# {hardlink10: [hardlink11, hardlink12],,,} 
 | 
# The hardlink10, hardlink11 and hardlink12 are the same file. 
 | 
def _collect_hardlink(hardlink_dict, file): 
 | 
    for hardlink in hardlink_dict: 
 | 
        # Add to the existed hardlink 
 | 
        if os.path.samefile(hardlink, file): 
 | 
            hardlink_dict[hardlink].append(file) 
 | 
            return hardlink_dict 
 | 
  
 | 
    hardlink_dict[file] = [] 
 | 
    return hardlink_dict 
 | 
  
 | 
def _process_hardlink(hardlink_dict, compress_mode, shell_cmds, decompress=False): 
 | 
    import subprocess 
 | 
    for target in hardlink_dict: 
 | 
        if decompress: 
 | 
            compress_format = _get_compress_format(target, shell_cmds.keys()) 
 | 
            cmd = "%s -f %s" % (shell_cmds[compress_format], target) 
 | 
            bb.note('decompress hardlink %s' % target) 
 | 
        else: 
 | 
            cmd = "%s -f %s" % (shell_cmds[compress_mode], target) 
 | 
            bb.note('compress hardlink %s' % target) 
 | 
        (retval, output) = subprocess.getstatusoutput(cmd) 
 | 
        if retval: 
 | 
            bb.warn("de/compress file failed %s (cmd was %s)%s" % (retval, cmd, ":\n%s" % output if output else "")) 
 | 
            return 
 | 
  
 | 
        for hardlink_dup in hardlink_dict[target]: 
 | 
            if decompress: 
 | 
                # Remove compress suffix 
 | 
                compress_suffix = '.' + compress_format 
 | 
                new_hardlink = hardlink_dup[:-len(compress_suffix)] 
 | 
                new_target = target[:-len(compress_suffix)] 
 | 
            else: 
 | 
                # Append compress suffix 
 | 
                compress_suffix = '.' + compress_mode 
 | 
                new_hardlink = hardlink_dup + compress_suffix 
 | 
                new_target = target + compress_suffix 
 | 
  
 | 
            bb.note('hardlink %s-->%s' % (new_hardlink, new_target)) 
 | 
            if not os.path.exists(new_hardlink): 
 | 
                os.link(new_target, new_hardlink) 
 | 
            if os.path.exists(hardlink_dup): 
 | 
                os.unlink(hardlink_dup) 
 | 
  
 | 
def _process_symlink(file, compress_format, decompress=False): 
 | 
    compress_suffix = '.' + compress_format 
 | 
    if decompress: 
 | 
        # Remove compress suffix 
 | 
        new_linkname = file[:-len(compress_suffix)] 
 | 
        new_source = os.readlink(file)[:-len(compress_suffix)] 
 | 
    else: 
 | 
        # Append compress suffix 
 | 
        new_linkname = file + compress_suffix 
 | 
        new_source = os.readlink(file) + compress_suffix 
 | 
  
 | 
    bb.note('symlink %s-->%s' % (new_linkname, new_source)) 
 | 
    if not os.path.exists(new_linkname): 
 | 
        os.symlink(new_source, new_linkname) 
 | 
  
 | 
    os.unlink(file) 
 | 
  
 | 
def _is_info(file): 
 | 
    flags = '.info .info-'.split() 
 | 
    for flag in flags: 
 | 
        if flag in os.path.basename(file): 
 | 
            return True 
 | 
  
 | 
    return False 
 | 
  
 | 
def _is_man(file): 
 | 
    import re 
 | 
  
 | 
    # It refers MANSECT-var in man(1.6g)'s man.config 
 | 
    # ".1:.1p:.8:.2:.3:.3p:.4:.5:.6:.7:.9:.0p:.tcl:.n:.l:.p:.o" 
 | 
    # Not start with '.', and contain the above colon-seperate element 
 | 
    p = re.compile(r'[^\.]+\.([1-9lnop]|0p|tcl)') 
 | 
    if p.search(file): 
 | 
        return True 
 | 
  
 | 
    return False 
 | 
  
 | 
def _is_compress_doc(file, compress_format_list): 
 | 
    compress_format = _get_compress_format(file, compress_format_list) 
 | 
    compress_suffix = '.' + compress_format 
 | 
    if file.endswith(compress_suffix): 
 | 
        # Remove the compress suffix 
 | 
        uncompress_file = file[:-len(compress_suffix)] 
 | 
        if _is_info(uncompress_file) or _is_man(uncompress_file): 
 | 
            return True, compress_format 
 | 
  
 | 
    return False, '' 
 | 
  
 | 
def compress_doc(topdir, compress_mode, compress_cmds): 
 | 
    import subprocess 
 | 
    hardlink_dict = {} 
 | 
    for root, dirs, files in os.walk(topdir): 
 | 
        for f in files: 
 | 
            file = os.path.join(root, f) 
 | 
            if os.path.isdir(file): 
 | 
                continue 
 | 
  
 | 
            if _is_info(file) or _is_man(file): 
 | 
                # Symlink 
 | 
                if os.path.islink(file): 
 | 
                    _process_symlink(file, compress_mode) 
 | 
                # Hardlink 
 | 
                elif os.lstat(file).st_nlink > 1: 
 | 
                    _collect_hardlink(hardlink_dict, file) 
 | 
                # Normal file 
 | 
                elif os.path.isfile(file): 
 | 
                    cmd = "%s %s" % (compress_cmds[compress_mode], file) 
 | 
                    (retval, output) = subprocess.getstatusoutput(cmd) 
 | 
                    if retval: 
 | 
                        bb.warn("compress failed %s (cmd was %s)%s" % (retval, cmd, ":\n%s" % output if output else "")) 
 | 
                        continue 
 | 
                    bb.note('compress file %s' % file) 
 | 
  
 | 
    _process_hardlink(hardlink_dict, compress_mode, compress_cmds) 
 | 
  
 | 
# Decompress doc files which format is not compress_mode 
 | 
def decompress_doc(topdir, compress_mode, decompress_cmds): 
 | 
    import subprocess 
 | 
    hardlink_dict = {} 
 | 
    decompress = True 
 | 
    for root, dirs, files in os.walk(topdir): 
 | 
        for f in files: 
 | 
            file = os.path.join(root, f) 
 | 
            if os.path.isdir(file): 
 | 
                continue 
 | 
  
 | 
            res, compress_format = _is_compress_doc(file, decompress_cmds.keys()) 
 | 
            # Decompress files which format is not compress_mode 
 | 
            if res and compress_mode!=compress_format: 
 | 
                # Symlink 
 | 
                if os.path.islink(file): 
 | 
                    _process_symlink(file, compress_format, decompress) 
 | 
                # Hardlink 
 | 
                elif os.lstat(file).st_nlink > 1: 
 | 
                    _collect_hardlink(hardlink_dict, file) 
 | 
                # Normal file 
 | 
                elif os.path.isfile(file): 
 | 
                    cmd = "%s %s" % (decompress_cmds[compress_format], file) 
 | 
                    (retval, output) = subprocess.getstatusoutput(cmd) 
 | 
                    if retval: 
 | 
                        bb.warn("decompress failed %s (cmd was %s)%s" % (retval, cmd, ":\n%s" % output if output else "")) 
 | 
                        continue 
 | 
                    bb.note('decompress file %s' % file) 
 | 
  
 | 
    _process_hardlink(hardlink_dict, compress_mode, decompress_cmds, decompress) 
 | 
  
 | 
python compress_doc_updatealternatives () { 
 | 
    if not bb.data.inherits_class('update-alternatives', d): 
 | 
        return 
 | 
  
 | 
    mandir = d.getVar("mandir") 
 | 
    infodir = d.getVar("infodir") 
 | 
    compress_mode = d.getVar('DOC_COMPRESS') 
 | 
    for pkg in (d.getVar('PACKAGES') or "").split(): 
 | 
        old_names = (d.getVar('ALTERNATIVE:%s' % pkg) or "").split() 
 | 
        new_names = [] 
 | 
        for old_name in old_names: 
 | 
            old_link     = d.getVarFlag('ALTERNATIVE_LINK_NAME', old_name) 
 | 
            old_target   = d.getVarFlag('ALTERNATIVE_TARGET_%s' % pkg, old_name) or \ 
 | 
                d.getVarFlag('ALTERNATIVE_TARGET', old_name) or \ 
 | 
                d.getVar('ALTERNATIVE_TARGET_%s' % pkg) or \ 
 | 
                d.getVar('ALTERNATIVE_TARGET') or \ 
 | 
                old_link 
 | 
            # Sometimes old_target is specified as relative to the link name. 
 | 
            old_target   = os.path.join(os.path.dirname(old_link), old_target) 
 | 
  
 | 
            # The updatealternatives used for compress doc 
 | 
            if mandir in old_target or infodir in old_target: 
 | 
                new_name = old_name + '.' + compress_mode 
 | 
                new_link = old_link + '.' + compress_mode 
 | 
                new_target = old_target + '.' + compress_mode 
 | 
                d.delVarFlag('ALTERNATIVE_LINK_NAME', old_name) 
 | 
                d.setVarFlag('ALTERNATIVE_LINK_NAME', new_name, new_link) 
 | 
                if d.getVarFlag('ALTERNATIVE_TARGET_%s' % pkg, old_name): 
 | 
                    d.delVarFlag('ALTERNATIVE_TARGET_%s' % pkg, old_name) 
 | 
                    d.setVarFlag('ALTERNATIVE_TARGET_%s' % pkg, new_name, new_target) 
 | 
                elif d.getVarFlag('ALTERNATIVE_TARGET', old_name): 
 | 
                    d.delVarFlag('ALTERNATIVE_TARGET', old_name) 
 | 
                    d.setVarFlag('ALTERNATIVE_TARGET', new_name, new_target) 
 | 
                elif d.getVar('ALTERNATIVE_TARGET_%s' % pkg): 
 | 
                    d.setVar('ALTERNATIVE_TARGET_%s' % pkg, new_target) 
 | 
                elif d.getVar('ALTERNATIVE_TARGET'): 
 | 
                    d.setVar('ALTERNATIVE_TARGET', new_target) 
 | 
  
 | 
                new_names.append(new_name) 
 | 
  
 | 
        if new_names: 
 | 
            d.setVar('ALTERNATIVE:%s' % pkg, ' '.join(new_names)) 
 | 
} 
 |