Best Syzkaller code snippet using vcs.String
vcs.go
Source:vcs.go
...161 return "", err162 }163 out := strings.TrimSpace(string(outb))164 var repoURL *url.URL165 if m := scpSyntaxRe.FindStringSubmatch(out); m != nil {166 // Match SCP-like syntax and convert it to a URL.167 // Eg, "git@github.com:user/repo" becomes168 // "ssh://git@github.com/user/repo".169 repoURL = &url.URL{170 Scheme: "ssh",171 User: url.User(m[1]),172 Host: m[2],173 Path: m[3],174 }175 } else {176 repoURL, err = url.Parse(out)177 if err != nil {178 return "", err179 }180 }181 // Iterate over insecure schemes too, because this function simply182 // reports the state of the repo. If we can't see insecure schemes then183 // we can't report the actual repo URL.184 for _, s := range vcsGit.scheme {185 if repoURL.Scheme == s {186 return repoURL.String(), nil187 }188 }189 return "", errParse190}191// vcsBzr describes how to use Bazaar.192var vcsBzr = &vcsCmd{193 name: "Bazaar",194 cmd: "bzr",195 createCmd: []string{"branch {repo} {dir}"},196 // Without --overwrite bzr will not pull tags that changed.197 // Replace by --overwrite-tags after http://pad.lv/681792 goes in.198 downloadCmd: []string{"pull --overwrite"},199 tagCmd: []tagCmd{{"tags", `^(\S+)`}},200 tagSyncCmd: []string{"update -r {tag}"},201 tagSyncDefault: []string{"update -r revno:-1"},202 scheme: []string{"https", "http", "bzr", "bzr+ssh"},203 pingCmd: "info {scheme}://{repo}",204 remoteRepo: bzrRemoteRepo,205 resolveRepo: bzrResolveRepo,206}207func bzrRemoteRepo(vcsBzr *vcsCmd, rootDir string) (remoteRepo string, err error) {208 outb, err := vcsBzr.runOutput(rootDir, "config parent_location")209 if err != nil {210 return "", err211 }212 return strings.TrimSpace(string(outb)), nil213}214func bzrResolveRepo(vcsBzr *vcsCmd, rootDir, remoteRepo string) (realRepo string, err error) {215 outb, err := vcsBzr.runOutput(rootDir, "info "+remoteRepo)216 if err != nil {217 return "", err218 }219 out := string(outb)220 // Expect:221 // ...222 // (branch root|repository branch): <URL>223 // ...224 found := false225 for _, prefix := range []string{"\n branch root: ", "\n repository branch: "} {226 i := strings.Index(out, prefix)227 if i >= 0 {228 out = out[i+len(prefix):]229 found = true230 break231 }232 }233 if !found {234 return "", fmt.Errorf("unable to parse output of bzr info")235 }236 i := strings.Index(out, "\n")237 if i < 0 {238 return "", fmt.Errorf("unable to parse output of bzr info")239 }240 out = out[:i]241 return strings.TrimSpace(out), nil242}243// vcsSvn describes how to use Subversion.244var vcsSvn = &vcsCmd{245 name: "Subversion",246 cmd: "svn",247 createCmd: []string{"checkout {repo} {dir}"},248 downloadCmd: []string{"update"},249 // There is no tag command in subversion.250 // The branch information is all in the path names.251 scheme: []string{"https", "http", "svn", "svn+ssh"},252 pingCmd: "info {scheme}://{repo}",253 remoteRepo: svnRemoteRepo,254}255func svnRemoteRepo(vcsSvn *vcsCmd, rootDir string) (remoteRepo string, err error) {256 outb, err := vcsSvn.runOutput(rootDir, "info")257 if err != nil {258 return "", err259 }260 out := string(outb)261 // Expect:262 //263 // ...264 // URL: <URL>265 // ...266 //267 // Note that we're not using the Repository Root line,268 // because svn allows checking out subtrees.269 // The URL will be the URL of the subtree (what we used with 'svn co')270 // while the Repository Root may be a much higher parent.271 i := strings.Index(out, "\nURL: ")272 if i < 0 {273 return "", fmt.Errorf("unable to parse output of svn info")274 }275 out = out[i+len("\nURL: "):]276 i = strings.Index(out, "\n")277 if i < 0 {278 return "", fmt.Errorf("unable to parse output of svn info")279 }280 out = out[:i]281 return strings.TrimSpace(out), nil282}283// fossilRepoName is the name go get associates with a fossil repository. In the284// real world the file can be named anything.285const fossilRepoName = ".fossil"286// vcsFossil describes how to use Fossil (fossil-scm.org)287var vcsFossil = &vcsCmd{288 name: "Fossil",289 cmd: "fossil",290 createCmd: []string{"-go-internal-mkdir {dir} clone {repo} " + filepath.Join("{dir}", fossilRepoName), "-go-internal-cd {dir} open .fossil"},291 downloadCmd: []string{"up"},292 tagCmd: []tagCmd{{"tag ls", `(.*)`}},293 tagSyncCmd: []string{"up tag:{tag}"},294 tagSyncDefault: []string{"up trunk"},295 scheme: []string{"https", "http"},296 remoteRepo: fossilRemoteRepo,297}298func fossilRemoteRepo(vcsFossil *vcsCmd, rootDir string) (remoteRepo string, err error) {299 out, err := vcsFossil.runOutput(rootDir, "remote-url")300 if err != nil {301 return "", err302 }303 return strings.TrimSpace(string(out)), nil304}305func (v *vcsCmd) String() string {306 return v.name307}308// run runs the command line cmd in the given directory.309// keyval is a list of key, value pairs. run expands310// instances of {key} in cmd into value, but only after311// splitting cmd into individual arguments.312// If an error occurs, run prints the command line and the313// command's combined stdout+stderr to standard error.314// Otherwise run discards the command's output.315func (v *vcsCmd) run(dir string, cmd string, keyval ...string) error {316 _, err := v.run1(dir, cmd, keyval, true)317 return err318}319// runVerboseOnly is like run but only generates error output to standard error in verbose mode.320func (v *vcsCmd) runVerboseOnly(dir string, cmd string, keyval ...string) error {321 _, err := v.run1(dir, cmd, keyval, false)322 return err323}324// runOutput is like run but returns the output of the command.325func (v *vcsCmd) runOutput(dir string, cmd string, keyval ...string) ([]byte, error) {326 return v.run1(dir, cmd, keyval, true)327}328// run1 is the generalized implementation of run and runOutput.329func (v *vcsCmd) run1(dir string, cmdline string, keyval []string, verbose bool) ([]byte, error) {330 m := make(map[string]string)331 for i := 0; i < len(keyval); i += 2 {332 m[keyval[i]] = keyval[i+1]333 }334 args := strings.Fields(cmdline)335 for i, arg := range args {336 args[i] = expand(m, arg)337 }338 if len(args) >= 2 && args[0] == "-go-internal-mkdir" {339 var err error340 if filepath.IsAbs(args[1]) {341 err = os.Mkdir(args[1], os.ModePerm)342 } else {343 err = os.Mkdir(filepath.Join(dir, args[1]), os.ModePerm)344 }345 if err != nil {346 return nil, err347 }348 args = args[2:]349 }350 if len(args) >= 2 && args[0] == "-go-internal-cd" {351 if filepath.IsAbs(args[1]) {352 dir = args[1]353 } else {354 dir = filepath.Join(dir, args[1])355 }356 args = args[2:]357 }358 _, err := exec.LookPath(v.cmd)359 if err != nil {360 fmt.Fprintf(os.Stderr,361 "go: missing %s command. See https://golang.org/s/gogetcmd\n",362 v.name)363 return nil, err364 }365 cmd := exec.Command(v.cmd, args...)366 cmd.Dir = dir367 cmd.Env = base.EnvForDir(cmd.Dir, os.Environ())368 if cfg.BuildX {369 fmt.Fprintf(os.Stderr, "cd %s\n", dir)370 fmt.Fprintf(os.Stderr, "%s %s\n", v.cmd, strings.Join(args, " "))371 }372 out, err := cmd.Output()373 if err != nil {374 if verbose || cfg.BuildV {375 fmt.Fprintf(os.Stderr, "# cd %s; %s %s\n", dir, v.cmd, strings.Join(args, " "))376 if ee, ok := err.(*exec.ExitError); ok && len(ee.Stderr) > 0 {377 os.Stderr.Write(ee.Stderr)378 } else {379 fmt.Fprintf(os.Stderr, err.Error())380 }381 }382 }383 return out, err384}385// ping pings to determine scheme to use.386func (v *vcsCmd) ping(scheme, repo string) error {387 return v.runVerboseOnly(".", v.pingCmd, "scheme", scheme, "repo", repo)388}389// create creates a new copy of repo in dir.390// The parent of dir must exist; dir must not.391func (v *vcsCmd) create(dir, repo string) error {392 for _, cmd := range v.createCmd {393 if err := v.run(".", cmd, "dir", dir, "repo", repo); err != nil {394 return err395 }396 }397 return nil398}399// download downloads any new changes for the repo in dir.400func (v *vcsCmd) download(dir string) error {401 for _, cmd := range v.downloadCmd {402 if err := v.run(dir, cmd); err != nil {403 return err404 }405 }406 return nil407}408// tags returns the list of available tags for the repo in dir.409func (v *vcsCmd) tags(dir string) ([]string, error) {410 var tags []string411 for _, tc := range v.tagCmd {412 out, err := v.runOutput(dir, tc.cmd)413 if err != nil {414 return nil, err415 }416 re := regexp.MustCompile(`(?m-s)` + tc.pattern)417 for _, m := range re.FindAllStringSubmatch(string(out), -1) {418 tags = append(tags, m[1])419 }420 }421 return tags, nil422}423// tagSync syncs the repo in dir to the named tag,424// which either is a tag returned by tags or is v.tagDefault.425func (v *vcsCmd) tagSync(dir, tag string) error {426 if v.tagSyncCmd == nil {427 return nil428 }429 if tag != "" {430 for _, tc := range v.tagLookupCmd {431 out, err := v.runOutput(dir, tc.cmd, "tag", tag)432 if err != nil {433 return err434 }435 re := regexp.MustCompile(`(?m-s)` + tc.pattern)436 m := re.FindStringSubmatch(string(out))437 if len(m) > 1 {438 tag = m[1]439 break440 }441 }442 }443 if tag == "" && v.tagSyncDefault != nil {444 for _, cmd := range v.tagSyncDefault {445 if err := v.run(dir, cmd); err != nil {446 return err447 }448 }449 return nil450 }451 for _, cmd := range v.tagSyncCmd {452 if err := v.run(dir, cmd, "tag", tag); err != nil {453 return err454 }455 }456 return nil457}458// A vcsPath describes how to convert an import path into a459// version control system and repository name.460type vcsPath struct {461 prefix string // prefix this description applies to462 re string // pattern for import path463 repo string // repository to use (expand with match of re)464 vcs string // version control system to use (expand with match of re)465 check func(match map[string]string) error // additional checks466 ping bool // ping for scheme to use to download repo467 regexp *regexp.Regexp // cached compiled form of re468}469// vcsFromDir inspects dir and its parents to determine the470// version control system and code repository to use.471// On return, root is the import path472// corresponding to the root of the repository.473func vcsFromDir(dir, srcRoot string) (vcs *vcsCmd, root string, err error) {474 // Clean and double-check that dir is in (a subdirectory of) srcRoot.475 dir = filepath.Clean(dir)476 srcRoot = filepath.Clean(srcRoot)477 if len(dir) <= len(srcRoot) || dir[len(srcRoot)] != filepath.Separator {478 return nil, "", fmt.Errorf("directory %q is outside source root %q", dir, srcRoot)479 }480 var vcsRet *vcsCmd481 var rootRet string482 origDir := dir483 for len(dir) > len(srcRoot) {484 for _, vcs := range vcsList {485 if _, err := os.Stat(filepath.Join(dir, "."+vcs.cmd)); err == nil {486 root := filepath.ToSlash(dir[len(srcRoot)+1:])487 // Record first VCS we find, but keep looking,488 // to detect mistakes like one kind of VCS inside another.489 if vcsRet == nil {490 vcsRet = vcs491 rootRet = root492 continue493 }494 // Allow .git inside .git, which can arise due to submodules.495 if vcsRet == vcs && vcs.cmd == "git" {496 continue497 }498 // Otherwise, we have one VCS inside a different VCS.499 return nil, "", fmt.Errorf("directory %q uses %s, but parent %q uses %s",500 filepath.Join(srcRoot, rootRet), vcsRet.cmd, filepath.Join(srcRoot, root), vcs.cmd)501 }502 }503 // Move to parent.504 ndir := filepath.Dir(dir)505 if len(ndir) >= len(dir) {506 // Shouldn't happen, but just in case, stop.507 break508 }509 dir = ndir510 }511 if vcsRet != nil {512 return vcsRet, rootRet, nil513 }514 return nil, "", fmt.Errorf("directory %q is not using a known version control system", origDir)515}516// checkNestedVCS checks for an incorrectly-nested VCS-inside-VCS517// situation for dir, checking parents up until srcRoot.518func checkNestedVCS(vcs *vcsCmd, dir, srcRoot string) error {519 if len(dir) <= len(srcRoot) || dir[len(srcRoot)] != filepath.Separator {520 return fmt.Errorf("directory %q is outside source root %q", dir, srcRoot)521 }522 otherDir := dir523 for len(otherDir) > len(srcRoot) {524 for _, otherVCS := range vcsList {525 if _, err := os.Stat(filepath.Join(otherDir, "."+otherVCS.cmd)); err == nil {526 // Allow expected vcs in original dir.527 if otherDir == dir && otherVCS == vcs {528 continue529 }530 // Allow .git inside .git, which can arise due to submodules.531 if otherVCS == vcs && vcs.cmd == "git" {532 continue533 }534 // Otherwise, we have one VCS inside a different VCS.535 return fmt.Errorf("directory %q uses %s, but parent %q uses %s", dir, vcs.cmd, otherDir, otherVCS.cmd)536 }537 }538 // Move to parent.539 newDir := filepath.Dir(otherDir)540 if len(newDir) >= len(otherDir) {541 // Shouldn't happen, but just in case, stop.542 break543 }544 otherDir = newDir545 }546 return nil547}548// RepoRoot describes the repository root for a tree of source code.549type RepoRoot struct {550 Repo string // repository URL, including scheme551 Root string // import path corresponding to root of repo552 IsCustom bool // defined by served <meta> tags (as opposed to hard-coded pattern)553 VCS string // vcs type ("mod", "git", ...)554 vcs *vcsCmd // internal: vcs command access555}556var httpPrefixRE = regexp.MustCompile(`^https?:`)557// ModuleMode specifies whether to prefer modules when looking up code sources.558type ModuleMode int559const (560 IgnoreMod ModuleMode = iota561 PreferMod562)563// RepoRootForImportPath analyzes importPath to determine the564// version control system, and code repository to use.565func RepoRootForImportPath(importPath string, mod ModuleMode, security web.SecurityMode) (*RepoRoot, error) {566 rr, err := repoRootFromVCSPaths(importPath, "", security, vcsPaths)567 if err == errUnknownSite {568 rr, err = repoRootForImportDynamic(importPath, mod, security)569 if err != nil {570 err = fmt.Errorf("unrecognized import path %q (%v)", importPath, err)571 }572 }573 if err != nil {574 rr1, err1 := repoRootFromVCSPaths(importPath, "", security, vcsPathsAfterDynamic)575 if err1 == nil {576 rr = rr1577 err = nil578 }579 }580 // Should have been taken care of above, but make sure.581 if err == nil && strings.Contains(importPath, "...") && strings.Contains(rr.Root, "...") {582 // Do not allow wildcards in the repo root.583 rr = nil584 err = fmt.Errorf("cannot expand ... in %q", importPath)585 }586 return rr, err587}588var errUnknownSite = errors.New("dynamic lookup required to find mapping")589// repoRootFromVCSPaths attempts to map importPath to a repoRoot590// using the mappings defined in vcsPaths.591// If scheme is non-empty, that scheme is forced.592func repoRootFromVCSPaths(importPath, scheme string, security web.SecurityMode, vcsPaths []*vcsPath) (*RepoRoot, error) {593 // A common error is to use https://packagepath because that's what594 // hg and git require. Diagnose this helpfully.595 if loc := httpPrefixRE.FindStringIndex(importPath); loc != nil {596 // The importPath has been cleaned, so has only one slash. The pattern597 // ignores the slashes; the error message puts them back on the RHS at least.598 return nil, fmt.Errorf("%q not allowed in import path", importPath[loc[0]:loc[1]]+"//")599 }600 for _, srv := range vcsPaths {601 if !strings.HasPrefix(importPath, srv.prefix) {602 continue603 }604 m := srv.regexp.FindStringSubmatch(importPath)605 if m == nil {606 if srv.prefix != "" {607 return nil, fmt.Errorf("invalid %s import path %q", srv.prefix, importPath)608 }609 continue610 }611 // Build map of named subexpression matches for expand.612 match := map[string]string{613 "prefix": srv.prefix,614 "import": importPath,615 }616 for i, name := range srv.regexp.SubexpNames() {617 if name != "" && match[name] == "" {618 match[name] = m[i]619 }620 }621 if srv.vcs != "" {622 match["vcs"] = expand(match, srv.vcs)623 }624 if srv.repo != "" {625 match["repo"] = expand(match, srv.repo)626 }627 if srv.check != nil {628 if err := srv.check(match); err != nil {629 return nil, err630 }631 }632 vcs := vcsByCmd(match["vcs"])633 if vcs == nil {634 return nil, fmt.Errorf("unknown version control system %q", match["vcs"])635 }636 if srv.ping {637 if scheme != "" {638 match["repo"] = scheme + "://" + match["repo"]639 } else {640 for _, scheme := range vcs.scheme {641 if security == web.Secure && !vcs.isSecureScheme(scheme) {642 continue643 }644 if vcs.pingCmd != "" && vcs.ping(scheme, match["repo"]) == nil {645 match["repo"] = scheme + "://" + match["repo"]646 goto Found647 }648 }649 // No scheme found. Fall back to the first one.650 match["repo"] = vcs.scheme[0] + "://" + match["repo"]651 Found:652 }653 }654 rr := &RepoRoot{655 Repo: match["repo"],656 Root: match["root"],657 VCS: vcs.cmd,658 vcs: vcs,659 }660 return rr, nil661 }662 return nil, errUnknownSite663}664// repoRootForImportDynamic finds a *RepoRoot for a custom domain that's not665// statically known by repoRootForImportPathStatic.666//667// This handles custom import paths like "name.tld/pkg/foo" or just "name.tld".668func repoRootForImportDynamic(importPath string, mod ModuleMode, security web.SecurityMode) (*RepoRoot, error) {669 slash := strings.Index(importPath, "/")670 if slash < 0 {671 slash = len(importPath)672 }673 host := importPath[:slash]674 if !strings.Contains(host, ".") {675 return nil, errors.New("import path does not begin with hostname")676 }677 urlStr, body, err := web.GetMaybeInsecure(importPath, security)678 if err != nil {679 msg := "https fetch: %v"680 if security == web.Insecure {681 msg = "http/" + msg682 }683 return nil, fmt.Errorf(msg, err)684 }685 defer body.Close()686 imports, err := parseMetaGoImports(body, mod)687 if err != nil {688 return nil, fmt.Errorf("parsing %s: %v", importPath, err)689 }690 // Find the matched meta import.691 mmi, err := matchGoImport(imports, importPath)692 if err != nil {693 if _, ok := err.(ImportMismatchError); !ok {694 return nil, fmt.Errorf("parse %s: %v", urlStr, err)695 }696 return nil, fmt.Errorf("parse %s: no go-import meta tags (%s)", urlStr, err)697 }698 if cfg.BuildV {699 log.Printf("get %q: found meta tag %#v at %s", importPath, mmi, urlStr)700 }701 // If the import was "uni.edu/bob/project", which said the702 // prefix was "uni.edu" and the RepoRoot was "evilroot.com",703 // make sure we don't trust Bob and check out evilroot.com to704 // "uni.edu" yet (possibly overwriting/preempting another705 // non-evil student). Instead, first verify the root and see706 // if it matches Bob's claim.707 if mmi.Prefix != importPath {708 if cfg.BuildV {709 log.Printf("get %q: verifying non-authoritative meta tag", importPath)710 }711 urlStr0 := urlStr712 var imports []metaImport713 urlStr, imports, err = metaImportsForPrefix(mmi.Prefix, mod, security)714 if err != nil {715 return nil, err716 }717 metaImport2, err := matchGoImport(imports, importPath)718 if err != nil || mmi != metaImport2 {719 return nil, fmt.Errorf("%s and %s disagree about go-import for %s", urlStr0, urlStr, mmi.Prefix)720 }721 }722 if err := validateRepoRoot(mmi.RepoRoot); err != nil {723 return nil, fmt.Errorf("%s: invalid repo root %q: %v", urlStr, mmi.RepoRoot, err)724 }725 vcs := vcsByCmd(mmi.VCS)726 if vcs == nil && mmi.VCS != "mod" {727 return nil, fmt.Errorf("%s: unknown vcs %q", urlStr, mmi.VCS)728 }729 rr := &RepoRoot{730 Repo: mmi.RepoRoot,731 Root: mmi.Prefix,732 IsCustom: true,733 VCS: mmi.VCS,734 vcs: vcs,735 }736 return rr, nil737}738// validateRepoRoot returns an error if repoRoot does not seem to be739// a valid URL with scheme.740func validateRepoRoot(repoRoot string) error {741 url, err := url.Parse(repoRoot)742 if err != nil {743 return err744 }745 if url.Scheme == "" {746 return errors.New("no scheme")747 }748 return nil749}750var fetchGroup singleflight.Group751var (752 fetchCacheMu sync.Mutex753 fetchCache = map[string]fetchResult{} // key is metaImportsForPrefix's importPrefix754)755// metaImportsForPrefix takes a package's root import path as declared in a <meta> tag756// and returns its HTML discovery URL and the parsed metaImport lines757// found on the page.758//759// The importPath is of the form "golang.org/x/tools".760// It is an error if no imports are found.761// urlStr will still be valid if err != nil.762// The returned urlStr will be of the form "https://golang.org/x/tools?go-get=1"763func metaImportsForPrefix(importPrefix string, mod ModuleMode, security web.SecurityMode) (urlStr string, imports []metaImport, err error) {764 setCache := func(res fetchResult) (fetchResult, error) {765 fetchCacheMu.Lock()766 defer fetchCacheMu.Unlock()767 fetchCache[importPrefix] = res768 return res, nil769 }770 resi, _, _ := fetchGroup.Do(importPrefix, func() (resi interface{}, err error) {771 fetchCacheMu.Lock()772 if res, ok := fetchCache[importPrefix]; ok {773 fetchCacheMu.Unlock()774 return res, nil775 }776 fetchCacheMu.Unlock()777 urlStr, body, err := web.GetMaybeInsecure(importPrefix, security)778 if err != nil {779 return setCache(fetchResult{urlStr: urlStr, err: fmt.Errorf("fetch %s: %v", urlStr, err)})780 }781 imports, err := parseMetaGoImports(body, mod)782 if err != nil {783 return setCache(fetchResult{urlStr: urlStr, err: fmt.Errorf("parsing %s: %v", urlStr, err)})784 }785 if len(imports) == 0 {786 err = fmt.Errorf("fetch %s: no go-import meta tag", urlStr)787 }788 return setCache(fetchResult{urlStr: urlStr, imports: imports, err: err})789 })790 res := resi.(fetchResult)791 return res.urlStr, res.imports, res.err792}793type fetchResult struct {794 urlStr string // e.g. "https://foo.com/x/bar?go-get=1"795 imports []metaImport796 err error797}798// metaImport represents the parsed <meta name="go-import"799// content="prefix vcs reporoot" /> tags from HTML files.800type metaImport struct {801 Prefix, VCS, RepoRoot string802}803// pathPrefix reports whether sub is a prefix of s,804// only considering entire path components.805func pathPrefix(s, sub string) bool {806 // strings.HasPrefix is necessary but not sufficient.807 if !strings.HasPrefix(s, sub) {808 return false809 }810 // The remainder after the prefix must either be empty or start with a slash.811 rem := s[len(sub):]812 return rem == "" || rem[0] == '/'813}814// A ImportMismatchError is returned where metaImport/s are present815// but none match our import path.816type ImportMismatchError struct {817 importPath string818 mismatches []string // the meta imports that were discarded for not matching our importPath819}820func (m ImportMismatchError) Error() string {821 formattedStrings := make([]string, len(m.mismatches))822 for i, pre := range m.mismatches {823 formattedStrings[i] = fmt.Sprintf("meta tag %s did not match import path %s", pre, m.importPath)824 }825 return strings.Join(formattedStrings, ", ")826}827// matchGoImport returns the metaImport from imports matching importPath.828// An error is returned if there are multiple matches.829// errNoMatch is returned if none match.830func matchGoImport(imports []metaImport, importPath string) (metaImport, error) {831 match := -1832 errImportMismatch := ImportMismatchError{importPath: importPath}833 for i, im := range imports {834 if !pathPrefix(importPath, im.Prefix) {835 errImportMismatch.mismatches = append(errImportMismatch.mismatches, im.Prefix)836 continue837 }838 if match >= 0 {839 if imports[match].VCS == "mod" && im.VCS != "mod" {...
String
Using AI Code Generation
1import (2func main() {3 golenv.Load()4 vcs_obj := vcs.VCS{5 Repo: golstring.Env("GOPATH", "/src/github.com/abhishekkr/gol/vcs"),6 }7 fmt.Println(vcs_obj.String())8}
String
Using AI Code Generation
1import (2func main() {3 fmt.Println(vcs.String())4}5import (6func String() string {7}
String
Using AI Code Generation
1import (2func main() {3 fmt.Println(v)4}5import (6func main() {7 fmt.Printf("%+v", v)8}
Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!