1package cquery
2
3import (
4	"fmt"
5	"strings"
6)
7
8var (
9	GetOutputFiles = &getOutputFilesRequestType{}
10	GetCcInfo      = &getCcInfoType{}
11)
12
13type CcInfo struct {
14	OutputFiles          []string
15	CcObjectFiles        []string
16	CcStaticLibraryFiles []string
17	Includes             []string
18	SystemIncludes       []string
19}
20
21type getOutputFilesRequestType struct{}
22
23// Name returns a string name for this request type. Such request type names must be unique,
24// and must only consist of alphanumeric characters.
25func (g getOutputFilesRequestType) Name() string {
26	return "getOutputFiles"
27}
28
29// StarlarkFunctionBody returns a starlark function body to process this request type.
30// The returned string is the body of a Starlark function which obtains
31// all request-relevant information about a target and returns a string containing
32// this information.
33// The function should have the following properties:
34//   - `target` is the only parameter to this function (a configured target).
35//   - The return value must be a string.
36//   - The function body should not be indented outside of its own scope.
37func (g getOutputFilesRequestType) StarlarkFunctionBody() string {
38	return "return ', '.join([f.path for f in target.files.to_list()])"
39}
40
41// ParseResult returns a value obtained by parsing the result of the request's Starlark function.
42// The given rawString must correspond to the string output which was created by evaluating the
43// Starlark given in StarlarkFunctionBody.
44func (g getOutputFilesRequestType) ParseResult(rawString string) []string {
45	return splitOrEmpty(rawString, ", ")
46}
47
48type getCcInfoType struct{}
49
50// Name returns a string name for this request type. Such request type names must be unique,
51// and must only consist of alphanumeric characters.
52func (g getCcInfoType) Name() string {
53	return "getCcInfo"
54}
55
56// StarlarkFunctionBody returns a starlark function body to process this request type.
57// The returned string is the body of a Starlark function which obtains
58// all request-relevant information about a target and returns a string containing
59// this information.
60// The function should have the following properties:
61//   - `target` is the only parameter to this function (a configured target).
62//   - The return value must be a string.
63//   - The function body should not be indented outside of its own scope.
64func (g getCcInfoType) StarlarkFunctionBody() string {
65	return `
66outputFiles = [f.path for f in target.files.to_list()]
67
68includes = providers(target)["CcInfo"].compilation_context.includes.to_list()
69system_includes = providers(target)["CcInfo"].compilation_context.system_includes.to_list()
70
71ccObjectFiles = []
72staticLibraries = []
73linker_inputs = providers(target)["CcInfo"].linking_context.linker_inputs.to_list()
74
75for linker_input in linker_inputs:
76  for library in linker_input.libraries:
77    for object in library.objects:
78      ccObjectFiles += [object.path]
79    if library.static_library:
80      staticLibraries.append(library.static_library.path)
81
82returns = [
83  outputFiles,
84  staticLibraries,
85  ccObjectFiles,
86  includes,
87  system_includes,
88]
89
90return "|".join([", ".join(r) for r in returns])`
91}
92
93// ParseResult returns a value obtained by parsing the result of the request's Starlark function.
94// The given rawString must correspond to the string output which was created by evaluating the
95// Starlark given in StarlarkFunctionBody.
96func (g getCcInfoType) ParseResult(rawString string) (CcInfo, error) {
97	var outputFiles []string
98	var ccObjects []string
99
100	splitString := strings.Split(rawString, "|")
101	if expectedLen := 5; len(splitString) != expectedLen {
102		return CcInfo{}, fmt.Errorf("Expected %d items, got %q", expectedLen, splitString)
103	}
104	outputFilesString := splitString[0]
105	ccStaticLibrariesString := splitString[1]
106	ccObjectsString := splitString[2]
107	outputFiles = splitOrEmpty(outputFilesString, ", ")
108	ccStaticLibraries := splitOrEmpty(ccStaticLibrariesString, ", ")
109	ccObjects = splitOrEmpty(ccObjectsString, ", ")
110	includes := splitOrEmpty(splitString[3], ", ")
111	systemIncludes := splitOrEmpty(splitString[4], ", ")
112	return CcInfo{
113		OutputFiles:          outputFiles,
114		CcObjectFiles:        ccObjects,
115		CcStaticLibraryFiles: ccStaticLibraries,
116		Includes:             includes,
117		SystemIncludes:       systemIncludes,
118	}, nil
119}
120
121// splitOrEmpty is a modification of strings.Split() that returns an empty list
122// if the given string is empty.
123func splitOrEmpty(s string, sep string) []string {
124	if len(s) < 1 {
125		return []string{}
126	} else {
127		return strings.Split(s, sep)
128	}
129}
130