Skip to content

Commit ede671f

Browse files
authored
Add sub-command mirror to set the mirror address (#15)
1 parent 1f248b0 commit ede671f

File tree

5 files changed

+194
-17
lines changed

5 files changed

+194
-17
lines changed

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,14 @@ cgit is a wrapper of git.
1212
* GitHub proxy transparent support
1313
* Git command alias support
1414

15+
## Mirror
16+
17+
`cgit` can set a mirror address for you if it's very slow with fetching data from GitHub.
18+
19+
Run this command `cgit mirror` in your local git repository directory,
20+
it'll change the fetch address to `github.com.cnpmjs.org`. Reversing it is very easy,
21+
just run command `cigt mirror --enable=false`.
22+
1523
# Install
1624

1725
```
@@ -43,3 +51,4 @@ Add a command alias: `cgit alias set cm 'checkout master'`
4351
Use an alias: `cgit cm`
4452

4553
List all alias commands: `cgit alias list`
54+

cmd/mirror.go

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package cmd
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"github.com/linuxsuren/cgit/pkg"
7+
"github.com/spf13/cobra"
8+
"net/url"
9+
"strings"
10+
)
11+
12+
type mirrorOption struct {
13+
enable bool
14+
remote string
15+
}
16+
17+
// NewMirrorCmd returns the mirror command
18+
func NewMirrorCmd(ctx context.Context) (cmd *cobra.Command) {
19+
opt := mirrorOption{}
20+
21+
cmd = &cobra.Command{
22+
Use: "mirror",
23+
Short: "Toggle the git mirror",
24+
RunE: opt.runE,
25+
}
26+
27+
flags := cmd.Flags()
28+
flags.BoolVarP(&opt.enable, "enable", "e", true, "Enable/disable the git mirror")
29+
flags.StringVarP(&opt.remote, "remote", "r", "origin", "The remote of git repository")
30+
return
31+
}
32+
33+
func (o *mirrorOption) runE(cmd *cobra.Command, args []string) (err error) {
34+
var remoteURLStr string
35+
var remotePushURLStr string
36+
if remoteURLStr, err = pkg.ExecCommandWithOutput("git", "", "remote", "get-url", o.remote); err != nil {
37+
return
38+
}
39+
40+
if remotePushURLStr, err = pkg.ExecCommandWithOutput("git", "", "remote", "get-url", "--push", o.remote); err != nil {
41+
return
42+
}
43+
// remove the .git tail
44+
remoteURLStr = strings.TrimSuffix(remoteURLStr, ".git")
45+
46+
gitProtocol := strings.HasPrefix(remoteURLStr, "git@")
47+
if gitProtocol {
48+
remoteURLStr = strings.ReplaceAll(remoteURLStr, "git@github.com:", "https://github.com/")
49+
}
50+
51+
var remoteURL *url.URL
52+
if remoteURL, err = url.Parse(remoteURLStr); err != nil {
53+
cmd.Println("error with parse URL", remoteURLStr)
54+
return
55+
}
56+
57+
if o.enable {
58+
remoteURL.Host = "github.com.cnpmjs.org"
59+
} else {
60+
remoteURL.Host = "github.com"
61+
}
62+
63+
targetRemoteURLStr := remoteURL.String()
64+
if strings.HasPrefix(remotePushURLStr, "git@") && !o.enable {
65+
// the mirror git server does not support git protocol
66+
targetRemoteURLStr = strings.ReplaceAll(targetRemoteURLStr, fmt.Sprintf("https://%s/", remoteURL.Host),
67+
fmt.Sprintf("git@%s:", remoteURL.Host))
68+
targetRemoteURLStr += ".git"
69+
}
70+
71+
if err = pkg.ExecCommandInDir("git", "", "remote", "set-url", o.remote, targetRemoteURLStr); err != nil {
72+
return
73+
}
74+
if err = pkg.ExecCommandInDir("git", "", "remote", "set-url", "--push", o.remote, remotePushURLStr); err != nil {
75+
return
76+
}
77+
return
78+
}

go.sum

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -158,15 +158,9 @@ github.com/kr/pty v1.1.4/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
158158
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
159159
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
160160
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
161-
github.com/linuxsuren/cobra-extension v0.0.1 h1:e288zsm1iWUaAOjfiw42hiWJsrrXZnJ0vKApWPyTfkQ=
162-
github.com/linuxsuren/cobra-extension v0.0.1/go.mod h1:UqHi31q7Dj+46nzcVWNZz5Z1JcHBJcmCyPAZRoM8LXo=
163161
github.com/linuxsuren/cobra-extension v0.0.3/go.mod h1:UqHi31q7Dj+46nzcVWNZz5Z1JcHBJcmCyPAZRoM8LXo=
164162
github.com/linuxsuren/cobra-extension v0.0.5 h1:3go926vpXiizRzBEwt8CddCDerRsG5hlIFr0JJvGaKc=
165163
github.com/linuxsuren/cobra-extension v0.0.5/go.mod h1:qcEJv7BbL0UpK6MbrTESP/nKf1+z1wQdMAnE1NBl3QQ=
166-
github.com/linuxsuren/go-cli-alias v0.0.3-0.20201208135826-ad33122f181c h1:YNpS+IdkZA9fvNa9gi7xA45FrVSNsEamrzdyezJndjM=
167-
github.com/linuxsuren/go-cli-alias v0.0.3-0.20201208135826-ad33122f181c/go.mod h1:l2/nzdvung0zorpCxI1CT+Fuuc/W1sFEWS0jt3/b2ZM=
168-
github.com/linuxsuren/go-cli-alias v0.0.3 h1:IbqC+4uOTCRM27WCII7Z35pXP4bwqck0J5jg2xmIqr4=
169-
github.com/linuxsuren/go-cli-alias v0.0.3/go.mod h1:l2/nzdvung0zorpCxI1CT+Fuuc/W1sFEWS0jt3/b2ZM=
170164
github.com/linuxsuren/go-cli-alias v0.0.4 h1:+otarDOeSZzzbTCr9CllAOQCQNpaf/HI41iDvWWUo/w=
171165
github.com/linuxsuren/go-cli-alias v0.0.4/go.mod h1:dfwOx8H0iVpdS9gtLC80GCC4cvDvzWejxjxXn7sFWUs=
172166
github.com/linuxsuren/go-cli-plugin v0.0.1/go.mod h1:uyO09KK8otYfDV5LVTfcWX2UbAi3kEz3PrkdfIxnDlg=

main.go

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
package main
22

33
import (
4+
"context"
45
"fmt"
6+
"github.com/linuxsuren/cgit/cmd"
7+
"github.com/linuxsuren/cgit/pkg"
58
ext "github.com/linuxsuren/cobra-extension"
69
extver "github.com/linuxsuren/cobra-extension/version"
710
aliasCmd "github.com/linuxsuren/go-cli-alias/pkg/cmd"
811
"github.com/spf13/cobra"
9-
"os"
1012
"os/exec"
1113
"strings"
12-
"syscall"
1314
)
1415

1516
const (
@@ -18,28 +19,30 @@ const (
1819
)
1920

2021
func main() {
21-
cmd := &cobra.Command{
22+
command := &cobra.Command{
2223
Use: AliasCLI,
23-
RunE: func(cmd *cobra.Command, args []string) (err error) {
24-
env := os.Environ()
25-
24+
RunE: func(command *cobra.Command, args []string) (err error) {
25+
fmt.Println(args, "sdfs")
2626
preHook(args)
2727

28+
command.Println(args)
29+
2830
var gitBinary string
2931
if gitBinary, err = exec.LookPath(TargetCLI); err == nil {
30-
syscall.Exec(gitBinary, append([]string{TargetCLI}, args...), env)
32+
err = pkg.ExecCommandInDir(gitBinary, "", args...)
3133
}
3234
return
3335
},
3436
}
3537

36-
cmd.AddCommand(extver.NewVersionCmd("linuxsuren", AliasCLI, AliasCLI, nil))
38+
command.AddCommand(extver.NewVersionCmd("linuxsuren", AliasCLI, AliasCLI, nil))
3739

38-
aliasCmd.AddAliasCmd(cmd, getAliasList())
40+
aliasCmd.AddAliasCmd(command, getAliasList())
3941

40-
cmd.AddCommand(ext.NewCompletionCmd(cmd))
42+
command.AddCommand(ext.NewCompletionCmd(command),
43+
cmd.NewMirrorCmd(context.TODO()))
4144

42-
aliasCmd.Execute(cmd, TargetCLI, getAliasList(), preHook)
45+
aliasCmd.Execute(command, TargetCLI, getAliasList(), preHook)
4346
}
4447

4548
func preHook(args []string) {

pkg/exec.go

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
package pkg
2+
3+
import (
4+
"io"
5+
"io/ioutil"
6+
"os"
7+
"os/exec"
8+
"strings"
9+
"sync"
10+
)
11+
12+
// ExecCommandWithOutput run a command than returns the output
13+
func ExecCommandWithOutput(name, dir string, args ...string) (output string, err error) {
14+
command := exec.Command(name, args...)
15+
if dir != "" {
16+
command.Dir = dir
17+
}
18+
19+
var stdoutIn io.ReadCloser
20+
if stdoutIn, err = command.StdoutPipe(); err != nil {
21+
return
22+
}
23+
if err = command.Start(); err != nil {
24+
return
25+
}
26+
27+
var data []byte
28+
if data, err = ioutil.ReadAll(stdoutIn); err == nil {
29+
output = strings.TrimSpace(string(data))
30+
}
31+
return
32+
}
33+
34+
// ExecCommandInDir run a command in a directory
35+
func ExecCommandInDir(name, dir string, args ...string) (err error) {
36+
command := exec.Command(name, args...)
37+
if dir != "" {
38+
command.Dir = dir
39+
}
40+
41+
//var stdout []byte
42+
//var errStdout error
43+
stdoutIn, _ := command.StdoutPipe()
44+
stderrIn, _ := command.StderrPipe()
45+
err = command.Start()
46+
if err != nil {
47+
return err
48+
}
49+
50+
// cmd.Wait() should be called only after we finish reading
51+
// from stdoutIn and stderrIn.
52+
// wg ensures that we finish
53+
var wg sync.WaitGroup
54+
wg.Add(1)
55+
go func() {
56+
_, _ = copyAndCapture(os.Stdout, stdoutIn)
57+
wg.Done()
58+
}()
59+
60+
_, _ = copyAndCapture(os.Stderr, stderrIn)
61+
62+
wg.Wait()
63+
64+
err = command.Wait()
65+
return
66+
}
67+
68+
func execCommand(name string, arg ...string) (err error) {
69+
return ExecCommandInDir(name, "", arg...)
70+
}
71+
72+
func copyAndCapture(w io.Writer, r io.Reader) ([]byte, error) {
73+
var out []byte
74+
buf := make([]byte, 1024, 1024)
75+
for {
76+
n, err := r.Read(buf[:])
77+
if n > 0 {
78+
d := buf[:n]
79+
out = append(out, d...)
80+
_, err := w.Write(d)
81+
if err != nil {
82+
return out, err
83+
}
84+
}
85+
if err != nil {
86+
// Read returns io.EOF at the end of file, which is not an error for us
87+
if err == io.EOF {
88+
err = nil
89+
}
90+
return out, err
91+
}
92+
}
93+
}

0 commit comments

Comments
 (0)