Bug 1578501 [wpt PR 18803] - WebKit export of https://bugs.webkit.org/show_bug.cgi...
[gecko.git] / build / moz.configure / checks.configure
blob3fd3e146c50dfd36b895c3743b182e3a0b0784b8
1 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
2 # vim: set filetype=python:
3 # This Source Code Form is subject to the terms of the Mozilla Public
4 # License, v. 2.0. If a copy of the MPL was not distributed with this
5 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 # Templates implementing some generic checks.
8 # ==============================================================
10 # Declare some exceptions. This is cumbersome, but since we shouldn't need a
11 # lot of them, let's stack them all here. When adding a new one, put it in the
12 # _declare_exceptions template, and add it to the return statement. Then
13 # destructure in the assignment below the function declaration.
16 @template
17 @imports(_from='__builtin__', _import='Exception')
18 def _declare_exceptions():
19     class FatalCheckError(Exception):
20         '''An exception to throw from a function decorated with @checking.
21         It will result in calling die() with the given message.
22         Debugging messages emitted from the decorated function will also be
23         printed out.'''
24     return (FatalCheckError,)
27 (FatalCheckError,) = _declare_exceptions()
29 del _declare_exceptions
31 # Helper to display "checking" messages
32 #   @checking('for foo')
33 #   def foo():
34 #       return 'foo'
35 # is equivalent to:
36 #   def foo():
37 #       log.info('checking for foo... ')
38 #       ret = foo
39 #       log.info(ret)
40 #       return ret
41 # This can be combined with e.g. @depends:
42 #   @depends(some_option)
43 #   @checking('for something')
44 #   def check(value):
45 #       ...
46 # An optional callback can be given, that will be used to format the returned
47 # value when displaying it.
50 @template
51 def checking(what, callback=None):
52     def decorator(func):
53         def wrapped(*args, **kwargs):
54             log.info('checking %s... ', what)
55             with log.queue_debug():
56                 error, ret = None, None
57                 try:
58                     ret = func(*args, **kwargs)
59                 except FatalCheckError as e:
60                     error = e.message
61                 display_ret = callback(ret) if callback else ret
62                 if display_ret is True:
63                     log.info('yes')
64                 elif display_ret is False or display_ret is None:
65                     log.info('no')
66                 else:
67                     log.info(display_ret)
68                 if error is not None:
69                     die(error)
70             return ret
71         return wrapped
72     return decorator
75 # Template to check for programs in $PATH.
76 # - `var` is the name of the variable that will be set with `set_config` when
77 #   the program is found.
78 # - `progs` is a list (or tuple) of program names that will be searched for.
79 #   It can also be a reference to a @depends function that returns such a
80 #   list. If the list is empty and there is no input, the check is skipped.
81 # - `what` is a human readable description of what is being looked for. It
82 #   defaults to the lowercase version of `var`.
83 # - `input` is a string reference to an existing option or a reference to a
84 #   @depends function resolving to explicit input for the program check.
85 #   The default is to create an option for the environment variable `var`.
86 #   This argument allows to use a different kind of option (possibly using a
87 #   configure flag), or doing some pre-processing with a @depends function.
88 # - `allow_missing` indicates whether not finding the program is an error.
89 # - `paths` is a list of paths or @depends function returning a list of paths
90 #   that will cause the given path(s) to be searched rather than $PATH. Input
91 #   paths may either be individual paths or delimited by os.pathsep, to allow
92 #   passing $PATH (for example) as an element.
93 # - `paths_have_priority` means that any programs found early in the PATH
94 #   will be prioritized over programs found later in the PATH.  The default is
95 #   False, meaning that any of the programs earlier in the program list will be
96 #   given priority, no matter where in the PATH they are found.
98 # The simplest form is:
99 #   check_prog('PROG', ('a', 'b'))
100 # This will look for 'a' or 'b' in $PATH, and set_config PROG to the one
101 # it can find. If PROG is already set from the environment or command line,
102 # use that value instead.
103 @template
104 @imports(_from='mozbuild.shellutil', _import='quote')
105 def check_prog(var, progs, what=None, input=None, allow_missing=False,
106                paths=None, paths_have_priority=False, when=None):
107     if input is not None:
108         # Wrap input with type checking and normalization.
109         @depends(input, when=when)
110         def input(value):
111             if not value:
112                 return
113             if isinstance(value, str):
114                 return (value,)
115             if isinstance(value, (tuple, list)) and len(value) == 1:
116                 return value
117             configure_error('input must resolve to a tuple or a list with a '
118                             'single element, or a string')
119     else:
120         option(env=var, nargs=1, when=when,
121                help='Path to %s' % (what or 'the %s program' % var.lower()))
122         input = var
123     what = what or var.lower()
125     # Trick to make a @depends function out of an immediate value.
126     progs = dependable(progs)
127     paths = dependable(paths)
129     @depends_if(input, progs, paths, when=when)
130     @checking('for %s' % what, lambda x: quote(x) if x else 'not found')
131     def check(value, progs, paths):
132         if progs is None:
133             progs = ()
135         if not isinstance(progs, (tuple, list)):
136             configure_error('progs must resolve to a list or tuple!')
138         if paths_have_priority:
139             for path in paths:
140                 for prog in value or progs:
141                     log.debug('%s: Trying %s', var.lower(), quote(prog))
142                     result = find_program(prog, [path])
143                     if result:
144                         return result
145         else:
146             for prog in value or progs:
147                 log.debug('%s: Trying %s', var.lower(), quote(prog))
148                 result = find_program(prog, paths)
149                 if result:
150                     return result
152         if not allow_missing or value:
153             raise FatalCheckError('Cannot find %s' % what)
155     @depends_if(check, progs, when=when)
156     def normalized_for_config(value, progs):
157         return ':' if value is None else value
159     set_config(var, normalized_for_config)
161     return check