1*4882a593Smuzhiyun# Compress man pages in ${mandir} and info pages in ${infodir} 2*4882a593Smuzhiyun# 3*4882a593Smuzhiyun# 1. The doc will be compressed to gz format by default. 4*4882a593Smuzhiyun# 5*4882a593Smuzhiyun# 2. It will automatically correct the compressed doc which is not 6*4882a593Smuzhiyun# in ${DOC_COMPRESS} but in ${DOC_COMPRESS_LIST} to the format 7*4882a593Smuzhiyun# of ${DOC_COMPRESS} policy 8*4882a593Smuzhiyun# 9*4882a593Smuzhiyun# 3. It is easy to add a new type compression by editing 10*4882a593Smuzhiyun# local.conf, such as: 11*4882a593Smuzhiyun# DOC_COMPRESS_LIST:append = ' abc' 12*4882a593Smuzhiyun# DOC_COMPRESS = 'abc' 13*4882a593Smuzhiyun# DOC_COMPRESS_CMD[abc] = 'abc compress cmd ***' 14*4882a593Smuzhiyun# DOC_DECOMPRESS_CMD[abc] = 'abc decompress cmd ***' 15*4882a593Smuzhiyun 16*4882a593Smuzhiyun# All supported compression policy 17*4882a593SmuzhiyunDOC_COMPRESS_LIST ?= "gz xz bz2" 18*4882a593Smuzhiyun 19*4882a593Smuzhiyun# Compression policy, must be one of ${DOC_COMPRESS_LIST} 20*4882a593SmuzhiyunDOC_COMPRESS ?= "gz" 21*4882a593Smuzhiyun 22*4882a593Smuzhiyun# Compression shell command 23*4882a593SmuzhiyunDOC_COMPRESS_CMD[gz] ?= 'gzip -v -9 -n' 24*4882a593SmuzhiyunDOC_COMPRESS_CMD[bz2] ?= "bzip2 -v -9" 25*4882a593SmuzhiyunDOC_COMPRESS_CMD[xz] ?= "xz -v" 26*4882a593Smuzhiyun 27*4882a593Smuzhiyun# Decompression shell command 28*4882a593SmuzhiyunDOC_DECOMPRESS_CMD[gz] ?= 'gunzip -v' 29*4882a593SmuzhiyunDOC_DECOMPRESS_CMD[bz2] ?= "bunzip2 -v" 30*4882a593SmuzhiyunDOC_DECOMPRESS_CMD[xz] ?= "unxz -v" 31*4882a593Smuzhiyun 32*4882a593SmuzhiyunPACKAGE_PREPROCESS_FUNCS += "package_do_compress_doc compress_doc_updatealternatives" 33*4882a593Smuzhiyunpython package_do_compress_doc() { 34*4882a593Smuzhiyun compress_mode = d.getVar('DOC_COMPRESS') 35*4882a593Smuzhiyun compress_list = (d.getVar('DOC_COMPRESS_LIST') or '').split() 36*4882a593Smuzhiyun if compress_mode not in compress_list: 37*4882a593Smuzhiyun bb.fatal('Compression policy %s not supported (not listed in %s)\n' % (compress_mode, compress_list)) 38*4882a593Smuzhiyun 39*4882a593Smuzhiyun dvar = d.getVar('PKGD') 40*4882a593Smuzhiyun compress_cmds = {} 41*4882a593Smuzhiyun decompress_cmds = {} 42*4882a593Smuzhiyun for mode in compress_list: 43*4882a593Smuzhiyun compress_cmds[mode] = d.getVarFlag('DOC_COMPRESS_CMD', mode) 44*4882a593Smuzhiyun decompress_cmds[mode] = d.getVarFlag('DOC_DECOMPRESS_CMD', mode) 45*4882a593Smuzhiyun 46*4882a593Smuzhiyun mandir = os.path.abspath(dvar + os.sep + d.getVar("mandir")) 47*4882a593Smuzhiyun if os.path.exists(mandir): 48*4882a593Smuzhiyun # Decompress doc files which format is not compress_mode 49*4882a593Smuzhiyun decompress_doc(mandir, compress_mode, decompress_cmds) 50*4882a593Smuzhiyun compress_doc(mandir, compress_mode, compress_cmds) 51*4882a593Smuzhiyun 52*4882a593Smuzhiyun infodir = os.path.abspath(dvar + os.sep + d.getVar("infodir")) 53*4882a593Smuzhiyun if os.path.exists(infodir): 54*4882a593Smuzhiyun # Decompress doc files which format is not compress_mode 55*4882a593Smuzhiyun decompress_doc(infodir, compress_mode, decompress_cmds) 56*4882a593Smuzhiyun compress_doc(infodir, compress_mode, compress_cmds) 57*4882a593Smuzhiyun} 58*4882a593Smuzhiyun 59*4882a593Smuzhiyundef _get_compress_format(file, compress_format_list): 60*4882a593Smuzhiyun for compress_format in compress_format_list: 61*4882a593Smuzhiyun compress_suffix = '.' + compress_format 62*4882a593Smuzhiyun if file.endswith(compress_suffix): 63*4882a593Smuzhiyun return compress_format 64*4882a593Smuzhiyun 65*4882a593Smuzhiyun return '' 66*4882a593Smuzhiyun 67*4882a593Smuzhiyun# Collect hardlinks to dict, each element in dict lists hardlinks 68*4882a593Smuzhiyun# which points to the same doc file. 69*4882a593Smuzhiyun# {hardlink10: [hardlink11, hardlink12],,,} 70*4882a593Smuzhiyun# The hardlink10, hardlink11 and hardlink12 are the same file. 71*4882a593Smuzhiyundef _collect_hardlink(hardlink_dict, file): 72*4882a593Smuzhiyun for hardlink in hardlink_dict: 73*4882a593Smuzhiyun # Add to the existed hardlink 74*4882a593Smuzhiyun if os.path.samefile(hardlink, file): 75*4882a593Smuzhiyun hardlink_dict[hardlink].append(file) 76*4882a593Smuzhiyun return hardlink_dict 77*4882a593Smuzhiyun 78*4882a593Smuzhiyun hardlink_dict[file] = [] 79*4882a593Smuzhiyun return hardlink_dict 80*4882a593Smuzhiyun 81*4882a593Smuzhiyundef _process_hardlink(hardlink_dict, compress_mode, shell_cmds, decompress=False): 82*4882a593Smuzhiyun import subprocess 83*4882a593Smuzhiyun for target in hardlink_dict: 84*4882a593Smuzhiyun if decompress: 85*4882a593Smuzhiyun compress_format = _get_compress_format(target, shell_cmds.keys()) 86*4882a593Smuzhiyun cmd = "%s -f %s" % (shell_cmds[compress_format], target) 87*4882a593Smuzhiyun bb.note('decompress hardlink %s' % target) 88*4882a593Smuzhiyun else: 89*4882a593Smuzhiyun cmd = "%s -f %s" % (shell_cmds[compress_mode], target) 90*4882a593Smuzhiyun bb.note('compress hardlink %s' % target) 91*4882a593Smuzhiyun (retval, output) = subprocess.getstatusoutput(cmd) 92*4882a593Smuzhiyun if retval: 93*4882a593Smuzhiyun bb.warn("de/compress file failed %s (cmd was %s)%s" % (retval, cmd, ":\n%s" % output if output else "")) 94*4882a593Smuzhiyun return 95*4882a593Smuzhiyun 96*4882a593Smuzhiyun for hardlink_dup in hardlink_dict[target]: 97*4882a593Smuzhiyun if decompress: 98*4882a593Smuzhiyun # Remove compress suffix 99*4882a593Smuzhiyun compress_suffix = '.' + compress_format 100*4882a593Smuzhiyun new_hardlink = hardlink_dup[:-len(compress_suffix)] 101*4882a593Smuzhiyun new_target = target[:-len(compress_suffix)] 102*4882a593Smuzhiyun else: 103*4882a593Smuzhiyun # Append compress suffix 104*4882a593Smuzhiyun compress_suffix = '.' + compress_mode 105*4882a593Smuzhiyun new_hardlink = hardlink_dup + compress_suffix 106*4882a593Smuzhiyun new_target = target + compress_suffix 107*4882a593Smuzhiyun 108*4882a593Smuzhiyun bb.note('hardlink %s-->%s' % (new_hardlink, new_target)) 109*4882a593Smuzhiyun if not os.path.exists(new_hardlink): 110*4882a593Smuzhiyun os.link(new_target, new_hardlink) 111*4882a593Smuzhiyun if os.path.exists(hardlink_dup): 112*4882a593Smuzhiyun os.unlink(hardlink_dup) 113*4882a593Smuzhiyun 114*4882a593Smuzhiyundef _process_symlink(file, compress_format, decompress=False): 115*4882a593Smuzhiyun compress_suffix = '.' + compress_format 116*4882a593Smuzhiyun if decompress: 117*4882a593Smuzhiyun # Remove compress suffix 118*4882a593Smuzhiyun new_linkname = file[:-len(compress_suffix)] 119*4882a593Smuzhiyun new_source = os.readlink(file)[:-len(compress_suffix)] 120*4882a593Smuzhiyun else: 121*4882a593Smuzhiyun # Append compress suffix 122*4882a593Smuzhiyun new_linkname = file + compress_suffix 123*4882a593Smuzhiyun new_source = os.readlink(file) + compress_suffix 124*4882a593Smuzhiyun 125*4882a593Smuzhiyun bb.note('symlink %s-->%s' % (new_linkname, new_source)) 126*4882a593Smuzhiyun if not os.path.exists(new_linkname): 127*4882a593Smuzhiyun os.symlink(new_source, new_linkname) 128*4882a593Smuzhiyun 129*4882a593Smuzhiyun os.unlink(file) 130*4882a593Smuzhiyun 131*4882a593Smuzhiyundef _is_info(file): 132*4882a593Smuzhiyun flags = '.info .info-'.split() 133*4882a593Smuzhiyun for flag in flags: 134*4882a593Smuzhiyun if flag in os.path.basename(file): 135*4882a593Smuzhiyun return True 136*4882a593Smuzhiyun 137*4882a593Smuzhiyun return False 138*4882a593Smuzhiyun 139*4882a593Smuzhiyundef _is_man(file): 140*4882a593Smuzhiyun import re 141*4882a593Smuzhiyun 142*4882a593Smuzhiyun # It refers MANSECT-var in man(1.6g)'s man.config 143*4882a593Smuzhiyun # ".1:.1p:.8:.2:.3:.3p:.4:.5:.6:.7:.9:.0p:.tcl:.n:.l:.p:.o" 144*4882a593Smuzhiyun # Not start with '.', and contain the above colon-seperate element 145*4882a593Smuzhiyun p = re.compile(r'[^\.]+\.([1-9lnop]|0p|tcl)') 146*4882a593Smuzhiyun if p.search(file): 147*4882a593Smuzhiyun return True 148*4882a593Smuzhiyun 149*4882a593Smuzhiyun return False 150*4882a593Smuzhiyun 151*4882a593Smuzhiyundef _is_compress_doc(file, compress_format_list): 152*4882a593Smuzhiyun compress_format = _get_compress_format(file, compress_format_list) 153*4882a593Smuzhiyun compress_suffix = '.' + compress_format 154*4882a593Smuzhiyun if file.endswith(compress_suffix): 155*4882a593Smuzhiyun # Remove the compress suffix 156*4882a593Smuzhiyun uncompress_file = file[:-len(compress_suffix)] 157*4882a593Smuzhiyun if _is_info(uncompress_file) or _is_man(uncompress_file): 158*4882a593Smuzhiyun return True, compress_format 159*4882a593Smuzhiyun 160*4882a593Smuzhiyun return False, '' 161*4882a593Smuzhiyun 162*4882a593Smuzhiyundef compress_doc(topdir, compress_mode, compress_cmds): 163*4882a593Smuzhiyun import subprocess 164*4882a593Smuzhiyun hardlink_dict = {} 165*4882a593Smuzhiyun for root, dirs, files in os.walk(topdir): 166*4882a593Smuzhiyun for f in files: 167*4882a593Smuzhiyun file = os.path.join(root, f) 168*4882a593Smuzhiyun if os.path.isdir(file): 169*4882a593Smuzhiyun continue 170*4882a593Smuzhiyun 171*4882a593Smuzhiyun if _is_info(file) or _is_man(file): 172*4882a593Smuzhiyun # Symlink 173*4882a593Smuzhiyun if os.path.islink(file): 174*4882a593Smuzhiyun _process_symlink(file, compress_mode) 175*4882a593Smuzhiyun # Hardlink 176*4882a593Smuzhiyun elif os.lstat(file).st_nlink > 1: 177*4882a593Smuzhiyun _collect_hardlink(hardlink_dict, file) 178*4882a593Smuzhiyun # Normal file 179*4882a593Smuzhiyun elif os.path.isfile(file): 180*4882a593Smuzhiyun cmd = "%s %s" % (compress_cmds[compress_mode], file) 181*4882a593Smuzhiyun (retval, output) = subprocess.getstatusoutput(cmd) 182*4882a593Smuzhiyun if retval: 183*4882a593Smuzhiyun bb.warn("compress failed %s (cmd was %s)%s" % (retval, cmd, ":\n%s" % output if output else "")) 184*4882a593Smuzhiyun continue 185*4882a593Smuzhiyun bb.note('compress file %s' % file) 186*4882a593Smuzhiyun 187*4882a593Smuzhiyun _process_hardlink(hardlink_dict, compress_mode, compress_cmds) 188*4882a593Smuzhiyun 189*4882a593Smuzhiyun# Decompress doc files which format is not compress_mode 190*4882a593Smuzhiyundef decompress_doc(topdir, compress_mode, decompress_cmds): 191*4882a593Smuzhiyun import subprocess 192*4882a593Smuzhiyun hardlink_dict = {} 193*4882a593Smuzhiyun decompress = True 194*4882a593Smuzhiyun for root, dirs, files in os.walk(topdir): 195*4882a593Smuzhiyun for f in files: 196*4882a593Smuzhiyun file = os.path.join(root, f) 197*4882a593Smuzhiyun if os.path.isdir(file): 198*4882a593Smuzhiyun continue 199*4882a593Smuzhiyun 200*4882a593Smuzhiyun res, compress_format = _is_compress_doc(file, decompress_cmds.keys()) 201*4882a593Smuzhiyun # Decompress files which format is not compress_mode 202*4882a593Smuzhiyun if res and compress_mode!=compress_format: 203*4882a593Smuzhiyun # Symlink 204*4882a593Smuzhiyun if os.path.islink(file): 205*4882a593Smuzhiyun _process_symlink(file, compress_format, decompress) 206*4882a593Smuzhiyun # Hardlink 207*4882a593Smuzhiyun elif os.lstat(file).st_nlink > 1: 208*4882a593Smuzhiyun _collect_hardlink(hardlink_dict, file) 209*4882a593Smuzhiyun # Normal file 210*4882a593Smuzhiyun elif os.path.isfile(file): 211*4882a593Smuzhiyun cmd = "%s %s" % (decompress_cmds[compress_format], file) 212*4882a593Smuzhiyun (retval, output) = subprocess.getstatusoutput(cmd) 213*4882a593Smuzhiyun if retval: 214*4882a593Smuzhiyun bb.warn("decompress failed %s (cmd was %s)%s" % (retval, cmd, ":\n%s" % output if output else "")) 215*4882a593Smuzhiyun continue 216*4882a593Smuzhiyun bb.note('decompress file %s' % file) 217*4882a593Smuzhiyun 218*4882a593Smuzhiyun _process_hardlink(hardlink_dict, compress_mode, decompress_cmds, decompress) 219*4882a593Smuzhiyun 220*4882a593Smuzhiyunpython compress_doc_updatealternatives () { 221*4882a593Smuzhiyun if not bb.data.inherits_class('update-alternatives', d): 222*4882a593Smuzhiyun return 223*4882a593Smuzhiyun 224*4882a593Smuzhiyun mandir = d.getVar("mandir") 225*4882a593Smuzhiyun infodir = d.getVar("infodir") 226*4882a593Smuzhiyun compress_mode = d.getVar('DOC_COMPRESS') 227*4882a593Smuzhiyun for pkg in (d.getVar('PACKAGES') or "").split(): 228*4882a593Smuzhiyun old_names = (d.getVar('ALTERNATIVE:%s' % pkg) or "").split() 229*4882a593Smuzhiyun new_names = [] 230*4882a593Smuzhiyun for old_name in old_names: 231*4882a593Smuzhiyun old_link = d.getVarFlag('ALTERNATIVE_LINK_NAME', old_name) 232*4882a593Smuzhiyun old_target = d.getVarFlag('ALTERNATIVE_TARGET_%s' % pkg, old_name) or \ 233*4882a593Smuzhiyun d.getVarFlag('ALTERNATIVE_TARGET', old_name) or \ 234*4882a593Smuzhiyun d.getVar('ALTERNATIVE_TARGET_%s' % pkg) or \ 235*4882a593Smuzhiyun d.getVar('ALTERNATIVE_TARGET') or \ 236*4882a593Smuzhiyun old_link 237*4882a593Smuzhiyun # Sometimes old_target is specified as relative to the link name. 238*4882a593Smuzhiyun old_target = os.path.join(os.path.dirname(old_link), old_target) 239*4882a593Smuzhiyun 240*4882a593Smuzhiyun # The updatealternatives used for compress doc 241*4882a593Smuzhiyun if mandir in old_target or infodir in old_target: 242*4882a593Smuzhiyun new_name = old_name + '.' + compress_mode 243*4882a593Smuzhiyun new_link = old_link + '.' + compress_mode 244*4882a593Smuzhiyun new_target = old_target + '.' + compress_mode 245*4882a593Smuzhiyun d.delVarFlag('ALTERNATIVE_LINK_NAME', old_name) 246*4882a593Smuzhiyun d.setVarFlag('ALTERNATIVE_LINK_NAME', new_name, new_link) 247*4882a593Smuzhiyun if d.getVarFlag('ALTERNATIVE_TARGET_%s' % pkg, old_name): 248*4882a593Smuzhiyun d.delVarFlag('ALTERNATIVE_TARGET_%s' % pkg, old_name) 249*4882a593Smuzhiyun d.setVarFlag('ALTERNATIVE_TARGET_%s' % pkg, new_name, new_target) 250*4882a593Smuzhiyun elif d.getVarFlag('ALTERNATIVE_TARGET', old_name): 251*4882a593Smuzhiyun d.delVarFlag('ALTERNATIVE_TARGET', old_name) 252*4882a593Smuzhiyun d.setVarFlag('ALTERNATIVE_TARGET', new_name, new_target) 253*4882a593Smuzhiyun elif d.getVar('ALTERNATIVE_TARGET_%s' % pkg): 254*4882a593Smuzhiyun d.setVar('ALTERNATIVE_TARGET_%s' % pkg, new_target) 255*4882a593Smuzhiyun elif d.getVar('ALTERNATIVE_TARGET'): 256*4882a593Smuzhiyun d.setVar('ALTERNATIVE_TARGET', new_target) 257*4882a593Smuzhiyun 258*4882a593Smuzhiyun new_names.append(new_name) 259*4882a593Smuzhiyun 260*4882a593Smuzhiyun if new_names: 261*4882a593Smuzhiyun d.setVar('ALTERNATIVE:%s' % pkg, ' '.join(new_names)) 262*4882a593Smuzhiyun} 263*4882a593Smuzhiyun 264