Skip to content

Commit

Permalink
feat: parse urls correctly
Browse files Browse the repository at this point in the history
Closed #3, #4
  • Loading branch information
juev committed Apr 22, 2024
1 parent f50571b commit 6322eef
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 124 deletions.
85 changes: 43 additions & 42 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ import (
"errors"
"fmt"
"io"
"net/url"
"os"
"os/exec"
"path/filepath"
"regexp"
"strings"
)

Expand All @@ -19,23 +21,26 @@ var (
func main() {
if len(os.Args) < 2 {
usage()
return
}

var repository string
switch os.Args[1] {
case "-h", "--help", "help":
usage()
return
case "-v", "--version", "version":
fmt.Printf("gclone version %s, commit %s, built at %s\n", version, commit, date)
if commit != "none" {
fmt.Printf("gclone version %s, commit %s, built at %s\n", version, commit, date)
} else {
fmt.Printf("gclone version %s\n", version)
}
return
default:
repository = os.Args[1]
}

if repository == stripPrefixes(repository) {
repository = "https://" + repository
}

_, err := exec.LookPath("git")
if err != nil {
if _, err := exec.LookPath("git"); err != nil {
fatal("git not found")
}

Expand All @@ -59,29 +64,22 @@ func main() {
fmt.Println(projectDir)
}

// parseRepositoryURL get directory from repository URL
// URL can be http and ssh
func parseRepositoryURL(repository string) (dir string) {
dir = stripPrefixes(repository)
dir = strings.TrimSuffix(dir, ".git")
dir = strings.ReplaceAll(dir, "~", "")
dir = strings.Replace(dir, ":", string(os.PathSeparator), 1)

if dir == "" {
usage()
// parse parses the given repository string and returns the parsed repository URL.
//
// It takes a string parameter named repository, which represents the repository to be parsed.
// The function returns a string that represents the parsed repository URL.
func parse(repository string) string {
r := regexp.MustCompile(`^[^@\:\/]+@([^:]+):(.+)`)
if r.MatchString(repository) {
repository = "git://" + strings.ReplaceAll(repository, ":", "/")
}

return dir
}

func stripPrefixes(repository string) string {
prefixes := []string{"git@", "https://", "http://", "ssh://", "git://", "ftp://", "ftps://"}
for _, prefix := range prefixes {
if strings.HasPrefix(repository, prefix) {
return strings.TrimPrefix(repository, prefix)
}
repositoryURL, err := url.Parse(repository)
if err != nil {
fatal("failed parse repository: %w", err)
}
return repository

return repositoryURL.Hostname() + strings.TrimSuffix(strings.TrimSuffix(repositoryURL.Path, ".git"), "/")
}

// getProjectDir return directory from GIT_PROJECT_DIR variable and
Expand All @@ -99,8 +97,8 @@ func getProjectDir(repository string) string {
}

return filepath.Join(
filepath.Clean(gitProjectDir),
filepath.Clean(parseRepositoryURL(repository)),
gitProjectDir,
parse(repository),
)
}

Expand All @@ -120,20 +118,23 @@ func isNotEmpty(name string) bool {
// fatal print to Stderr message and exit from program
func fatal(format string, a ...any) {
fmt.Fprintf(os.Stderr, format+"\n", a...)
os.Exit(0)
os.Exit(1)
}

// usage print program usage
// Usage prints the usage of the program.
func usage() {
fmt.Printf(
`example:
GIT_PROJECT_DIR="~/src" gclone https://github.com/juev/gclone.git
the repository must be in one of the following formats:
- https://github.com/repository/name
- git@github.com/repository/name
`,
)
os.Exit(0)
fmt.Println("usage: gclone [-h] [-v] [REPOSITORY]")
fmt.Println()
fmt.Println("positional arguments:")
fmt.Println(" REPOSITORY Repository URL")
fmt.Println()
fmt.Println("optional arguments:")
fmt.Println(" -h, --help Show this help message and exit")
fmt.Println(" -v, --version Show the version number and exit")
fmt.Println()
fmt.Println("environment variables:")
fmt.Println(" GIT_PROJECT_DIR Directory to clone repositories")
fmt.Println()
fmt.Println("example:")
fmt.Println(" GIT_PROJECT_DIR=\"$HOME/src\" gclone https://github.com/user/repo")
}
104 changes: 22 additions & 82 deletions main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,67 +5,6 @@ import (
"testing"
)

func Test_parseRepositoryURL(t *testing.T) {
type args struct {
repository string
}
tests := []struct {
name string
args args
wantDir string
}{
{
name: "http github",
args: args{
repository: "https://github.com/kevincobain2000/gobrew.git",
},
wantDir: "github.com/kevincobain2000/gobrew",
},
{
name: "http github without prefix",
args: args{
repository: "github.com/kevincobain2000/gobrew.git",
},
wantDir: "github.com/kevincobain2000/gobrew",
},
{
name: "http github without prefix",
args: args{
repository: "https://github.com/kevincobain2000/gobrew",
},
wantDir: "github.com/kevincobain2000/gobrew",
},
{
name: "git github",
args: args{
repository: "git@github.com:kevincobain2000/gobrew.git",
},
wantDir: "github.com/kevincobain2000/gobrew",
},
{
name: "http sr.ht",
args: args{
repository: "https://git.sr.ht/~libreboot/lbmk",
},
wantDir: "git.sr.ht/libreboot/lbmk",
},
{
name: "git sr.ht",
args: args{
repository: "git@git.sr.ht:~libreboot/lbmk",
},
wantDir: "git.sr.ht/libreboot/lbmk",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if gotDir := parseRepositoryURL(tt.args.repository); gotDir != tt.wantDir {
t.Errorf("parseRepository() = %v, want %v", gotDir, tt.wantDir)
}
})
}
}

func Test_getProjectDir(t *testing.T) {
tests := []struct {
name string
Expand Down Expand Up @@ -116,6 +55,13 @@ func Test_getProjectDir(t *testing.T) {
gitProjectDir: "",
want: "github.com/user/repo",
},
{
name: "src",
repository: "ssh://user@host.xz:443/~user/path/to/repo.git/",
homeVar: "/home/test",
gitProjectDir: "src",
want: "src/host.xz/~user/path/to/repo.git",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down Expand Up @@ -170,55 +116,49 @@ func Test_isNotEmpty(t *testing.T) {
}
}

func Test_stripPrefixes(t *testing.T) {
func Test_parse(t *testing.T) {
type args struct {
repository string
}
tests := []struct {
name string
args args
want string
name string
args args
wantRepo string
}{
{
name: "https",
args: args{
repository: "https://github.com/user/repo",
},
want: "github.com/user/repo",
wantRepo: "github.com/user/repo",
},
{
name: "git",
name: "without scheme",
args: args{
repository: "git@git.sr.ht:~libreboot/lbmk",
repository: "github.com/user/repo",
},
want: "git.sr.ht:~libreboot/lbmk",
wantRepo: "github.com/user/repo",
},
{
name: "ssh",
args: args{
repository: "ssh://git.sr.ht/~libreboot/lbmk",
repository: "ssh://user@host.xz:443/~user/path/to/repo.git/",
},
want: "git.sr.ht/~libreboot/lbmk",
wantRepo: "host.xz/~user/path/to/repo.git",
},
{
name: "git",
args: args{
repository: "git://git@git.sr.ht:~libreboot/lbmk.git",
},
want: "git@git.sr.ht:~libreboot/lbmk.git",
},
{
name: "ftp",
args: args{
repository: "ftp://git.sr.ht/~libreboot/lbmk.git",
repository: "git@git.sr.ht:~libreboot/lbmk",
},
want: "git.sr.ht/~libreboot/lbmk.git",
wantRepo: "git.sr.ht/~libreboot/lbmk",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := stripPrefixes(tt.args.repository); got != tt.want {
t.Errorf("stripPrefixes() = %v, want %v", got, tt.want)
gotRepo := parse(tt.args.repository)
if gotRepo != tt.wantRepo {
t.Errorf("parse() gotRepo = %v, want %v", gotRepo, tt.wantRepo)
}
})
}
Expand Down

0 comments on commit 6322eef

Please sign in to comment.