async def generate_targets_from_go_mod( request: GenerateTargetsFromGoModRequest, union_membership: UnionMembership, ) -> GeneratedTargets: generator_addr = request.generator.address go_mod_info = await Get( GoModInfo, GoModInfoRequest(request.generator[GoModSourcesField])) all_packages = await Get( AllThirdPartyPackages, AllThirdPartyPackagesRequest(go_mod_info.digest, go_mod_info.mod_path), ) def create_tgt( pkg_info: ThirdPartyPkgAnalysis) -> GoThirdPartyPackageTarget: return GoThirdPartyPackageTarget( {GoImportPathField.alias: pkg_info.import_path}, # E.g. `src/go:mod#github.com/google/uuid`. generator_addr.create_generated(pkg_info.import_path), union_membership, residence_dir=generator_addr.spec_path, ) return GeneratedTargets( request.generator, (create_tgt(pkg_info) for pkg_info in all_packages.import_paths_to_pkg_info.values()), )
def test_invalid_go_sum(rule_runner: RuleRunner) -> None: digest = set_up_go_mod( rule_runner, dedent("""\ module example.com/third-party-module go 1.17 require github.com/google/uuid v1.3.0 """), dedent("""\ github.com/google/uuid v1.3.0 h1:00000gmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:00000e4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= """), ) with engine_error(ProcessExecutionFailure, contains="SECURITY ERROR"): rule_runner.request(AllThirdPartyPackages, [AllThirdPartyPackagesRequest(digest, "go.mod")])
def test_module_with_no_packages(rule_runner) -> None: digest = set_up_go_mod( rule_runner, dedent("""\ module example.com/third-party-module go 1.17 require github.com/Azure/go-autorest v13.3.2+incompatible """), dedent("""\ github.com/Azure/go-autorest v13.3.2+incompatible h1:VxzPyuhtnlBOzc4IWCZHqpyH2d+QMLQEuy3wREyY4oc= github.com/Azure/go-autorest v13.3.2+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= """), ) all_packages = rule_runner.request(AllThirdPartyPackages, [AllThirdPartyPackagesRequest(digest)]) assert not all_packages.import_paths_to_pkg_info
def test_missing_go_sum(rule_runner: RuleRunner) -> None: digest = set_up_go_mod( rule_runner, dedent("""\ module example.com/third-party-module go 1.17 require github.com/google/uuid v1.3.0 """), # `go.sum` is for a different module. dedent("""\ cloud.google.com/go v0.26.0 h1:e0WKqKTd5BnrG8aKH3J3h+QvEIQtSUcf2n5UZ5ZgLtQ= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= """), ) with engine_error( contains="github.com/google/[email protected]: missing go.sum entry"): rule_runner.request(AllThirdPartyPackages, [AllThirdPartyPackagesRequest(digest, "go.mod")])
async def generate_targets_from_go_mod( request: GenerateTargetsFromGoModRequest, union_membership: UnionMembership, ) -> GeneratedTargets: generator_addr = request.generator.address go_mod_sources = request.generator[GoModSourcesField] go_mod_info = await Get(GoModInfo, GoModInfoRequest(go_mod_sources)) go_mod_snapshot = await Get(Snapshot, Digest, go_mod_info.digest) all_packages = await Get( AllThirdPartyPackages, AllThirdPartyPackagesRequest(go_mod_info.digest, go_mod_info.mod_path), ) def gen_file_tgt(fp: str) -> TargetGeneratorSourcesHelperTarget: return TargetGeneratorSourcesHelperTarget( {TargetGeneratorSourcesHelperSourcesField.alias: fp}, generator_addr.create_file(fp), union_membership, ) file_tgts = [gen_file_tgt("go.mod")] if go_mod_sources.go_sum_path in go_mod_snapshot.files: file_tgts.append(gen_file_tgt("go.sum")) def create_tgt(pkg_info: ThirdPartyPkgAnalysis) -> GoThirdPartyPackageTarget: return GoThirdPartyPackageTarget( { **request.template, GoImportPathField.alias: pkg_info.import_path, Dependencies.alias: [t.address.spec for t in file_tgts], }, # E.g. `src/go:mod#github.com/google/uuid`. generator_addr.create_generated(pkg_info.import_path), union_membership, residence_dir=generator_addr.spec_path, ) result = tuple( create_tgt(pkg_info) for pkg_info in all_packages.import_paths_to_pkg_info.values() ) + tuple(file_tgts) return GeneratedTargets(request.generator, result)
def test_stale_go_mod(rule_runner: RuleRunner) -> None: digest = set_up_go_mod( rule_runner, # Go 1.17+ expects indirect dependencies to be included in the `go.mod`, i.e. # `golang.org/x/xerrors `. dedent("""\ module example.com/third-party-module go 1.17 require github.com/google/go-cmp v0.5.6 """), dedent("""\ github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= """), ) with engine_error(ProcessExecutionFailure, contains="updates to go.mod needed"): rule_runner.request(AllThirdPartyPackages, [AllThirdPartyPackagesRequest(digest, "go.mod")])
def test_download_and_analyze_all_packages(rule_runner: RuleRunner) -> None: input_digest = rule_runner.make_snapshot({ "go.mod": GO_MOD, "go.sum": GO_SUM }).digest all_packages = rule_runner.request( AllThirdPartyPackages, [AllThirdPartyPackagesRequest(input_digest, "go.mod")]) assert set(all_packages.import_paths_to_pkg_info.keys()) == { "golang.org/x/text/encoding/japanese", "golang.org/x/text/message/catalog", "golang.org/x/text/internal/testtext", "golang.org/x/text/encoding/ianaindex", "golang.org/x/text/cmd/gotext", "golang.org/x/text/width", "golang.org/x/text/internal/format", "rsc.io/sampler", "golang.org/x/text/internal/tag", "golang.org/x/text/unicode/norm", "golang.org/x/text/number", "golang.org/x/text/transform", "golang.org/x/text/internal", "golang.org/x/text/internal/utf8internal", "golang.org/x/text/language/display", "golang.org/x/text/internal/stringset", "golang.org/x/text/encoding/korean", "golang.org/x/text/internal/triegen", "golang.org/x/text/secure/bidirule", "golang.org/x/text/secure/precis", "golang.org/x/text/language", "golang.org/x/text/encoding/unicode/utf32", "golang.org/x/text/internal/colltab", "golang.org/x/text/unicode/rangetable", "golang.org/x/text/encoding/htmlindex", "golang.org/x/text/internal/export/idna", "golang.org/x/text/encoding/charmap", "golang.org/x/text/unicode/cldr", "golang.org/x/text/secure", "golang.org/x/text/internal/ucd", "golang.org/x/text/feature/plural", "golang.org/x/text/unicode", "golang.org/x/text/encoding/traditionalchinese", "golang.org/x/text/runes", "golang.org/x/text/internal/catmsg", "rsc.io/quote/buggy", "golang.org/x/text/encoding/simplifiedchinese", "golang.org/x/text/cases", "golang.org/x/text/encoding/internal", "github.com/google/uuid", "golang.org/x/text/encoding/internal/enctest", "golang.org/x/text/collate/build", "golang.org/x/text", "golang.org/x/text/unicode/bidi", "golang.org/x/text/search", "golang.org/x/text/unicode/runenames", "golang.org/x/text/message", "golang.org/x/text/encoding", "golang.org/x/text/encoding/unicode", "rsc.io/quote", "golang.org/x/text/currency", "golang.org/x/text/internal/number", "golang.org/x/text/collate/tools/colcmp", "golang.org/x/text/encoding/internal/identifier", "golang.org/x/text/collate", "golang.org/x/text/internal/gen", } def assert_pkg_info( import_path: str, dir_path: str, imports: tuple[str, ...], go_files: tuple[str, ...], extra_files: tuple[str, ...], minimum_go_version: str | None, ) -> None: assert import_path in all_packages.import_paths_to_pkg_info pkg_info = all_packages.import_paths_to_pkg_info[import_path] assert pkg_info.import_path == import_path assert pkg_info.dir_path == dir_path assert pkg_info.imports == imports assert pkg_info.go_files == go_files assert not pkg_info.s_files snapshot = rule_runner.request(Snapshot, [pkg_info.digest]) assert set(snapshot.files) == { os.path.join(dir_path, file_name) for file_name in (*go_files, *extra_files) } assert pkg_info.minimum_go_version == minimum_go_version assert_pkg_info( import_path="github.com/google/uuid", dir_path="gopath/pkg/mod/github.com/google/[email protected]", imports=( "bytes", "crypto/md5", "crypto/rand", "crypto/sha1", "database/sql/driver", "encoding/binary", "encoding/hex", "encoding/json", "errors", "fmt", "hash", "io", "net", "os", "strings", "sync", "time", ), go_files=( "dce.go", "doc.go", "hash.go", "marshal.go", "node.go", "node_net.go", "null.go", "sql.go", "time.go", "util.go", "uuid.go", "version1.go", "version4.go", ), extra_files=( ".travis.yml", "CONTRIBUTING.md", "CONTRIBUTORS", "LICENSE", "README.md", "go.mod", "json_test.go", "node_js.go", "null_test.go", "seq_test.go", "sql_test.go", "uuid_test.go", ), minimum_go_version=None, ) assert_pkg_info( import_path="golang.org/x/text/unicode/bidi", dir_path= "gopath/pkg/mod/golang.org/x/[email protected]/unicode/bidi", imports=("container/list", "fmt", "log", "sort", "unicode/utf8"), go_files=("bidi.go", "bracket.go", "core.go", "prop.go", "tables.go", "trieval.go"), extra_files=( "core_test.go", "gen.go", "gen_ranges.go", "gen_trieval.go", "ranges_test.go", "tables_test.go", ), minimum_go_version=None, )
async def generate_targets_from_go_mod( request: GenerateTargetsFromGoModRequest, files_not_found_behavior: FilesNotFoundBehavior, union_membership: UnionMembership, ) -> GeneratedTargets: generator_addr = request.generator.address go_mod_info, go_paths = await MultiGet( Get(GoModInfo, GoModInfoRequest(generator_addr)), Get( Paths, PathGlobs, request.generator[GoModPackageSourcesField].path_globs( files_not_found_behavior), ), ) all_third_party_packages = await Get( AllThirdPartyPackages, AllThirdPartyPackagesRequest(go_mod_info.stripped_digest), ) dir_to_filenames = group_by_dir(go_paths.files) matched_dirs = [ dir for dir, filenames in dir_to_filenames.items() if filenames ] def create_first_party_package_tgt(dir: str) -> GoFirstPartyPackageTarget: subpath = fast_relpath(dir, generator_addr.spec_path) import_path = f"{go_mod_info.import_path}/{subpath}" if subpath else go_mod_info.import_path return GoFirstPartyPackageTarget( { GoImportPathField.alias: import_path, GoFirstPartyPackageSubpathField.alias: subpath, GoFirstPartyPackageSourcesField.alias: tuple( sorted( os.path.join(subpath, f) for f in dir_to_filenames[dir])), }, # E.g. `src/go:mod#./subdir`. generator_addr.create_generated(f"./{subpath}"), union_membership, residence_dir=dir, ) first_party_pkgs = (create_first_party_package_tgt(dir) for dir in matched_dirs) def create_third_party_package_tgt( pkg_info: ThirdPartyPkgInfo) -> GoThirdPartyPackageTarget: return GoThirdPartyPackageTarget( {GoImportPathField.alias: pkg_info.import_path}, # E.g. `src/go:mod#github.com/google/uuid`. generator_addr.create_generated(pkg_info.import_path), union_membership, residence_dir=generator_addr.spec_path, ) third_party_pkgs = (create_third_party_package_tgt(pkg_info) for pkg_info in all_third_party_packages. import_paths_to_pkg_info.values()) return GeneratedTargets(request.generator, (*first_party_pkgs, *third_party_pkgs))