1package cli
2
3import (
4 "fmt"
5 "os"
6 "path/filepath"
7 "strings"
8
9 "arche/internal/repo"
10 "arche/internal/syncpkg"
11
12 "github.com/spf13/cobra"
13)
14
15var cloneCmd = &cobra.Command{
16 Use: "clone <url> [directory]",
17 Short: "Clone a remote Arche repository",
18 Long: `Clone a remote Arche repository into a new directory.
19
20The URL may use any scheme supported by arche sync:
21 arche clone http://host:8765 # bearer token over HTTP
22 arche clone arche+ssh://host/repo # SSH with key auth
23
24The directory defaults to the last path component of the URL.
25
26Examples:
27 arche clone http://forge.example.com/myrepo
28 arche clone arche+ssh://forge.example.com/simao/project local-dir
29 arche clone http://forge.example.com/myrepo --token mysecret`,
30 Args: cobra.RangeArgs(1, 2),
31 RunE: func(cmd *cobra.Command, args []string) error {
32 remoteURL := args[0]
33 token, _ := cmd.Flags().GetString("token")
34
35 dir := ""
36 if len(args) == 2 {
37 dir = args[1]
38 } else {
39 dir = guessLocalDir(remoteURL)
40 }
41
42 if _, err := os.Stat(dir); err == nil {
43 return fmt.Errorf("destination %q already exists", dir)
44 }
45
46 fmt.Printf("arche clone: cloning %s into %s …\n", remoteURL, dir)
47
48 r, err := repo.Init(dir)
49 if err != nil {
50 return fmt.Errorf("init: %w", err)
51 }
52 defer r.Close()
53
54 client := syncpkg.NewClient(r, remoteURL, token)
55 if err := client.Pull(); err != nil {
56 os.RemoveAll(dir) //nolint:errcheck
57 return fmt.Errorf("pull: %w", err)
58 }
59
60 r.Cfg.Remotes = append(r.Cfg.Remotes, repo.RemoteConfig{
61 Name: "origin",
62 URL: remoteURL,
63 Token: token,
64 })
65 if err := r.SaveConfig(); err != nil {
66 fmt.Fprintf(os.Stderr, "arche clone: warning: could not save remote config: %v\n", err)
67 }
68
69 headCID, _ := r.Head()
70 fmt.Printf("arche clone: done. Working copy at %s\n", headCID)
71 fmt.Printf("cd %s && arche log\n", dir)
72 return nil
73 },
74}
75
76func guessLocalDir(rawURL string) string {
77 s := rawURL
78 for _, prefix := range []string{"arche+ssh://", "arche://", "https://", "http://"} {
79 s = strings.TrimPrefix(s, prefix)
80 }
81
82 s = strings.TrimRight(s, "/")
83 if idx := strings.LastIndex(s, "/"); idx >= 0 {
84 s = s[idx+1:]
85 }
86
87 s = strings.TrimSuffix(s, ".git")
88 if s == "" {
89 s = "repo"
90 }
91 return filepath.Clean(s)
92}
93
94func init() {
95 cloneCmd.Flags().String("token", "", "bearer token for HTTP auth")
96}