1// Copyright 2022 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package main
16
17import (
18	"flag"
19	"fmt"
20	"io/ioutil"
21	"os"
22	"strings"
23
24	"google.golang.org/protobuf/encoding/prototext"
25	"google.golang.org/protobuf/proto"
26
27	"android/soong/compliance/license_metadata_proto"
28	"android/soong/response"
29)
30
31func newMultiString(flags *flag.FlagSet, name, usage string) *multiString {
32	var f multiString
33	flags.Var(&f, name, usage)
34	return &f
35}
36
37type multiString []string
38
39func (ms *multiString) String() string     { return strings.Join(*ms, ", ") }
40func (ms *multiString) Set(s string) error { *ms = append(*ms, s); return nil }
41
42func main() {
43	var expandedArgs []string
44	for _, arg := range os.Args[1:] {
45		if strings.HasPrefix(arg, "@") {
46			f, err := os.Open(strings.TrimPrefix(arg, "@"))
47			if err != nil {
48				fmt.Fprintln(os.Stderr, err.Error())
49				os.Exit(1)
50			}
51
52			respArgs, err := response.ReadRspFile(f)
53			f.Close()
54			if err != nil {
55				fmt.Fprintln(os.Stderr, err.Error())
56				os.Exit(1)
57			}
58			expandedArgs = append(expandedArgs, respArgs...)
59		} else {
60			expandedArgs = append(expandedArgs, arg)
61		}
62	}
63
64	flags := flag.NewFlagSet("flags", flag.ExitOnError)
65
66	installed := flags.String("i", "", "installed target")
67	sources := newMultiString(flags, "s", "source (input) file")
68	dep := flags.String("d", "", "license metadata file dependency")
69	outFile := flags.String("o", "", "output file")
70
71	flags.Parse(expandedArgs)
72
73	if len(*dep) == 0 || len(*installed) == 0 || len(*sources) == 0 {
74		flags.Usage()
75		if len(*dep) == 0 {
76			fmt.Fprintf(os.Stderr, "source license metadata (-d flag) required\n")
77		}
78		if len(*sources) == 0 {
79			fmt.Fprintf(os.Stderr, "source copy (-s flag required\n")
80		}
81		if len(*installed) == 0 {
82			fmt.Fprintf(os.Stderr, "installed copy (-i flag) required\n")
83		}
84		os.Exit(1)
85	}
86
87	src_metadata := license_metadata_proto.LicenseMetadata{}
88	err := readMetadata(*dep, &src_metadata)
89	if err != nil {
90		fmt.Fprintf(os.Stderr, "error: %s\n", err.Error())
91		os.Exit(2)
92	}
93
94	metadata := src_metadata
95	metadata.Built = nil
96	metadata.InstallMap = nil
97	metadata.Installed = []string{*installed}
98	metadata.Sources = *sources
99	metadata.Deps = []*license_metadata_proto.AnnotatedDependency{&license_metadata_proto.AnnotatedDependency{
100		File:        proto.String(*dep),
101		Annotations: []string{"static"},
102	}}
103
104	err = writeMetadata(*outFile, &metadata)
105	if err != nil {
106		fmt.Fprintf(os.Stderr, "error: %s\n", err.Error())
107		os.Exit(2)
108	}
109}
110
111func readMetadata(file string, metadata *license_metadata_proto.LicenseMetadata) error {
112	if file == "" {
113		return fmt.Errorf("source metadata file (-d) required")
114	}
115	buf, err := ioutil.ReadFile(file)
116	if err != nil {
117		return fmt.Errorf("error reading textproto %q: %w", file, err)
118	}
119
120	err = prototext.Unmarshal(buf, metadata)
121	if err != nil {
122		return fmt.Errorf("error unmarshalling textproto: %w", err)
123	}
124
125	return nil
126}
127
128func writeMetadata(file string, metadata *license_metadata_proto.LicenseMetadata) error {
129	buf, err := prototext.MarshalOptions{Multiline: true}.Marshal(metadata)
130	if err != nil {
131		return fmt.Errorf("error marshalling textproto: %w", err)
132	}
133
134	if file != "" {
135		err = ioutil.WriteFile(file, buf, 0666)
136		if err != nil {
137			return fmt.Errorf("error writing textproto %q: %w", file, err)
138		}
139	} else {
140		_, _ = os.Stdout.Write(buf)
141	}
142
143	return nil
144}
145