// Copyright 2017 Google Inc. All rights reserved.
//
// 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 build

import (
	"android/soong/ui/metrics"
	"android/soong/ui/status"
	"bufio"
	"fmt"
	"path/filepath"
	"runtime"
	"sort"
	"strings"
)

// Checks for files in the out directory that have a rule that depends on them but no rule to
// create them. This catches a common set of build failures where a rule to generate a file is
// deleted (either by deleting a module in an Android.mk file, or by modifying the build system
// incorrectly).  These failures are often not caught by a local incremental build because the
// previously built files are still present in the output directory.
func testForDanglingRules(ctx Context, config Config) {
	// Many modules are disabled on mac.  Checking for dangling rules would cause lots of build
	// breakages, and presubmit wouldn't catch them, so just disable the check.
	if runtime.GOOS != "linux" {
		return
	}

	ctx.BeginTrace(metrics.TestRun, "test for dangling rules")
	defer ctx.EndTrace()

	ts := ctx.Status.StartTool()
	action := &status.Action{
		Description: "Test for dangling rules",
	}
	ts.StartAction(action)

	// Get a list of leaf nodes in the dependency graph from ninja
	executable := config.PrebuiltBuildTool("ninja")

	commonArgs := []string{}
	commonArgs = append(commonArgs, "-f", config.CombinedNinjaFile())
	args := append(commonArgs, "-t", "targets", "rule")

	cmd := Command(ctx, config, "ninja", executable, args...)
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		ctx.Fatal(err)
	}

	cmd.StartOrFatal()

	outDir := config.OutDir()
	modulePathsDir := filepath.Join(outDir, ".module_paths")
	rawFilesDir := filepath.Join(outDir, "soong", "raw")
	variablesFilePath := filepath.Join(outDir, "soong", "soong.variables")

	// dexpreopt.config is an input to the soong_docs action, which runs the
	// soong_build primary builder. However, this file is created from $(shell)
	// invocation at Kati parse time, so it's not an explicit output of any
	// Ninja action, but it is present during the build itself and can be
	// treated as an source file.
	dexpreoptConfigFilePath := filepath.Join(outDir, "soong", "dexpreopt.config")

	// out/build_date.txt is considered a "source file"
	buildDatetimeFilePath := filepath.Join(outDir, "build_date.txt")

	// bpglob is built explicitly using Microfactory
	bpglob := filepath.Join(config.SoongOutDir(), "bpglob")

	danglingRules := make(map[string]bool)

	scanner := bufio.NewScanner(stdout)
	for scanner.Scan() {
		line := scanner.Text()
		if !strings.HasPrefix(line, outDir) {
			// Leaf node is not in the out directory.
			continue
		}
		if strings.HasPrefix(line, modulePathsDir) ||
			strings.HasPrefix(line, rawFilesDir) ||
			line == variablesFilePath ||
			line == dexpreoptConfigFilePath ||
			line == buildDatetimeFilePath ||
			line == bpglob {
			// Leaf node is in one of Soong's bootstrap directories, which do not have
			// full build rules in the primary build.ninja file.
			continue
		}

		danglingRules[line] = true
	}

	cmd.WaitOrFatal()

	var danglingRulesList []string
	for rule := range danglingRules {
		danglingRulesList = append(danglingRulesList, rule)
	}
	sort.Strings(danglingRulesList)

	if len(danglingRulesList) > 0 {
		sb := &strings.Builder{}
		title := "Dependencies in out found with no rule to create them:"
		fmt.Fprintln(sb, title)

		reportLines := 1
		for i, dep := range danglingRulesList {
			if reportLines > 20 {
				fmt.Fprintf(sb, "  ... and %d more\n", len(danglingRulesList)-i)
				break
			}
			// It's helpful to see the reverse dependencies. ninja -t query is the
			// best tool we got for that. Its output starts with the dependency
			// itself.
			queryCmd := Command(ctx, config, "ninja", executable,
				append(commonArgs, "-t", "query", dep)...)
			queryStdout, err := queryCmd.StdoutPipe()
			if err != nil {
				ctx.Fatal(err)
			}
			queryCmd.StartOrFatal()
			scanner := bufio.NewScanner(queryStdout)
			for scanner.Scan() {
				reportLines++
				fmt.Fprintln(sb, " ", scanner.Text())
			}
			queryCmd.WaitOrFatal()
		}

		ts.FinishAction(status.ActionResult{
			Action: action,
			Error:  fmt.Errorf(title),
			Output: sb.String(),
		})
		ctx.Fatal("stopping")
	}
	ts.FinishAction(status.ActionResult{Action: action})
}
