def main()

in python-dsl/buck_parser/buck.py [0:0]


def main():
    # Our parent expects to read JSON from our stdout, so if anyone
    # uses print, buck will complain with a helpful "but I wanted an
    # array!" message and quit.  Redirect stdout to stderr so that
    # doesn't happen.  Actually dup2 the file handle so that writing
    # to file descriptor 1, os.system, and so on work as expected too.

    # w instead of a mode is used because of https://bugs.python.org/issue27805
    to_parent = os.fdopen(os.dup(sys.stdout.fileno()), "wb")
    os.dup2(sys.stderr.fileno(), sys.stdout.fileno())

    parser = optparse.OptionParser()
    parser.add_option(
        "--project_root", action="store", type="string", dest="project_root"
    )
    parser.add_option(
        "--cell_root",
        action="callback",
        type="string",
        dest="cell_roots",
        metavar="NAME=PATH",
        help="Cell roots that can be referenced by includes.",
        callback=_optparse_store_kv,
        default={},
    )
    parser.add_option("--cell_name", action="store", type="string", dest="cell_name")
    parser.add_option(
        "--build_file_name", action="store", type="string", dest="build_file_name"
    )
    parser.add_option(
        "--allow_empty_globs",
        action="store_true",
        dest="allow_empty_globs",
        help="Tells the parser not to raise an error when glob returns no results.",
    )
    parser.add_option(
        "--use_watchman_glob",
        action="store_true",
        dest="use_watchman_glob",
        help="Invokes `watchman query` to get lists of files instead of globbing in-process.",
    )
    parser.add_option(
        "--watchman_use_glob_generator",
        action="store_true",
        dest="watchman_use_glob_generator",
        help="Uses Watchman glob generator to speed queries",
    )
    parser.add_option(
        "--watchman_glob_stat_results",
        action="store_true",
        dest="watchman_glob_stat_results",
        help="Invokes `stat()` to sanity check result of `watchman query`.",
    )
    parser.add_option(
        "--watchman_socket_path",
        action="store",
        type="string",
        dest="watchman_socket_path",
        help="Path to Unix domain socket/named pipe as returned by `watchman get-sockname`.",
    )
    parser.add_option(
        "--watchman_query_timeout_ms",
        action="store",
        type="int",
        dest="watchman_query_timeout_ms",
        help="Maximum time in milliseconds to wait for watchman query to respond.",
    )
    parser.add_option("--include", action="append", dest="include")
    parser.add_option("--config", help="BuckConfig settings available at parse time.")
    parser.add_option("--ignore_paths", help="Paths that should be ignored.")
    parser.add_option(
        "--quiet",
        action="store_true",
        dest="quiet",
        help="Stifles exception backtraces printed to stderr during parsing.",
    )
    parser.add_option(
        "--profile", action="store_true", help="Profile every buck file execution"
    )
    parser.add_option(
        "--build_file_import_whitelist",
        action="append",
        dest="build_file_import_whitelist",
    )
    parser.add_option(
        "--disable_implicit_native_rules",
        action="store_true",
        help="Do not allow native rules in build files, only included ones",
    )
    parser.add_option(
        "--warn_about_deprecated_syntax",
        action="store_true",
        help="Warn about deprecated syntax usage.",
    )
    parser.add_option(
        "--enable_user_defined_rules",
        action="store_true",
        help="Allow user defined rules' primitives in build files.",
    )
    (options, args) = parser.parse_args()

    # Even though project_root is absolute path, it may not be concise. For
    # example, it might be like "C:\project\.\rule".
    #
    # Under cygwin, the project root will be invoked from buck as C:\path, but
    # the cygwin python uses UNIX-style paths. They can be converted using
    # cygpath, which is necessary because abspath will treat C:\path as a
    # relative path.
    options.project_root = cygwin_adjusted_path(options.project_root)
    project_root = os.path.abspath(options.project_root)
    cell_roots = {
        k: os.path.abspath(cygwin_adjusted_path(v))
        for k, v in iteritems(options.cell_roots)
    }

    watchman_client = None
    if options.use_watchman_glob:
        client_args = {"sendEncoding": "json", "recvEncoding": "json"}
        if options.watchman_query_timeout_ms is not None:
            # pywatchman expects a timeout as a nonnegative floating-point
            # value in seconds.
            client_args["timeout"] = max(
                0.0, options.watchman_query_timeout_ms / 1000.0
            )
        else:
            client_args["timeout"] = DEFAULT_WATCHMAN_QUERY_TIMEOUT
        if options.watchman_socket_path is not None:
            client_args["sockpath"] = options.watchman_socket_path
            client_args["transport"] = "local"
        watchman_client = pywatchman.client(**client_args)

    configs = {}
    if options.config is not None:
        with open(options.config, "r") as f:
            for section, contents in iteritems(json.load(f)):
                for field, value in iteritems(contents):
                    configs[(section, field)] = value

    ignore_paths = []
    if options.ignore_paths is not None:
        with open(options.ignore_paths, "r") as f:
            ignore_paths = [make_glob(i) for i in json.load(f)]

    build_file_processor = BuildFileProcessor(
        project_root,
        cell_roots,
        options.cell_name,
        options.build_file_name,
        options.allow_empty_globs,
        watchman_client,
        options.watchman_glob_stat_results,
        options.watchman_use_glob_generator,
        project_import_whitelist=options.build_file_import_whitelist or [],
        implicit_includes=options.include or [],
        configs=configs,
        ignore_paths=ignore_paths,
        disable_implicit_native_rules=options.disable_implicit_native_rules,
        warn_about_deprecated_syntax=options.warn_about_deprecated_syntax,
        enable_user_defined_rules=options.enable_user_defined_rules,
    )

    # While processing, we'll write exceptions as diagnostic messages
    # to the parent then re-raise them to crash the process. While
    # doing so, we don't want Python's default unhandled exception
    # behavior of writing to stderr.
    orig_excepthook = None
    if options.quiet:
        orig_excepthook = sys.excepthook
        sys.excepthook = silent_excepthook

    # Process the build files with the env var interceptors and builtins
    # installed.
    with build_file_processor.with_env_interceptors():
        with build_file_processor.with_builtins(builtins.__dict__):
            processed_build_file = []

            profiler = None
            if options.profile:
                profiler = Profiler(True)
                profiler.start()
                Tracer.enable()

            for build_file in args:
                query = {
                    "buildFile": build_file,
                    "watchRoot": project_root,
                    "projectPrefix": project_root,
                }
                duration = process_with_diagnostics(
                    query, build_file_processor, to_parent
                )
                processed_build_file.append(
                    {"buildFile": build_file, "duration": duration}
                )

            # From https://docs.python.org/2/using/cmdline.html :
            #
            # Note that there is internal buffering in file.readlines()
            # and File Objects (for line in sys.stdin) which is not
            # influenced by this option. To work around this, you will
            # want to use file.readline() inside a while 1: loop.
            for line in wait_and_read_build_file_query():
                if line == "":
                    break
                build_file_query = json.loads(line)
                if build_file_query.get("command") == "report_profile":
                    report_profile(options, to_parent, processed_build_file, profiler)
                else:
                    duration = process_with_diagnostics(
                        build_file_query, build_file_processor, to_parent
                    )
                    processed_build_file.append(
                        {
                            "buildFile": build_file_query["buildFile"],
                            "duration": duration,
                        }
                    )

    if options.quiet:
        sys.excepthook = orig_excepthook

    # Python tries to flush/close stdout when it quits, and if there's a dead
    # pipe on the other end, it will spit some warnings to stderr. This breaks
    # tests sometimes. Prevent that by explicitly catching the error.
    try:
        to_parent.close()
    except IOError:
        pass