• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2022 Google LLC
2//
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5
6package exporter
7
8import (
9	"fmt"
10	"os"
11	"os/exec"
12
13	"go.skia.org/infra/go/skerr"
14	"go.skia.org/skia/bazel/exporter/interfaces"
15)
16
17// BazelQueryCommand implements the QueryCommand interface. It will
18// execute the bazel executable to return all rules defined in
19// a protocol buffer.
20type BazelQueryCommand struct {
21	ruleNames []string
22	workspace string
23	queryType string // "query" or "cquery"
24}
25
26// A list of all Skia Bazel build flags which enable the building and/or
27// exposure of all source files.
28var allSkiaFlags = []string{
29	"--ck_enable_canvas_polyfill",
30	"--ck_enable_embedded_font",
31	"--ck_enable_fonts",
32	"--ck_enable_matrix_js",
33	"--ck_enable_runtime_effect",
34	"--ck_enable_skottie",
35	"--ck_enable_skp_serialization",
36	"--enable_effect_serialization",
37	"--enable_gpu_test_utils",
38	"--enable_pdf_backend",
39	// "--enable_skslc", // external dependency on spirv-tools/libspirv.hpp
40	"--enable_svg_canvas",
41	"--enable_tracing",
42	"--enable_vma",
43	"--gpu_backend=gl_backend",
44	// "--include_decoder=*",  // All decoders have external dependencies.
45	// "--include_encoder",    // All encoders have external dependencies.
46	// "--include_fontmgr=custom_embedded_fontmgr", // external dependency on ft2build.h
47}
48
49// NewBazelQueryCommand will create a new BazelQueryCommand instance which will,
50// when Read() is called, invoke the bazel executable to execute a cquery
51// command in the provided workspace for the supplied rules.
52func NewBazelCMakeQueryCommand(ruleNames []string, workspace string) *BazelQueryCommand {
53	return &BazelQueryCommand{ruleNames: ruleNames, workspace: workspace, queryType: "cquery"}
54}
55
56// NewBazelQueryCommand will create a new BazelQueryCommand instance which will,
57// when Read() is called, invoke the bazel executable to execute a query
58// command in the provided workspace for the supplied rules.
59func NewBazelGNIQueryCommand(ruleNames []string, workspace string) *BazelQueryCommand {
60	return &BazelQueryCommand{ruleNames: ruleNames, workspace: workspace, queryType: "query"}
61}
62
63// Stop the Bazel server if running.
64func shutdownBazelServer() error {
65	cmd := exec.Command("bazelisk", "shutdown")
66	_, err := cmd.Output()
67	return err
68}
69
70// Read will execute the Bazel query/cquery command, supplied to NewBazel*QueryCommand(),
71// and return the binary protobuf results.
72func (c *BazelQueryCommand) Read() ([]byte, error) {
73	if len(c.ruleNames) == 0 {
74		return nil, skerr.Fmt("no query rules")
75	}
76
77	pwd, err := os.Getwd()
78	if err != nil {
79		return nil, skerr.Wrapf(err, `can't get working directory`)
80	}
81	err = os.Chdir(c.workspace)
82	if err != nil {
83		return nil, skerr.Wrapf(err, `can't set working directory to %q`, c.workspace)
84	}
85	if c.queryType == "cquery" {
86		// Shutdown the Bazel server to workaround a known issue with cquery:
87		// See "Non-deterministic output" in https://bazel.build/docs/cquery#known-issues
88		err = shutdownBazelServer()
89		if err != nil {
90			return nil, skerr.Wrap(err)
91		}
92	}
93	ruleArg := `kind("rule", `
94	for i, r := range c.ruleNames {
95		if i > 0 {
96			ruleArg = ruleArg + " + "
97		}
98		ruleArg = ruleArg + fmt.Sprintf("deps(%s)", r)
99	}
100	ruleArg = ruleArg + ")"
101	args := []string{c.queryType, "--noimplicit_deps", ruleArg, "--output", "proto"}
102	if c.queryType == "cquery" {
103		args = append(args, allSkiaFlags...)
104	}
105	cmd := exec.Command("bazelisk", args...)
106	_ = os.Chdir(pwd)
107	data, err := cmd.Output()
108	if err != nil {
109		if exiterr, ok := err.(*exec.ExitError); ok {
110			fmt.Printf("Stderr: %s\n", exiterr.Stderr)
111		}
112		return nil, skerr.Wrapf(err, `error running %v`, cmd)
113	}
114	return data, nil
115}
116
117// Make sure BazelQueryCommand fulfills the QueryCommand interface.
118var _ interfaces.QueryCommand = (*BazelQueryCommand)(nil)
119