192 lines
4.7 KiB
Go
192 lines
4.7 KiB
Go
// Copyright 2022 The Android Open Source Project
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package report
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"io/fs"
|
|
"path/filepath"
|
|
|
|
"tools/treble/build/report/app"
|
|
)
|
|
|
|
// Find all binary executables under the given directory along with the number
|
|
// of symlinks
|
|
//
|
|
func binaryExecutables(ctx context.Context, dir string, recursive bool) ([]string, int, error) {
|
|
var files []string
|
|
numSymLinks := 0
|
|
err := filepath.WalkDir(dir, func(path string, d fs.DirEntry, err error) error {
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if !d.IsDir() {
|
|
if info, err := d.Info(); err == nil {
|
|
if info.Mode()&0111 != 0 {
|
|
files = append(files, path)
|
|
}
|
|
if d.Type()&fs.ModeSymlink != 0 {
|
|
numSymLinks++
|
|
}
|
|
}
|
|
} else {
|
|
if !recursive {
|
|
if path != dir {
|
|
return filepath.SkipDir
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
})
|
|
|
|
return files, numSymLinks, err
|
|
}
|
|
|
|
// Resolve the manifest
|
|
func (rtx *Context) ResolveProjectMap(ctx context.Context, manifest string, upstreamBranch string) {
|
|
if rtx.Info == nil {
|
|
rtx.Info = resolveProjectMap(ctx, rtx, manifest, true, upstreamBranch)
|
|
}
|
|
}
|
|
|
|
// Find host tools
|
|
func ResolveHostTools(ctx context.Context, hostToolPath string) (*app.HostReport, error) {
|
|
out := &app.HostReport{Path: hostToolPath}
|
|
out.Targets, out.SymLinks, _ = binaryExecutables(ctx, hostToolPath, true)
|
|
return out, nil
|
|
}
|
|
|
|
// Run reports
|
|
|
|
//
|
|
// Run report request
|
|
//
|
|
// Setup routines to:
|
|
// - resolve the manifest projects
|
|
// - resolve build queries
|
|
//
|
|
// Once the manifest projects have been resolved the build
|
|
// queries can be fully resolved
|
|
//
|
|
func RunReport(ctx context.Context, rtx *Context, req *app.ReportRequest) (*app.Report, error) {
|
|
inChan, targetCh := targetResolvers(ctx, rtx)
|
|
go func() {
|
|
for i, _ := range req.Targets {
|
|
inChan <- req.Targets[i]
|
|
}
|
|
close(inChan)
|
|
}()
|
|
|
|
// Resolve the build inputs into build target projects
|
|
buildTargetChan := resolveBuildInputs(ctx, rtx, targetCh)
|
|
|
|
out := &app.Report{Targets: make(map[string]*app.BuildTarget)}
|
|
for bt := range buildTargetChan {
|
|
out.Targets[bt.Name] = bt
|
|
}
|
|
|
|
return out, nil
|
|
}
|
|
|
|
// Resolve commit into git commit info
|
|
func ResolveCommit(ctx context.Context, rtx *Context, commit *app.ProjectCommit) (*app.GitCommit, []string, error) {
|
|
if proj, exists := rtx.Info.ProjMap[commit.Project]; exists {
|
|
info, err := rtx.Project.CommitInfo(ctx, proj.GitProj, commit.Revision)
|
|
files := []string{}
|
|
if err == nil {
|
|
for _, f := range info.Files {
|
|
if f.Type != app.GitFileRemoved {
|
|
files = append(files, filepath.Join(proj.GitProj.RepoDir, f.Filename))
|
|
}
|
|
}
|
|
}
|
|
return info, files, err
|
|
}
|
|
return nil, nil, errors.New(fmt.Sprintf("Unknown project %s", commit.Project))
|
|
|
|
}
|
|
|
|
// Run query report based on the input request.
|
|
//
|
|
// For each input file query the target and
|
|
// create a set of the inputs and outputs associated
|
|
// with all the input files.
|
|
//
|
|
//
|
|
func RunQuery(ctx context.Context, rtx *Context, req *app.QueryRequest) (*app.QueryResponse, error) {
|
|
inChan, queryCh := queryResolvers(ctx, rtx)
|
|
|
|
go func() {
|
|
// Convert source files to outputs
|
|
for _, target := range req.Files {
|
|
inChan <- target
|
|
}
|
|
close(inChan)
|
|
}()
|
|
|
|
inFiles := make(map[string]bool)
|
|
outFiles := make(map[string]bool)
|
|
unknownSrcFiles := make(map[string]bool)
|
|
for result := range queryCh {
|
|
if result.error {
|
|
unknownSrcFiles[result.source] = true
|
|
} else {
|
|
for _, outFile := range result.query.Outputs {
|
|
outFiles[outFile] = true
|
|
}
|
|
for _, inFile := range result.query.Inputs {
|
|
inFiles[inFile] = true
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
out := &app.QueryResponse{}
|
|
for k, _ := range outFiles {
|
|
out.OutputFiles = append(out.OutputFiles, k)
|
|
}
|
|
for k, _ := range inFiles {
|
|
out.InputFiles = append(out.InputFiles, k)
|
|
}
|
|
for k, _ := range unknownSrcFiles {
|
|
out.UnknownFiles = append(out.UnknownFiles, k)
|
|
}
|
|
|
|
return out, nil
|
|
}
|
|
|
|
// Get paths
|
|
func RunPaths(ctx context.Context, rtx *Context, target string, singlePath bool, files []string) []*app.BuildPath {
|
|
out := []*app.BuildPath{}
|
|
inChan, pathCh := pathsResolvers(ctx, rtx, target, singlePath)
|
|
// Convert source files to outputs
|
|
go func() {
|
|
for _, f := range files {
|
|
inChan <- f
|
|
}
|
|
close(inChan)
|
|
}()
|
|
|
|
for result := range pathCh {
|
|
if !result.error {
|
|
out = append(out, result.path)
|
|
}
|
|
}
|
|
return out
|
|
|
|
}
|