github.com/hattya/nazuna@v0.7.1-0.20240331055452-55e14c275c1c/remote.go (about) 1 // 2 // nazuna :: remote.go 3 // 4 // Copyright (c) 2013-2020 Akinori Hattori <hattya@gmail.com> 5 // 6 // SPDX-License-Identifier: MIT 7 // 8 9 package nazuna 10 11 import ( 12 "encoding/json" 13 "errors" 14 "fmt" 15 "regexp" 16 "strings" 17 ) 18 19 var ErrRemote = errors.New("unknown remote") 20 21 type Remote struct { 22 VCS string 23 URI string 24 Root string 25 Path string 26 27 ui UI 28 src string 29 } 30 31 func NewRemote(ui UI, src string) (*Remote, error) { 32 for _, rh := range remoteHandlers { 33 if !strings.HasPrefix(src, rh.Prefix) { 34 continue 35 } 36 m := rh.rx.FindStringSubmatch(src) 37 if m == nil { 38 continue 39 } 40 g := map[string]string{ 41 "vcs": rh.VCS, 42 } 43 for i, n := range rh.rx.SubexpNames() { 44 if n != "" && g[n] == "" { 45 g[n] = m[i] 46 } 47 } 48 g["uri"] = rh.Scheme + "://" + g["root"] 49 if rh.Check != nil { 50 if err := rh.Check(g); err != nil { 51 return nil, err 52 } 53 } 54 r := &Remote{ 55 VCS: g["vcs"], 56 URI: g["uri"], 57 Root: g["root"], 58 Path: g["path"], 59 ui: ui, 60 src: src, 61 } 62 return r, nil 63 } 64 return nil, ErrRemote 65 } 66 67 func (r *Remote) Clone(base, dst string) error { 68 vcs, err := FindVCS(r.ui, r.VCS, base) 69 if err != nil { 70 return fmt.Errorf("cannot detect remote vcs for %v", r.src) 71 } 72 return vcs.Clone(r.URI, dst) 73 } 74 75 func (r *Remote) Update(dir string) error { 76 vcs, err := VCSFor(r.ui, dir) 77 if err != nil { 78 return err 79 } 80 return vcs.Update() 81 } 82 83 type RemoteHandler struct { 84 Prefix string 85 Expr string 86 VCS string 87 Scheme string 88 Check func(map[string]string) error 89 90 rx *regexp.Regexp 91 } 92 93 var remoteHandlers = []*RemoteHandler{ 94 { 95 Prefix: "github.com/", 96 Expr: `^(?P<root>github\.com/[^/]+/[^/]+)(?P<path>.*)$`, 97 VCS: "git", 98 Scheme: "https", 99 }, 100 { 101 Prefix: "bitbucket.org/", 102 Expr: `^(?P<root>bitbucket\.org/(?P<repo>[^/]+/[^/]+))(?P<path>.*)$`, 103 Scheme: "https", 104 Check: bitbucket, 105 }, 106 } 107 108 func init() { 109 for _, r := range remoteHandlers { 110 r.rx = regexp.MustCompile(r.Expr) 111 } 112 } 113 114 func bitbucket(m map[string]string) error { 115 var resp struct { 116 SCM string 117 } 118 uri := "https://api.bitbucket.org/2.0/repositories/" + m["repo"] 119 data, err := httpGet(uri) 120 if err != nil { 121 return err 122 } 123 if err = json.Unmarshal(data, &resp); err != nil { 124 return fmt.Errorf("%v: %v", uri, err) 125 } 126 m["vcs"] = resp.SCM 127 if resp.SCM == "git" { 128 m["uri"] += ".git" 129 } 130 return nil 131 }