github.com/nya3jp/tast@v0.0.0-20230601000426-85c8e4d83a9b/src/go.chromium.org/tast/core/cmd/tast-lint/internal/check/forbidden_bundle_imports.go (about)

     1  // Copyright 2019 The ChromiumOS Authors
     2  // Use of this source code is governed by a BSD-style license that can be
     3  // found in the LICENSE file.
     4  
     5  package check
     6  
     7  import (
     8  	"fmt"
     9  	"go/ast"
    10  	"go/token"
    11  	"path"
    12  	"path/filepath"
    13  	"regexp"
    14  	"strconv"
    15  	"strings"
    16  )
    17  
    18  var bundleCategoryRegex = regexp.MustCompile(`^(go.chromium.org/tast-tests/cros/(?:local|remote)/bundles/\w+)/(\w+)`)
    19  
    20  // parseBundlePackage analyzes full package path and returns matching bundle prefix and the category name.
    21  // Returns ok=false if it's not a bundle (sub)package.
    22  //
    23  // Example:
    24  //
    25  //	"go.chromium.org/tast-tests/cros/local/bundles/cros/foo"         -> "go.chromium.org/tast-tests/cros/local/bundles/cros", "foo", true
    26  //	"go.chromium.org/tast-tests/cros/remote/bundles/crosint/foo/bar" -> "go.chromium.org/tast-tests/cros/remote/bundles/crosint", "foo", true
    27  //	"go.chromium.org/tast-tests/cros/local/foo"                      -> "", "", false
    28  func parseBundlePackage(p string) (bundlePkg, category string, ok bool) {
    29  	m := bundleCategoryRegex.FindStringSubmatch(p)
    30  	if len(m) == 0 {
    31  		return "", "", false
    32  	}
    33  	return m[1], m[2], true
    34  }
    35  
    36  // ForbiddenBundleImports makes sure libraries in another package under bundles/ are not imported.
    37  func ForbiddenBundleImports(fs *token.FileSet, f *ast.File) []*Issue {
    38  	filename := fs.Position(f.Package).Filename
    39  	mypkg := strings.TrimPrefix(filepath.Dir(filename), "src/")
    40  	myBundlePkg, myCategory, isBundle := parseBundlePackage(mypkg)
    41  	myBundlePath := path.Dir(myBundlePkg)
    42  
    43  	var issues []*Issue
    44  	for _, im := range f.Imports {
    45  		p, err := strconv.Unquote(im.Path.Value)
    46  		if err != nil {
    47  			continue
    48  		}
    49  
    50  		bundlePkg, category, ok := parseBundlePackage(p)
    51  		if !ok {
    52  			continue
    53  		}
    54  
    55  		// Allow import from main.go .
    56  		if mypkg == bundlePkg {
    57  			continue
    58  		}
    59  
    60  		// Allow import from package category across bundles.
    61  		bundlePath := path.Dir(bundlePkg)
    62  		if isBundle && myBundlePath == bundlePath && myCategory == category {
    63  			continue
    64  		}
    65  
    66  		categoryPkg := path.Join(bundlePath, "*", category)
    67  
    68  		issues = append(issues, &Issue{
    69  			Pos:  fs.Position(im.Pos()),
    70  			Msg:  fmt.Sprintf("import of %s is only allowed from %s or its descendant", p, categoryPkg),
    71  			Link: "https://chromium.googlesource.com/chromiumos/platform/tast/+/HEAD/docs/writing_tests.md#Scoping-and-shared-code",
    72  		})
    73  	}
    74  
    75  	return issues
    76  }