f98557f6179f1b996a2e09bbdd5dda753f639e10
[portage.git] / bin / dohtml.py
1 #!/usr/bin/python
2 # Copyright 1999-2013 Gentoo Foundation
3 # Distributed under the terms of the GNU General Public License v2
4
5 #
6 # Typical usage:
7 # dohtml -r docs/*
8 #  - put all files and directories in docs into /usr/share/doc/${PF}/html
9 # dohtml foo.html
10 #  - put foo.html into /usr/share/doc/${PF}/html
11 #
12 #
13 # Detailed usage:
14 # dohtml <list-of-files>
15 #  - will install the files in the list of files (space-separated list) into
16 #    /usr/share/doc/${PF}/html, provided the file ends in .css, .gif, .htm,
17 #    .html, .jpeg, .jpg, .js or .png.
18 # dohtml -r <list-of-files-and-directories>
19 #  - will do as 'dohtml', but recurse into all directories, as long as the
20 #    directory name is not CVS
21 # dohtml -A jpe,java [-r] <list-of-files[-and-directories]>
22 #  - will do as 'dohtml' but add .jpe,.java (default filter list is
23 #    added to your list)
24 # dohtml -a png,gif,html,htm [-r] <list-of-files[-and-directories]>
25 #  - will do as 'dohtml' but filter on .png,.gif,.html,.htm (default filter
26 #    list is ignored)
27 # dohtml -x CVS,SCCS,RCS -r <list-of-files-and-directories>
28 #  - will do as 'dohtml -r', but ignore directories named CVS, SCCS, RCS
29 #
30
31 from __future__ import print_function
32
33 import os
34 import shutil
35 import sys
36
37 from portage.util import normalize_path
38
39 # Change back to original cwd _after_ all imports (bug #469338).
40 os.chdir(os.environ["__PORTAGE_HELPER_CWD"])
41
42 def dodir(path):
43         try:
44                 os.makedirs(path, 0o755)
45         except OSError:
46                 if not os.path.isdir(path):
47                         raise
48                 os.chmod(path, 0o755)
49
50 def dofile(src,dst):
51         shutil.copy(src, dst)
52         os.chmod(dst, 0o644)
53
54 def eqawarn(lines):
55         cmd = "source '%s/isolated-functions.sh' ; " % \
56                 os.environ["PORTAGE_BIN_PATH"]
57         for line in lines:
58                 cmd += "eqawarn \"%s\" ; " % line
59         os.spawnlp(os.P_WAIT, "bash", "bash", "-c", cmd)
60
61 skipped_directories = []
62 skipped_files = []
63 warn_on_skipped_files = os.environ.get("PORTAGE_DOHTML_WARN_ON_SKIPPED_FILES") is not None
64 unwarned_skipped_extensions = os.environ.get("PORTAGE_DOHTML_UNWARNED_SKIPPED_EXTENSIONS", "").split()
65 unwarned_skipped_files = os.environ.get("PORTAGE_DOHTML_UNWARNED_SKIPPED_FILES", "").split()
66
67 def install(basename, dirname, options, prefix=""):
68         fullpath = basename
69         if prefix:
70                 fullpath = os.path.join(prefix, fullpath)
71         if dirname:
72                 fullpath = os.path.join(dirname, fullpath)
73
74         if options.DOCDESTTREE:
75                 desttree = options.DOCDESTTREE
76         else:
77                 desttree = "html"
78
79         destdir = os.path.join(options.ED, "usr", "share", "doc",
80                 options.PF.lstrip(os.sep), desttree.lstrip(os.sep),
81                 options.doc_prefix.lstrip(os.sep), prefix).rstrip(os.sep)
82
83         if not os.path.exists(fullpath):
84                 sys.stderr.write("!!! dohtml: %s does not exist\n" % fullpath)
85                 return False
86         elif os.path.isfile(fullpath):
87                 ext = os.path.splitext(basename)[1][1:]
88                 if ext in options.allowed_exts or basename in options.allowed_files:
89                         dodir(destdir)
90                         dofile(fullpath, os.path.join(destdir, basename))
91                 elif warn_on_skipped_files and ext not in unwarned_skipped_extensions and basename not in unwarned_skipped_files:
92                         skipped_files.append(fullpath)
93         elif options.recurse and os.path.isdir(fullpath) and \
94              basename not in options.disallowed_dirs:
95                 for i in os.listdir(fullpath):
96                         pfx = basename
97                         if prefix:
98                                 pfx = os.path.join(prefix, pfx)
99                         install(i, dirname, options, pfx)
100         elif not options.recurse and os.path.isdir(fullpath):
101                 global skipped_directories
102                 skipped_directories.append(fullpath)
103                 return False
104         else:
105                 return False
106         return True
107
108
109 class OptionsClass:
110         def __init__(self):
111                 self.PF = ""
112                 self.ED = ""
113                 self.DOCDESTTREE = ""
114
115                 if "PF" in os.environ:
116                         self.PF = os.environ["PF"]
117                         if self.PF:
118                                 self.PF = normalize_path(self.PF)
119                 if "force-prefix" not in os.environ.get("FEATURES", "").split() and \
120                         os.environ.get("EAPI", "0") in ("0", "1", "2"):
121                         self.ED = os.environ.get("D", "")
122                 else:
123                         self.ED = os.environ.get("ED", "")
124                 if self.ED:
125                         self.ED = normalize_path(self.ED)
126                 if "_E_DOCDESTTREE_" in os.environ:
127                         self.DOCDESTTREE = os.environ["_E_DOCDESTTREE_"]
128                         if self.DOCDESTTREE:
129                                 self.DOCDESTTREE = normalize_path(self.DOCDESTTREE)
130
131                 self.allowed_exts = ['css', 'gif', 'htm', 'html', 'jpeg', 'jpg', 'js', 'png']
132                 if os.environ.get("EAPI", "0") in ("4-python", "5-progress"):
133                         self.allowed_exts += ['ico', 'svg', 'xhtml', 'xml']
134                 self.allowed_files = []
135                 self.disallowed_dirs = ['CVS']
136                 self.recurse = False
137                 self.verbose = False
138                 self.doc_prefix = ""
139
140 def print_help():
141         opts = OptionsClass()
142
143         print("dohtml [-a .foo,.bar] [-A .foo,.bar] [-f foo,bar] [-x foo,bar]")
144         print("       [-r] [-V] <file> [file ...]")
145         print()
146         print(" -a   Set the list of allowed to those that are specified.")
147         print("      Default:", ",".join(opts.allowed_exts))
148         print(" -A   Extend the list of allowed file types.")
149         print(" -f   Set list of allowed extensionless file names.")
150         print(" -x   Set directories to be excluded from recursion.")
151         print("      Default:", ",".join(opts.disallowed_dirs))
152         print(" -p   Set a document prefix for installed files (empty by default).")
153         print(" -r   Install files and directories recursively.")
154         print(" -V   Be verbose.")
155         print()
156
157 def parse_args():
158         options = OptionsClass()
159         args = []
160
161         x = 1
162         while x < len(sys.argv):
163                 arg = sys.argv[x]
164                 if arg in ["-h","-r","-V"]:
165                         if arg == "-h":
166                                 print_help()
167                                 sys.exit(0)
168                         elif arg == "-r":
169                                 options.recurse = True
170                         elif arg == "-V":
171                                 options.verbose = True
172                 elif sys.argv[x] in ["-A","-a","-f","-x","-p"]:
173                         x += 1
174                         if x == len(sys.argv):
175                                 print_help()
176                                 sys.exit(0)
177                         elif arg == "-p":
178                                 options.doc_prefix = sys.argv[x]
179                                 if options.doc_prefix:
180                                         options.doc_prefix = normalize_path(options.doc_prefix)
181                         else:
182                                 values = sys.argv[x].split(",")
183                                 if arg == "-A":
184                                         options.allowed_exts.extend(values)
185                                 elif arg == "-a":
186                                         options.allowed_exts = values
187                                 elif arg == "-f":
188                                         options.allowed_files = values
189                                 elif arg == "-x":
190                                         options.disallowed_dirs = values
191                 else:
192                         args.append(sys.argv[x])
193                 x += 1
194
195         return (options, args)
196
197 def main():
198
199         (options, args) = parse_args()
200
201         if options.verbose:
202                 print("Allowed extensions:", options.allowed_exts)
203                 print("Document prefix : '" + options.doc_prefix + "'")
204                 print("Allowed files :", options.allowed_files)
205
206         success = False
207         endswith_slash = (os.sep, os.sep + ".")
208
209         for x in args:
210                 trailing_slash = x.endswith(endswith_slash)
211                 x = normalize_path(x)
212                 if trailing_slash:
213                         # Modify behavior of basename and dirname
214                         # as noted in bug #425214, causing foo/ to
215                         # behave similarly to the way that foo/*
216                         # behaves.
217                         x += os.sep
218                 basename = os.path.basename(x)
219                 dirname  = os.path.dirname(x)
220                 success |= install(basename, dirname, options)
221
222         for x in skipped_directories:
223                 eqawarn(["QA Notice: dohtml on directory '%s' without recursion option" % x])
224         for x in skipped_files:
225                 eqawarn(["dohtml: skipped file '%s'" % x])
226
227         if success:
228                 retcode = 0
229         else:
230                 retcode = 1
231
232         sys.exit(retcode)
233
234 if __name__ == "__main__":
235         main()