...

Source file src/pkg/cmd/go/internal/modconv/dep.go

     1	// Copyright 2018 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	
     5	package modconv
     6	
     7	import (
     8		"fmt"
     9		"internal/lazyregexp"
    10		"net/url"
    11		"path"
    12		"strconv"
    13		"strings"
    14	
    15		"cmd/go/internal/modfile"
    16		"cmd/go/internal/module"
    17		"cmd/go/internal/semver"
    18	)
    19	
    20	func ParseGopkgLock(file string, data []byte) (*modfile.File, error) {
    21		type pkg struct {
    22			Path    string
    23			Version string
    24			Source  string
    25		}
    26		mf := new(modfile.File)
    27		var list []pkg
    28		var r *pkg
    29		for lineno, line := range strings.Split(string(data), "\n") {
    30			lineno++
    31			if i := strings.Index(line, "#"); i >= 0 {
    32				line = line[:i]
    33			}
    34			line = strings.TrimSpace(line)
    35			if line == "[[projects]]" {
    36				list = append(list, pkg{})
    37				r = &list[len(list)-1]
    38				continue
    39			}
    40			if strings.HasPrefix(line, "[") {
    41				r = nil
    42				continue
    43			}
    44			if r == nil {
    45				continue
    46			}
    47			i := strings.Index(line, "=")
    48			if i < 0 {
    49				continue
    50			}
    51			key := strings.TrimSpace(line[:i])
    52			val := strings.TrimSpace(line[i+1:])
    53			if len(val) >= 2 && val[0] == '"' && val[len(val)-1] == '"' {
    54				q, err := strconv.Unquote(val) // Go unquoting, but close enough for now
    55				if err != nil {
    56					return nil, fmt.Errorf("%s:%d: invalid quoted string: %v", file, lineno, err)
    57				}
    58				val = q
    59			}
    60			switch key {
    61			case "name":
    62				r.Path = val
    63			case "source":
    64				r.Source = val
    65			case "revision", "version":
    66				// Note: key "version" should take priority over "revision",
    67				// and it does, because dep writes toml keys in alphabetical order,
    68				// so we see version (if present) second.
    69				if key == "version" {
    70					if !semver.IsValid(val) || semver.Canonical(val) != val {
    71						break
    72					}
    73				}
    74				r.Version = val
    75			}
    76		}
    77		for _, r := range list {
    78			if r.Path == "" || r.Version == "" {
    79				return nil, fmt.Errorf("%s: empty [[projects]] stanza (%s)", file, r.Path)
    80			}
    81			mf.Require = append(mf.Require, &modfile.Require{Mod: module.Version{Path: r.Path, Version: r.Version}})
    82	
    83			if r.Source != "" {
    84				// Convert "source" to import path, such as
    85				// git@test.com:x/y.git and https://test.com/x/y.git.
    86				// We get "test.com/x/y" at last.
    87				source, err := decodeSource(r.Source)
    88				if err != nil {
    89					return nil, err
    90				}
    91				old := module.Version{Path: r.Path, Version: r.Version}
    92				new := module.Version{Path: source, Version: r.Version}
    93				mf.Replace = append(mf.Replace, &modfile.Replace{Old: old, New: new})
    94			}
    95		}
    96		return mf, nil
    97	}
    98	
    99	var scpSyntaxReg = lazyregexp.New(`^([a-zA-Z0-9_]+)@([a-zA-Z0-9._-]+):(.*)$`)
   100	
   101	func decodeSource(source string) (string, error) {
   102		var u *url.URL
   103		var p string
   104		if m := scpSyntaxReg.FindStringSubmatch(source); m != nil {
   105			// Match SCP-like syntax and convert it to a URL.
   106			// Eg, "git@github.com:user/repo" becomes
   107			// "ssh://git@github.com/user/repo".
   108			u = &url.URL{
   109				Scheme: "ssh",
   110				User:   url.User(m[1]),
   111				Host:   m[2],
   112				Path:   "/" + m[3],
   113			}
   114		} else {
   115			var err error
   116			u, err = url.Parse(source)
   117			if err != nil {
   118				return "", fmt.Errorf("%q is not a valid URI", source)
   119			}
   120		}
   121	
   122		// If no scheme was passed, then the entire path will have been put into
   123		// u.Path. Either way, construct the normalized path correctly.
   124		if u.Host == "" {
   125			p = source
   126		} else {
   127			p = path.Join(u.Host, u.Path)
   128		}
   129		p = strings.TrimSuffix(p, ".git")
   130		p = strings.TrimSuffix(p, ".hg")
   131		return p, nil
   132	}
   133	

View as plain text