Skip to content

Commit

Permalink
Support to clone from a mirror and fork it (#43)
Browse files Browse the repository at this point in the history
  • Loading branch information
LinuxSuRen authored Jan 18, 2022
1 parent 2268167 commit 5eba315
Show file tree
Hide file tree
Showing 10 changed files with 202 additions and 8 deletions.
5 changes: 5 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,8 @@ goreleaser:

copy: build
sudo cp bin/cgit /usr/local/bin/cgit

# Install golang-lint via https://golangci-lint.run/usage/install/#local-installation
# or via 'hd install golangci-lint'
lint:
golangci-lint run ./...
74 changes: 74 additions & 0 deletions cmd/clone.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package cmd

import (
"github.com/AlecAivazis/survey/v2"
"github.com/linuxsuren/cgit/pkg"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"os/exec"
"path"
"strings"
)

type cloneOption struct {
ws bool
}

// NewCloneCommand returns the clone command
func NewCloneCommand() (cmd *cobra.Command) {
opt := &cloneOption{}

cmd = &cobra.Command{
Use: "clone",
Short: "A smart way to clone repositories from GitHub",
RunE: opt.runE,
}

flags := cmd.Flags()
flags.BoolVarP(&opt.ws, "ws", "", false, "Clone the code into ~/ws/github/org/repo if it is true")
return
}

func (o *cloneOption) runE(_ *cobra.Command, args []string) (err error) {
output := func(arg string) string {
if orgAndRepo := strings.Split(arg, "/"); len(orgAndRepo) == 2 {
return path.Join(viper.GetString("ws"), arg)
}
return ""
}
if !o.ws {
output = nil
}
args = pkg.ParseShortCode(args, output)

var targetDir string
gitAddress := args[0]
if len(args) >= 2 {
targetDir = args[1]
}

var gitBinary string
if gitBinary, err = exec.LookPath("git"); err == nil {
gitArgs := []string{"clone"}
gitArgs = append(gitArgs, args...)
pkg.UseMirror(gitArgs)
if err = pkg.ExecCommandInDir(gitBinary, "", gitArgs...); err == nil {
err = pkg.ExecCommandInDir(gitBinary, targetDir, "remote", "set-url", "origin", gitAddress)
}
}
if err != nil {
return
}

var ghBinary string
if ghBinary, err = exec.LookPath("gh"); err == nil {
prompt := &survey.Confirm{
Message: "do you want to fork it?",
}
var ok bool
if err = survey.AskOne(prompt, &ok); err == nil && ok {
err = pkg.ExecCommandInDir(ghBinary, targetDir, "repo", "fork", "--remote")
}
}
return
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module github.com/linuxsuren/cgit
go 1.16

require (
github.com/AlecAivazis/survey/v2 v2.3.2
github.com/linuxsuren/cobra-extension v0.0.12
github.com/linuxsuren/go-cli-alias v0.0.9
github.com/linuxsuren/http-downloader v0.0.52
Expand Down
4 changes: 2 additions & 2 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ func main() {

ctx := context.TODO()
command.AddCommand(ext.NewCompletionCmd(command),
cmd.NewMirrorCmd(ctx))
cmd.NewMirrorCmd(ctx),
cmd.NewCloneCommand())

// do the dep checking
if err := installDepTools(); err != nil {
Expand Down Expand Up @@ -129,7 +130,6 @@ func init() {
}
}
loadDefaults()
return
}

func loadDefaults() {
Expand Down
2 changes: 1 addition & 1 deletion mirror_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
func TestMirror(t *testing.T) {
abc := []string{"a", "b", "github.com"}
useMirror(abc)
assert.Equal(t, abc[2], "github.com.cnpmjs.org")
assert.Equal(t, abc[2], "github.com")

abc = []string{"clone", "https://github.com/cli/cli"}
useMirror(abc)
Expand Down
6 changes: 1 addition & 5 deletions pkg/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,9 @@ func ExecCommandInDir(name, dir string, args ...string) (err error) {
return
}

func execCommand(name string, arg ...string) (err error) {
return ExecCommandInDir(name, "", arg...)
}

func copyAndCapture(w io.Writer, r io.Reader) ([]byte, error) {
var out []byte
buf := make([]byte, 1024, 1024)
buf := make([]byte, 1024)
for {
n, err := r.Read(buf[:])
if n > 0 {
Expand Down
17 changes: 17 additions & 0 deletions pkg/mirror.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package pkg

import "strings"

// UseMirror modify the args with a GitHub mirror
func UseMirror(args []string) {
// only for git clone
if len(args) < 2 || args[0] != "clone" {
return
}
for i, arg := range args {
if strings.Contains(arg, "github.com") && !strings.Contains(arg, "github.com.cnpmjs.org") {
args[i] = strings.ReplaceAll(arg, "github.com", "github.com.cnpmjs.org")
break
}
}
}
32 changes: 32 additions & 0 deletions pkg/mirror_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package pkg

import (
"github.com/magiconair/properties/assert"
"testing"
)

func TestUseMirror(t *testing.T) {
type args struct {
args []string
}
tests := []struct {
name string
args args
verify func(*testing.T, []string)
}{{
name: "normal case",
args: args{
[]string{"clone", "https://github.com/a/b"},
},
verify: func(t *testing.T, args []string) {
assert.Equal(t, args[0], "clone")
assert.Equal(t, args[1], "https://github.com.cnpmjs.org/a/b")
},
}}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
UseMirror(tt.args.args)
tt.verify(t, tt.args.args)
})
}
}
33 changes: 33 additions & 0 deletions pkg/shortcode.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package pkg

import (
"fmt"
"strings"
)

// ParseShortCode parses a short org/repo to a GitHub URL
func ParseShortCode(args []string, output func(string) string) []string {
if len(args) <= 0 {
return args
}
if output == nil {
output = defaultOutput
}

result := []string{fmt.Sprintf("https://github.com/%s", args[0])}
if len(args) > 1 {
result = append(result, args[1:]...)
} else {
if target := output(args[0]); target != "" {
result = append(result, target)
}
}
return result
}

func defaultOutput(arg string) string {
if orgAndRepo := strings.Split(arg, "/"); len(orgAndRepo) == 2 {
return orgAndRepo[1]
}
return ""
}
36 changes: 36 additions & 0 deletions pkg/shortcode_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package pkg

import (
"reflect"
"testing"
)

func TestParseShortCode(t *testing.T) {
type args struct {
args []string
}
tests := []struct {
name string
args args
want []string
}{{
name: "org/repo format",
args: args{[]string{"org/repo"}},
want: []string{"https://github.com/org/repo", "repo"},
}, {
name: "'org/repo output' format",
args: args{[]string{"org/repo", "dir"}},
want: []string{"https://github.com/org/repo", "dir"},
}, {
name: "unexpected format",
args: args{[]string{}},
want: []string{},
}}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := ParseShortCode(tt.args.args, nil); !reflect.DeepEqual(got, tt.want) {
t.Errorf("ParseShortCode() = %v, want %v", got, tt.want)
}
})
}
}

0 comments on commit 5eba315

Please sign in to comment.