xref: /OK3568_Linux_fs/yocto/poky/meta/classes/compress_doc.bbclass (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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