compress_doc.bbclass 10 KB

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