1// Copyright 2017 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package load
6
7import (
8	"path/filepath"
9	"strings"
10
11	"cmd/go/internal/search"
12	"cmd/internal/pkgpattern"
13)
14
15// MatchPackage(pattern, cwd)(p) reports whether package p matches pattern in the working directory cwd.
16func MatchPackage(pattern, cwd string) func(*Package) bool {
17	switch {
18	case search.IsRelativePath(pattern):
19		// Split pattern into leading pattern-free directory path
20		// (including all . and .. elements) and the final pattern.
21		var dir string
22		i := strings.Index(pattern, "...")
23		if i < 0 {
24			dir, pattern = pattern, ""
25		} else {
26			j := strings.LastIndex(pattern[:i], "/")
27			dir, pattern = pattern[:j], pattern[j+1:]
28		}
29		dir = filepath.Join(cwd, dir)
30		if pattern == "" {
31			return func(p *Package) bool { return p.Dir == dir }
32		}
33		matchPath := pkgpattern.MatchPattern(pattern)
34		return func(p *Package) bool {
35			// Compute relative path to dir and see if it matches the pattern.
36			rel, err := filepath.Rel(dir, p.Dir)
37			if err != nil {
38				// Cannot make relative - e.g. different drive letters on Windows.
39				return false
40			}
41			rel = filepath.ToSlash(rel)
42			if rel == ".." || strings.HasPrefix(rel, "../") {
43				return false
44			}
45			return matchPath(rel)
46		}
47	case pattern == "all":
48		return func(p *Package) bool { return true }
49	case pattern == "std":
50		return func(p *Package) bool { return p.Standard }
51	case pattern == "cmd":
52		return func(p *Package) bool { return p.Standard && strings.HasPrefix(p.ImportPath, "cmd/") }
53	default:
54		matchPath := pkgpattern.MatchPattern(pattern)
55		return func(p *Package) bool { return matchPath(p.ImportPath) }
56	}
57}
58