basic clone capabilities
This commit is contained in:
commit
d3647b71d7
3 changed files with 227 additions and 0 deletions
119
main.go
Normal file
119
main.go
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const GHQDir = "ghq"
|
||||
|
||||
// GitURL holds the parsed structure of the repository
|
||||
type GitURL struct {
|
||||
Original string
|
||||
Host string
|
||||
Path string // This includes namespace/repo (e.g. "juancwu/tools")
|
||||
}
|
||||
|
||||
func main() {
|
||||
args := os.Args[1:]
|
||||
|
||||
if len(args) != 1 {
|
||||
printUsage()
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
rawURL := args[0]
|
||||
|
||||
repoInfo, err := parseGitURL(rawURL)
|
||||
if err != nil {
|
||||
fmt.Printf("Error parsing URL: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
homeDir, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
fmt.Printf("Error getting home directory: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
targetDir := filepath.Join(homeDir, GHQDir, repoInfo.Host, repoInfo.Path)
|
||||
|
||||
if err := cloneRepo(repoInfo.Original, targetDir); err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
// parseGitURL extracts the Host and Path from SSH (SCP-syntax) or HTTP/Standard URLs
|
||||
func parseGitURL(raw string) (*GitURL, error) {
|
||||
raw = strings.TrimSpace(raw)
|
||||
|
||||
// Regex for SCP-like syntax: user@host:path/to/repo.git
|
||||
// Matches: git@github.com:user/repo.git
|
||||
scpSyntax := regexp.MustCompile(`^[\w-]+@([^:]+):(.+?)(?:\.git)?$`)
|
||||
|
||||
if match := scpSyntax.FindStringSubmatch(raw); match != nil {
|
||||
return &GitURL{
|
||||
Original: raw,
|
||||
Host: match[1],
|
||||
Path: match[2],
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Standard URL parsing for http, https, ssh://
|
||||
u, err := url.Parse(raw)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid URL format: %w", err)
|
||||
}
|
||||
|
||||
if u.Host == "" {
|
||||
return nil, fmt.Errorf("URL is missing a host (e.g. github.com)")
|
||||
}
|
||||
|
||||
cleanPath := strings.TrimPrefix(u.Path, "/")
|
||||
cleanPath = strings.TrimSuffix(cleanPath, ".git")
|
||||
|
||||
return &GitURL{
|
||||
Original: raw,
|
||||
Host: u.Host,
|
||||
Path: cleanPath,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func cloneRepo(url, targetDir string) error {
|
||||
// Check if directory already exists
|
||||
if _, err := os.Stat(targetDir); !os.IsNotExist(err) {
|
||||
fmt.Printf("Directory already exists: %s\n", targetDir)
|
||||
return nil
|
||||
}
|
||||
|
||||
fmt.Printf("Cloning into: %s\n", targetDir)
|
||||
|
||||
cmd := exec.Command("git", "clone", url, targetDir)
|
||||
// Pipe git output directly to the user's terminal
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
cmd.Stdin = os.Stdin
|
||||
|
||||
if err := cmd.Run(); err != nil {
|
||||
return fmt.Errorf("git clone failed: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func printUsage() {
|
||||
fmt.Println(`Usage: cl <repository_url>
|
||||
|
||||
Description:
|
||||
Clones a git repository into a structured directory tree:
|
||||
~/ghq/<domain>/<user>/<repo>
|
||||
|
||||
Examples:
|
||||
cl git@github.com:user/project.git
|
||||
cl https://gitlab.com/group/subgroup/project.git
|
||||
cl https://git.company.corp/devops/tools.git`)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue