Skip to content

Commit

Permalink
internal/postgres: add GetPackagesInDirectory
Browse files Browse the repository at this point in the history
GetPackagesInDirectory is added, which uses the paths table to get all
of the packages within a given directory path. This will replace
LegacyGetDirectory and LegacyGetPackagesInModule in creating the
directories tab.

For golang/go#39629

Change-Id: I4b39690e838756421bee9b5ca389081e184761bf
Reviewed-on: https://go-review.googlesource.com/c/pkgsite/+/241838
Reviewed-by: Jonathan Amsterdam <jba@google.com>
  • Loading branch information
julieqiu committed Jul 10, 2020
1 parent 2dc763b commit 7924eac
Show file tree
Hide file tree
Showing 4 changed files with 239 additions and 11 deletions.
61 changes: 61 additions & 0 deletions internal/postgres/directory.go
Expand Up @@ -9,6 +9,7 @@ import (
"database/sql"
"fmt"
"sort"
"strings"

"github.com/lib/pq"
"golang.org/x/pkgsite/internal"
Expand All @@ -17,6 +18,66 @@ import (
"golang.org/x/pkgsite/internal/stdlib"
)

// GetPackagesInDirectory returns all of the packages in a directory from a
// module version, including the package that lives at dirPath, if present.
func (db *DB) GetPackagesInDirectory(ctx context.Context, dirPath, modulePath, resolvedVersion string) (_ []*internal.PackageMeta, err error) {
defer derrors.Wrap(&err, "DB.GetPackagesInDirectory(ctx, %q, %q, %q)", dirPath, modulePath, resolvedVersion)

query := `
SELECT
p.path,
p.name,
p.v1_path,
p.redistributable,
d.synopsis,
p.license_types,
p.license_paths
FROM modules m
INNER JOIN paths p
ON p.module_id = m.id
INNER JOIN documentation d
ON d.path_id = p.id
WHERE
m.module_path = $1
AND m.version = $2
ORDER BY path;`
var packages []*internal.PackageMeta
collect := func(rows *sql.Rows) error {
var (
pkg internal.PackageMeta
licenseTypes []string
licensePaths []string
)
if err := rows.Scan(
&pkg.Path,
&pkg.Name,
&pkg.V1Path,
&pkg.IsRedistributable,
&pkg.Synopsis,
pq.Array(&licenseTypes),
pq.Array(&licensePaths),
); err != nil {
return fmt.Errorf("row.Scan(): %v", err)
}
if dirPath == stdlib.ModulePath || pkg.Path == dirPath || strings.HasPrefix(pkg.Path, dirPath+"/") {
lics, err := zipLicenseMetadata(licenseTypes, licensePaths)
if err != nil {
return err
}
pkg.Licenses = lics
packages = append(packages, &pkg)
}
return nil
}
if err := db.db.RunQuery(ctx, query, collect, modulePath, resolvedVersion); err != nil {
return nil, err
}
if len(packages) == 0 {
return nil, fmt.Errorf("directory does not contain any packages: %w", derrors.NotFound)
}
return packages, nil
}

// GetDirectoryNew returns a directory from the database, along with all of the
// data associated with that directory, including the package, imports, readme,
// documentation, and licenses.
Expand Down
166 changes: 158 additions & 8 deletions internal/postgres/directory_test.go
Expand Up @@ -7,7 +7,6 @@ package postgres
import (
"context"
"errors"
"sort"
"testing"

"github.com/google/go-cmp/cmp"
Expand All @@ -21,6 +20,161 @@ import (
"golang.org/x/pkgsite/internal/testing/sample"
)

func TestGetPackagesInDirectory(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), testTimeout)
defer cancel()

defer ResetTestDB(testDB, t)

InsertSampleDirectoryTree(ctx, t, testDB)

for _, tc := range []struct {
name, dirPath, modulePath, version, wantModulePath, wantVersion string
wantSuffixes []string
wantNotFoundErr bool
}{
{
name: "directory path is the module path",
dirPath: "github.com/hashicorp/vault",
modulePath: "github.com/hashicorp/vault",
version: "v1.2.3",
wantVersion: "v1.2.3",
wantModulePath: "github.com/hashicorp/vault",
wantSuffixes: []string{
"builtin/audit/file",
"builtin/audit/socket",
"internal/foo",
"vault/replication",
"vault/seal/transit",
},
},
{
name: "directory path is a package path",
dirPath: "github.com/hashicorp/vault",
modulePath: "github.com/hashicorp/vault",
version: "v1.0.3",
wantVersion: "v1.0.3",
wantModulePath: "github.com/hashicorp/vault",
wantSuffixes: []string{
"api",
"builtin/audit/file",
"builtin/audit/socket",
},
},
{
name: "directory path is not a package or module",
dirPath: "github.com/hashicorp/vault/builtin",
modulePath: "github.com/hashicorp/vault",
wantModulePath: "github.com/hashicorp/vault",
version: "v1.0.3",
wantVersion: "v1.0.3",
wantSuffixes: []string{
"builtin/audit/file",
"builtin/audit/socket",
},
},
{
name: "stdlib module",
dirPath: stdlib.ModulePath,
modulePath: stdlib.ModulePath,
version: "v1.13.4",
wantModulePath: stdlib.ModulePath,
wantVersion: "v1.13.4",
wantSuffixes: []string{
"archive/tar",
"archive/zip",
"cmd/go",
"cmd/internal/obj",
"cmd/internal/obj/arm",
"cmd/internal/obj/arm64",
},
},
{
name: "stdlib directory",
dirPath: "archive",
modulePath: stdlib.ModulePath,
version: "v1.13.4",
wantModulePath: stdlib.ModulePath,
wantVersion: "v1.13.4",
wantSuffixes: []string{
"archive/tar",
"archive/zip",
},
},
{
name: "stdlib package",
dirPath: "archive/zip",
modulePath: stdlib.ModulePath,
version: "v1.13.4",
wantModulePath: stdlib.ModulePath,
wantVersion: "v1.13.4",
wantSuffixes: []string{
"archive/zip",
},
},
{
name: "stdlib package - incomplete last element",
dirPath: "archive/zi",
modulePath: stdlib.ModulePath,
version: "v1.13.4",
wantNotFoundErr: true,
},
{
name: "stdlib - internal directory",
dirPath: "cmd/internal",
modulePath: stdlib.ModulePath,
version: "v1.13.4",
wantModulePath: stdlib.ModulePath,
wantVersion: "v1.13.4",
wantSuffixes: []string{
"cmd/internal/obj",
"cmd/internal/obj/arm",
"cmd/internal/obj/arm64",
},
},
{
name: "stdlib - directory nested within an internal directory",
dirPath: "cmd/internal/obj",
modulePath: stdlib.ModulePath,
version: "v1.13.4",
wantModulePath: stdlib.ModulePath,
wantVersion: "v1.13.4",
wantSuffixes: []string{
"cmd/internal/obj",
"cmd/internal/obj/arm",
"cmd/internal/obj/arm64",
},
},
} {
t.Run(tc.name, func(t *testing.T) {
got, err := testDB.GetPackagesInDirectory(ctx, tc.dirPath, tc.modulePath, tc.version)
if tc.wantNotFoundErr {
if !errors.Is(err, derrors.NotFound) {
t.Fatalf("got error %v; want %v", err, derrors.NotFound)
}
return
}
if err != nil {
t.Fatal(err)
}

var wantPackages []*internal.PackageMeta
for _, suffix := range tc.wantSuffixes {
pkg := sample.PackageMeta(tc.wantModulePath, suffix)
wantPackages = append(wantPackages, pkg)
}

opts := []cmp.Option{
// The packages table only includes partial license information; it omits the Coverage field.
cmpopts.IgnoreFields(licenses.Metadata{}, "Coverage"),
}
if diff := cmp.Diff(wantPackages, got, opts...); diff != "" {
t.Errorf("mismatch (-want +got):\n%s", diff)
}
})
}
}

func TestLegacyGetDirectory(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), testTimeout)
defer cancel()
Expand Down Expand Up @@ -90,9 +244,9 @@ func TestLegacyGetDirectory(t *testing.T) {
wantVersion: "v1.2.3",
wantModulePath: "github.com/hashicorp/vault",
wantSuffixes: []string{
"internal/foo",
"builtin/audit/file",
"builtin/audit/socket",
"internal/foo",
"vault/replication",
"vault/seal/transit",
},
Expand Down Expand Up @@ -191,8 +345,8 @@ func TestLegacyGetDirectory(t *testing.T) {
wantModulePath: stdlib.ModulePath,
wantVersion: "v1.13.4",
wantSuffixes: []string{
"archive/zip",
"archive/tar",
"archive/zip",
},
},
{
Expand Down Expand Up @@ -244,7 +398,7 @@ func TestLegacyGetDirectory(t *testing.T) {
got, err := testDB.LegacyGetDirectory(ctx, tc.dirPath, tc.modulePath, tc.version, internal.AllFields)
if tc.wantNotFoundErr {
if !errors.Is(err, derrors.NotFound) {
t.Fatalf("want %v; got = \n%+v, %v", derrors.NotFound, got, err)
t.Fatalf("got error %v; want %v", err, derrors.NotFound)
}
return
}
Expand All @@ -259,17 +413,13 @@ func TestLegacyGetDirectory(t *testing.T) {
pkg.Imports = nil
wantPackages = append(wantPackages, pkg)
}
sort.Slice(wantPackages, func(i, j int) bool {
return wantPackages[i].Path < wantPackages[j].Path
})

wantDirectory := &internal.LegacyDirectory{
LegacyModuleInfo: *mi,
Packages: wantPackages,
Path: tc.dirPath,
}
opts := []cmp.Option{
cmpopts.EquateEmpty(),
cmp.AllowUnexported(source.Info{}, safehtml.HTML{}),
// The packages table only includes partial license information; it omits the Coverage field.
cmpopts.IgnoreFields(licenses.Metadata{}, "Coverage"),
Expand Down
6 changes: 3 additions & 3 deletions internal/postgres/test_helper.go
Expand Up @@ -159,8 +159,8 @@ func InsertSampleDirectoryTree(ctx context.Context, t *testing.T, testDB *DB) {
"std",
"v1.13.4",
[]string{
"archive/zip",
"archive/tar",
"archive/zip",
"cmd/go",
"cmd/internal/obj",
"cmd/internal/obj/arm",
Expand All @@ -171,8 +171,8 @@ func InsertSampleDirectoryTree(ctx context.Context, t *testing.T, testDB *DB) {
"std",
"v1.13.0",
[]string{
"archive/zip",
"archive/tar",
"archive/zip",
"cmd/go",
"cmd/internal/obj",
"cmd/internal/obj/arm",
Expand All @@ -199,9 +199,9 @@ func InsertSampleDirectoryTree(ctx context.Context, t *testing.T, testDB *DB) {
"github.com/hashicorp/vault",
"v1.2.3",
[]string{
"internal/foo",
"builtin/audit/file",
"builtin/audit/socket",
"internal/foo",
"vault/replication",
"vault/seal/transit",
},
Expand Down
17 changes: 17 additions & 0 deletions internal/testing/sample/sample.go
Expand Up @@ -107,6 +107,23 @@ func LegacyPackage(modulePath, suffix string) *internal.LegacyPackage {
}
}

func PackageMeta(modulePath, suffix string) *internal.PackageMeta {
pkgPath := suffix
if modulePath != stdlib.ModulePath {
pkgPath = path.Join(modulePath, suffix)
}
return &internal.PackageMeta{
DirectoryMeta: internal.DirectoryMeta{
Path: pkgPath,
V1Path: internal.V1Path(modulePath, suffix),
IsRedistributable: true,
Licenses: LicenseMetadata,
},
Name: path.Base(pkgPath),
Synopsis: Synopsis,
}
}

func LegacyModuleInfo(modulePath, versionString string) *internal.LegacyModuleInfo {
vtype, err := version.ParseType(versionString)
if err != nil {
Expand Down

0 comments on commit 7924eac

Please sign in to comment.