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  }