mirror of
https://github.com/grdl/git-get.git
synced 2026-02-09 00:29:17 +00:00
Make the URL scheme default to ssh instead of https and make it configurable
This commit is contained in:
@@ -27,6 +27,7 @@ var cmd = &cobra.Command{
|
|||||||
func init() {
|
func init() {
|
||||||
cmd.PersistentFlags().StringP(cfg.KeyBranch, "b", "", "Branch (or tag) to checkout after cloning.")
|
cmd.PersistentFlags().StringP(cfg.KeyBranch, "b", "", "Branch (or tag) to checkout after cloning.")
|
||||||
cmd.PersistentFlags().StringP(cfg.KeyDefaultHost, "t", cfg.Defaults[cfg.KeyDefaultHost], "Host to use when <REPO> doesn't have a specified host.")
|
cmd.PersistentFlags().StringP(cfg.KeyDefaultHost, "t", cfg.Defaults[cfg.KeyDefaultHost], "Host to use when <REPO> doesn't have a specified host.")
|
||||||
|
cmd.PersistentFlags().StringP(cfg.KeyDefaultScheme, "c", cfg.Defaults[cfg.KeyDefaultScheme], "Scheme to use when <REPO> doesn't have a specified scheme.")
|
||||||
cmd.PersistentFlags().StringP(cfg.KeyDump, "d", "", "Path to a dump file listing repos to clone. Ignored when <REPO> argument is used.")
|
cmd.PersistentFlags().StringP(cfg.KeyDump, "d", "", "Path to a dump file listing repos to clone. Ignored when <REPO> argument is used.")
|
||||||
cmd.PersistentFlags().BoolP(cfg.KeySkipHost, "s", false, "Don't create a directory for host.")
|
cmd.PersistentFlags().BoolP(cfg.KeySkipHost, "s", false, "Don't create a directory for host.")
|
||||||
cmd.PersistentFlags().StringP(cfg.KeyReposRoot, "r", cfg.Defaults[cfg.KeyReposRoot], "Path to repos root where repositories are cloned.")
|
cmd.PersistentFlags().StringP(cfg.KeyReposRoot, "r", cfg.Defaults[cfg.KeyReposRoot], "Path to repos root where repositories are cloned.")
|
||||||
@@ -35,6 +36,7 @@ func init() {
|
|||||||
|
|
||||||
viper.BindPFlag(cfg.KeyBranch, cmd.PersistentFlags().Lookup(cfg.KeyBranch))
|
viper.BindPFlag(cfg.KeyBranch, cmd.PersistentFlags().Lookup(cfg.KeyBranch))
|
||||||
viper.BindPFlag(cfg.KeyDefaultHost, cmd.PersistentFlags().Lookup(cfg.KeyDefaultHost))
|
viper.BindPFlag(cfg.KeyDefaultHost, cmd.PersistentFlags().Lookup(cfg.KeyDefaultHost))
|
||||||
|
viper.BindPFlag(cfg.KeyDefaultScheme, cmd.PersistentFlags().Lookup(cfg.KeyDefaultScheme))
|
||||||
viper.BindPFlag(cfg.KeyDump, cmd.PersistentFlags().Lookup(cfg.KeyDump))
|
viper.BindPFlag(cfg.KeyDump, cmd.PersistentFlags().Lookup(cfg.KeyDump))
|
||||||
viper.BindPFlag(cfg.KeyReposRoot, cmd.PersistentFlags().Lookup(cfg.KeyReposRoot))
|
viper.BindPFlag(cfg.KeyReposRoot, cmd.PersistentFlags().Lookup(cfg.KeyReposRoot))
|
||||||
viper.BindPFlag(cfg.KeySkipHost, cmd.PersistentFlags().Lookup(cfg.KeySkipHost))
|
viper.BindPFlag(cfg.KeySkipHost, cmd.PersistentFlags().Lookup(cfg.KeySkipHost))
|
||||||
@@ -51,12 +53,13 @@ func run(cmd *cobra.Command, args []string) error {
|
|||||||
cfg.Expand(cfg.KeyReposRoot)
|
cfg.Expand(cfg.KeyReposRoot)
|
||||||
|
|
||||||
config := &pkg.GetCfg{
|
config := &pkg.GetCfg{
|
||||||
Branch: viper.GetString(cfg.KeyBranch),
|
Branch: viper.GetString(cfg.KeyBranch),
|
||||||
DefHost: viper.GetString(cfg.KeyDefaultHost),
|
DefHost: viper.GetString(cfg.KeyDefaultHost),
|
||||||
Dump: viper.GetString(cfg.KeyDump),
|
DefScheme: viper.GetString(cfg.KeyDefaultScheme),
|
||||||
SkipHost: viper.GetBool(cfg.KeySkipHost),
|
Dump: viper.GetString(cfg.KeyDump),
|
||||||
Root: viper.GetString(cfg.KeyReposRoot),
|
SkipHost: viper.GetBool(cfg.KeySkipHost),
|
||||||
URL: url,
|
Root: viper.GetString(cfg.KeyReposRoot),
|
||||||
|
URL: url,
|
||||||
}
|
}
|
||||||
return pkg.Get(config)
|
return pkg.Get(config)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,21 +17,22 @@ const GitgetPrefix = "gitget"
|
|||||||
|
|
||||||
// CLI flag keys.
|
// CLI flag keys.
|
||||||
var (
|
var (
|
||||||
KeyBranch = "branch"
|
KeyBranch = "branch"
|
||||||
KeyDump = "dump"
|
KeyDump = "dump"
|
||||||
KeyDefaultHost = "host"
|
KeyDefaultHost = "host"
|
||||||
KeyFetch = "fetch"
|
KeyFetch = "fetch"
|
||||||
KeyOutput = "out"
|
KeyOutput = "out"
|
||||||
KeySkipHost = "skip-host"
|
KeyDefaultScheme = "scheme"
|
||||||
KeyReposRoot = "root"
|
KeySkipHost = "skip-host"
|
||||||
|
KeyReposRoot = "root"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Defaults is a map of default values for config keys.
|
// Defaults is a map of default values for config keys.
|
||||||
var Defaults = map[string]string{
|
var Defaults = map[string]string{
|
||||||
KeyDefaultHost: "github.com",
|
KeyDefaultHost: "github.com",
|
||||||
KeyOutput: OutTree,
|
KeyOutput: OutTree,
|
||||||
KeyReposRoot: fmt.Sprintf("~%c%s", filepath.Separator, "repositories"),
|
KeyReposRoot: fmt.Sprintf("~%c%s", filepath.Separator, "repositories"),
|
||||||
// KeySkipHost: "false",
|
KeyDefaultScheme: "ssh",
|
||||||
}
|
}
|
||||||
|
|
||||||
// Values for the --out flag.
|
// Values for the --out flag.
|
||||||
|
|||||||
17
pkg/get.go
17
pkg/get.go
@@ -8,12 +8,13 @@ import (
|
|||||||
|
|
||||||
// GetCfg provides configuration for the Get command.
|
// GetCfg provides configuration for the Get command.
|
||||||
type GetCfg struct {
|
type GetCfg struct {
|
||||||
Branch string
|
Branch string
|
||||||
DefHost string
|
DefHost string
|
||||||
Dump string
|
DefScheme string
|
||||||
Root string
|
Dump string
|
||||||
SkipHost bool
|
Root string
|
||||||
URL string
|
SkipHost bool
|
||||||
|
URL string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get executes the "git get" command.
|
// Get executes the "git get" command.
|
||||||
@@ -33,7 +34,7 @@ func Get(c *GetCfg) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func cloneSingleRepo(c *GetCfg) error {
|
func cloneSingleRepo(c *GetCfg) error {
|
||||||
url, err := ParseURL(c.URL, c.DefHost)
|
url, err := ParseURL(c.URL, c.DefHost, c.DefScheme)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -56,7 +57,7 @@ func cloneDumpFile(c *GetCfg) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, line := range parsedLines {
|
for _, line := range parsedLines {
|
||||||
url, err := ParseURL(line.rawurl, c.DefHost)
|
url, err := ParseURL(line.rawurl, c.DefHost, c.DefScheme)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
29
pkg/url.go
29
pkg/url.go
@@ -17,8 +17,9 @@ var errEmptyURLPath = errors.New("parsed URL path is empty")
|
|||||||
var scpSyntax = regexp.MustCompile(`^([a-zA-Z0-9_]+)@([a-zA-Z0-9._-]+):(.*)$`)
|
var scpSyntax = regexp.MustCompile(`^([a-zA-Z0-9_]+)@([a-zA-Z0-9._-]+):(.*)$`)
|
||||||
|
|
||||||
// ParseURL parses given rawURL string into a URL.
|
// ParseURL parses given rawURL string into a URL.
|
||||||
// The defaultHost argument defines the host to use (eg, github.com) in case parsed URL has an empty host.
|
// When the parsed URL has an empty host, use the defaultHost.
|
||||||
func ParseURL(rawURL string, defaultHost string) (url *urlpkg.URL, err error) {
|
// When the parsed URL has an empty scheme, use the defaultScheme.
|
||||||
|
func ParseURL(rawURL string, defaultHost string, defaultScheme string) (url *urlpkg.URL, err error) {
|
||||||
// If rawURL matches the SCP-like syntax, convert it into a standard ssh Path.
|
// If rawURL matches the SCP-like syntax, convert it into a standard ssh Path.
|
||||||
// eg, git@github.com:user/repo => ssh://git@github.com/user/repo
|
// eg, git@github.com:user/repo => ssh://git@github.com/user/repo
|
||||||
if m := scpSyntax.FindStringSubmatch(rawURL); m != nil {
|
if m := scpSyntax.FindStringSubmatch(rawURL); m != nil {
|
||||||
@@ -26,7 +27,7 @@ func ParseURL(rawURL string, defaultHost string) (url *urlpkg.URL, err error) {
|
|||||||
Scheme: "ssh",
|
Scheme: "ssh",
|
||||||
User: urlpkg.User(m[1]),
|
User: urlpkg.User(m[1]),
|
||||||
Host: m[2],
|
Host: m[2],
|
||||||
Path: m[3],
|
Path: path.Join("/", m[3]),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
url, err = urlpkg.Parse(rawURL)
|
url, err = urlpkg.Parse(rawURL)
|
||||||
@@ -43,14 +44,21 @@ func ParseURL(rawURL string, defaultHost string) (url *urlpkg.URL, err error) {
|
|||||||
url.Scheme = "ssh"
|
url.Scheme = "ssh"
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default to "git" user when using ssh and no user is provided
|
|
||||||
if url.Scheme == "ssh" && url.User == nil {
|
|
||||||
url.User = urlpkg.User("git")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Default to configured defaultHost when host is empty
|
// Default to configured defaultHost when host is empty
|
||||||
if url.Host == "" {
|
if url.Host == "" {
|
||||||
url.Host = defaultHost
|
url.Host = defaultHost
|
||||||
|
// Add a leading slash to path when host is missing. It's needed to correctly compare urlpkg.URL structs.
|
||||||
|
url.Path = path.Join("/", url.Path)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default to configured defaultScheme when scheme is empty
|
||||||
|
if url.Scheme == "" {
|
||||||
|
url.Scheme = defaultScheme
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default to "git" user when using ssh and no user is provided
|
||||||
|
if url.Scheme == "ssh" && url.User == nil {
|
||||||
|
url.User = urlpkg.User("git")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't use host when scheme is file://. The fragment detected as url.Host should be a first directory of url.Path
|
// Don't use host when scheme is file://. The fragment detected as url.Host should be a first directory of url.Path
|
||||||
@@ -59,11 +67,6 @@ func ParseURL(rawURL string, defaultHost string) (url *urlpkg.URL, err error) {
|
|||||||
url.Host = ""
|
url.Host = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default to https when scheme is empty
|
|
||||||
if url.Scheme == "" {
|
|
||||||
url.Scheme = "https"
|
|
||||||
}
|
|
||||||
|
|
||||||
return url, nil
|
return url, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ package pkg
|
|||||||
import (
|
import (
|
||||||
"git-get/pkg/cfg"
|
"git-get/pkg/cfg"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Following URLs are considered valid according to https://git-scm.com/docs/git-clone#_git_urls:
|
// Following URLs are considered valid according to https://git-scm.com/docs/git-clone#_git_urls:
|
||||||
@@ -50,16 +52,11 @@ func TestURLParse(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
url, err := ParseURL(test.in, cfg.Defaults[cfg.KeyDefaultHost])
|
url, err := ParseURL(test.in, cfg.Defaults[cfg.KeyDefaultHost], cfg.Defaults[cfg.KeyDefaultScheme])
|
||||||
if err != nil {
|
assert.NoError(t, err)
|
||||||
t.Fatalf("got error: %+v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
got := URLToPath(*url, false)
|
got := URLToPath(*url, false)
|
||||||
|
assert.Equal(t, test.want, got)
|
||||||
if got != test.want {
|
|
||||||
t.Errorf("wrong result for %q; expected %q; got %q", test.in, test.want, got)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func TestURLParseSkipHost(t *testing.T) {
|
func TestURLParseSkipHost(t *testing.T) {
|
||||||
@@ -95,16 +92,39 @@ func TestURLParseSkipHost(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
url, err := ParseURL(test.in, cfg.Defaults[cfg.KeyDefaultHost])
|
url, err := ParseURL(test.in, cfg.Defaults[cfg.KeyDefaultHost], cfg.Defaults[cfg.KeyDefaultScheme])
|
||||||
if err != nil {
|
assert.NoError(t, err)
|
||||||
t.Fatalf("got error: %+v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
got := URLToPath(*url, true)
|
got := URLToPath(*url, true)
|
||||||
|
assert.Equal(t, test.want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if got != test.want {
|
func TestDefaultScheme(t *testing.T) {
|
||||||
t.Errorf("wrong result for %q; expected %q; got %q", test.in, test.want, got)
|
tests := []struct {
|
||||||
}
|
in string
|
||||||
|
scheme string
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{"grdl/git-get", "ssh", "ssh://git@github.com/grdl/git-get"},
|
||||||
|
{"grdl/git-get", "https", "https://github.com/grdl/git-get"},
|
||||||
|
{"https://github.com/grdl/git-get", "ssh", "https://github.com/grdl/git-get"},
|
||||||
|
{"https://github.com/grdl/git-get", "https", "https://github.com/grdl/git-get"},
|
||||||
|
{"ssh://github.com/grdl/git-get", "ssh", "ssh://git@github.com/grdl/git-get"},
|
||||||
|
{"ssh://github.com/grdl/git-get", "https", "ssh://git@github.com/grdl/git-get"},
|
||||||
|
{"git+ssh://github.com/grdl/git-get", "https", "ssh://git@github.com/grdl/git-get"},
|
||||||
|
{"git@github.com:grdl/git-get", "ssh", "ssh://git@github.com/grdl/git-get"},
|
||||||
|
{"git@github.com:grdl/git-get", "https", "ssh://git@github.com/grdl/git-get"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
url, err := ParseURL(test.in, cfg.Defaults[cfg.KeyDefaultHost], test.scheme)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
want, err := url.Parse(test.want)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, url, want)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,9 +139,8 @@ func TestInvalidURLParse(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range invalidURLs {
|
for _, test := range invalidURLs {
|
||||||
got, err := ParseURL(test, cfg.Defaults[cfg.KeyDefaultHost])
|
_, err := ParseURL(test, cfg.Defaults[cfg.KeyDefaultHost], cfg.Defaults[cfg.KeyDefaultScheme])
|
||||||
if err == nil {
|
|
||||||
t.Errorf("expected error; got %q", got)
|
assert.Error(t, err)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user