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