commit
e38d07554c
|
@ -0,0 +1,2 @@
|
|||
.idea/
|
||||
/clone*
|
|
@ -0,0 +1,19 @@
|
|||
Copyright (c) 2022 John Olheiser
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
|
@ -0,0 +1,23 @@
|
|||
# clone
|
||||
|
||||
Clone projects into a common GOPATH-like structure.
|
||||
|
||||
Uses the base path (in order of preference):
|
||||
- `$(CLONE_DIR)`
|
||||
- `$(UserHomeDir)/code`
|
||||
- [$(UserHomeDir)](https://pkg.go.dev/os#UserHomeDir)
|
||||
|
||||
```shell
|
||||
clone git.jojodev.com/jolheiser/clone.git
|
||||
```
|
||||
by default, on a Linux machine, would clone to `/home/<user>/code/git.jojodev.com/jolheiser/clone`
|
||||
|
||||
To `cd` into a newly cloned (or initialized) project:
|
||||
|
||||
```shell
|
||||
cd $(clone --last)
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
[MIT](LICENSE)
|
|
@ -0,0 +1,10 @@
|
|||
module go.jolheiser.com/clone
|
||||
|
||||
go 1.17
|
||||
|
||||
require github.com/rs/zerolog v1.26.1
|
||||
|
||||
require (
|
||||
github.com/peterbourgon/ff/v3 v3.1.2 // indirect
|
||||
go.jolheiser.com/ffmd v0.0.2 // indirect
|
||||
)
|
|
@ -0,0 +1,42 @@
|
|||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
|
||||
github.com/pelletier/go-toml v1.6.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys=
|
||||
github.com/peterbourgon/ff/v3 v3.1.2 h1:0GNhbRhO9yHA4CC27ymskOsuRpmX0YQxwxM9UPiP6JM=
|
||||
github.com/peterbourgon/ff/v3 v3.1.2/go.mod h1:XNJLY8EIl6MjMVjBS4F0+G0LYoAqs0DTa4rmHHukKDE=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||
github.com/rs/zerolog v1.26.1 h1:/ihwxqH+4z8UxyI70wM1z9yCvkWcfz/a3mj48k/Zngc=
|
||||
github.com/rs/zerolog v1.26.1/go.mod h1:/wSSJWX7lVrsOwlbyTRSOJvqRlc+WjWlfes+CiJ+tmc=
|
||||
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
go.jolheiser.com/ffmd v0.0.2 h1:rNOUq5wQKsNQU3pc51XNaks9+GK9hLlFTsPHrQhlGRU=
|
||||
go.jolheiser.com/ffmd v0.0.2/go.mod h1:NLhcXZqO+dwvQ2/X9z3TUA3gORxUuRlgOjKC931vCZ4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20211215165025-cf75a172585e/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
@ -0,0 +1,150 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
func main() {
|
||||
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})
|
||||
|
||||
fs := flag.NewFlagSet("clone", flag.ExitOnError)
|
||||
init := fs.Bool("init", false, "Initialize new project")
|
||||
last := fs.Bool("last", false, "Show last created project")
|
||||
if err := fs.Parse(os.Args[1:]); err != nil {
|
||||
log.Fatal().Err(err).Msg("")
|
||||
}
|
||||
|
||||
if fs.NArg() < 1 && !*last {
|
||||
_, _ = fmt.Fprintln(fs.Output(), "Usage of clone:\nclone [-init|-last] <path>")
|
||||
return
|
||||
}
|
||||
|
||||
uri := fs.Arg(0)
|
||||
|
||||
path, err := clone(*init, *last, uri)
|
||||
if err != nil {
|
||||
log.Err(err).Msg("")
|
||||
return
|
||||
}
|
||||
|
||||
if path != "" {
|
||||
log.Info().Msg(path)
|
||||
}
|
||||
}
|
||||
|
||||
func clone(init, last bool, uri string) (string, error) {
|
||||
if last {
|
||||
lastProject()
|
||||
return "", nil
|
||||
}
|
||||
|
||||
base := codeDir()
|
||||
|
||||
if !strings.HasPrefix(uri, "http") {
|
||||
uri = "https://" + uri
|
||||
}
|
||||
|
||||
u, err := url.Parse(uri)
|
||||
if err != nil || strings.EqualFold(u.String(), "") {
|
||||
return "", err
|
||||
}
|
||||
|
||||
path := filepath.Join(base, u.Host+strings.TrimSuffix(u.Path, ".git"))
|
||||
setLastProject(path)
|
||||
|
||||
// Init project
|
||||
if init {
|
||||
if err := os.MkdirAll(path, os.ModePerm); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return path, nil
|
||||
}
|
||||
|
||||
// Clone project
|
||||
if !strings.HasSuffix(u.String(), ".git") {
|
||||
u.Path += ".git"
|
||||
}
|
||||
|
||||
dir := filepath.Dir(path)
|
||||
if err := os.MkdirAll(dir, os.ModePerm); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
cmd := exec.Command("git", "clone", u.String())
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
cmd.Dir = dir
|
||||
if err := cmd.Run(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return path, nil
|
||||
}
|
||||
|
||||
func codeDir() string {
|
||||
dir := os.Getenv("CLONE_DIR")
|
||||
if dir != "" {
|
||||
return dir
|
||||
}
|
||||
|
||||
home, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
log.Fatal().Err(err).Msg("")
|
||||
}
|
||||
|
||||
return filepath.Join(home, "code")
|
||||
}
|
||||
|
||||
func config() (*os.File, error) {
|
||||
cfg, err := os.UserConfigDir()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dir := filepath.Join(cfg, "clone")
|
||||
if err := os.MkdirAll(dir, os.ModePerm); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
path := filepath.Join(dir, "last.txt")
|
||||
return os.OpenFile(path, os.O_CREATE|os.O_RDWR, os.ModePerm)
|
||||
}
|
||||
|
||||
func lastProject() {
|
||||
fi, err := config()
|
||||
if err != nil {
|
||||
log.Err(err).Msg("")
|
||||
return
|
||||
}
|
||||
defer fi.Close()
|
||||
last, err := io.ReadAll(fi)
|
||||
if err != nil {
|
||||
log.Err(err).Msg("")
|
||||
return
|
||||
}
|
||||
fmt.Println(string(last))
|
||||
}
|
||||
|
||||
func setLastProject(last string) {
|
||||
fi, err := config()
|
||||
if err != nil {
|
||||
log.Err(err).Msg("")
|
||||
return
|
||||
}
|
||||
defer fi.Close()
|
||||
if err := fi.Truncate(0); err != nil {
|
||||
log.Err(err).Msg("")
|
||||
return
|
||||
}
|
||||
if _, err := fi.WriteString(last); err != nil {
|
||||
log.Err(err).Msg("")
|
||||
return
|
||||
}
|
||||
}
|
Reference in New Issue