1# Copyright (C) 2010 Google Inc. All rights reserved.
2#
3# Redistribution and use in source and binary forms, with or without
4# modification, are permitted provided that the following conditions
5# are met:
6# 1. Redistributions of source code must retain the above copyright
7#    notice, this list of conditions and the following disclaimer.
8# 2. Redistributions in binary form must reproduce the above copyright
9#    notice, this list of conditions and the following disclaimer in the
10#    documentation and/or other materials provided with the distribution.
11#
12# THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
13# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
15# PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
16# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
17# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
18# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
19# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
20# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
22# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23
24import glob
25import logging
26import optparse
27import os
28import re
29import sys
30from webkitpy.common.checkout import scm
31from webkitpy.common.system.filesystem import FileSystem
32from webkitpy.common.system.executive import Executive
33
34
35_log = logging.getLogger(__name__)
36
37
38def remove_first_line_comment(text):
39    return re.compile(r'^<!--.*?-->\s*', re.DOTALL).sub('', text)
40
41
42def translate_includes(text):
43    # Mapping of single filename to relative path under WebKit root.
44    # Assumption: these filenames are globally unique.
45    include_mapping = {
46        "js-test-style.css": "../../js/resources",
47        "js-test-pre.js": "../../js/resources",
48        "js-test-post.js": "../../js/resources",
49        "desktop-gl-constants.js": "resources",
50    }
51
52    for filename, path in include_mapping.items():
53        search = r'(?:[^"\'= ]*/)?' + re.escape(filename)
54        # We use '/' instead of os.path.join in order to produce consistent
55        # output cross-platform.
56        replace = path + '/' + filename
57        text = re.sub(search, replace, text)
58
59    return text
60
61
62def translate_khronos_test(text):
63    """
64    This method translates the contents of a Khronos test to a WebKit test.
65    """
66
67    translateFuncs = [
68        remove_first_line_comment,
69        translate_includes,
70    ]
71
72    for f in translateFuncs:
73        text = f(text)
74
75    return text
76
77
78def update_file(in_filename, out_dir):
79    # check in_filename exists
80    # check out_dir exists
81    out_filename = os.path.join(out_dir, os.path.basename(in_filename))
82
83    _log.debug("Processing " + in_filename)
84    with open(in_filename, 'r') as in_file:
85        with open(out_filename, 'w') as out_file:
86            out_file.write(translate_khronos_test(in_file.read()))
87
88
89def update_directory(in_dir, out_dir):
90    for filename in glob.glob(os.path.join(in_dir, '*.html')):
91        update_file(os.path.join(in_dir, filename), out_dir)
92
93
94def default_out_dir():
95    detector = scm.SCMDetector(FileSystem(), Executive())
96    current_scm = detector.detect_scm_system(os.path.dirname(sys.argv[0]))
97    if not current_scm:
98        return os.getcwd()
99    root_dir = current_scm.checkout_root
100    if not root_dir:
101        return os.getcwd()
102    out_dir = os.path.join(root_dir, "LayoutTests/fast/canvas/webgl")
103    if os.path.isdir(out_dir):
104        return out_dir
105    return os.getcwd()
106
107
108def configure_logging(options):
109    """Configures the logging system."""
110    log_fmt = '%(levelname)s: %(message)s'
111    log_datefmt = '%y%m%d %H:%M:%S'
112    log_level = logging.INFO
113    if options.verbose:
114        log_fmt = ('%(asctime)s %(filename)s:%(lineno)-4d %(levelname)s '
115                   '%(message)s')
116        log_level = logging.DEBUG
117    logging.basicConfig(level=log_level, format=log_fmt,
118                        datefmt=log_datefmt)
119
120
121def option_parser():
122    usage = "usage: %prog [options] (input file or directory)"
123    parser = optparse.OptionParser(usage=usage)
124    parser.add_option('-v', '--verbose',
125                             action='store_true',
126                             default=False,
127                             help='include debug-level logging')
128    parser.add_option('-o', '--output',
129                             action='store',
130                             type='string',
131                             default=default_out_dir(),
132                             metavar='DIR',
133                             help='specify an output directory to place files '
134                                  'in [default: %default]')
135    return parser
136
137
138def main():
139    parser = option_parser()
140    (options, args) = parser.parse_args()
141    configure_logging(options)
142
143    if len(args) == 0:
144        _log.error("Must specify an input directory or filename.")
145        parser.print_help()
146        return 1
147
148    in_name = args[0]
149    if os.path.isfile(in_name):
150        update_file(in_name, options.output)
151    elif os.path.isdir(in_name):
152        update_directory(in_name, options.output)
153    else:
154        _log.error("'%s' is not a directory or a file.", in_name)
155        return 2
156
157    return 0
158