-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathdownload.go
135 lines (123 loc) · 4.02 KB
/
download.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package gitstr
import (
"context"
"fmt"
"os"
"path/filepath"
"slices"
"strings"
"time"
"github.com/fatih/color"
"github.com/nbd-wtf/go-nostr"
"github.com/nbd-wtf/go-nostr/nip19"
"github.com/urfave/cli/v3"
)
var download = &cli.Command{
Name: "download",
Usage: "",
Description: "",
Flags: []cli.Flag{
&cli.StringSliceFlag{
Name: "relay",
Aliases: []string{"r"},
},
&cli.IntFlag{
Name: "limit",
Aliases: []string{"l"},
Value: 15,
},
},
Action: func(ctx context.Context, c *cli.Command) error {
id := getRepositoryID()
pk := getRepositoryPublicKey()
if pk == "" || id == "" {
logf("no repository id and pubkey found on `git config`, this command will only work with specific naddr or nevent patches.\n")
}
limit := c.Int("limit")
relays := append(getPatchRelays(), c.StringSlice("relay")...)
// patches we will try to browse -- if given an author we try to get all their patches targeting this repo,
// if given an event pointer we will try to fetch that patch specifically and so on, if given nothing we will
// list the latest patches available to this repository
items := c.Args().Slice()
if len(items) == 0 {
items = []string{""}
}
for _, arg := range items {
filter := nostr.Filter{
Limit: int(limit),
Kinds: []int{PatchKind},
Tags: nostr.TagMap{},
}
relays := slices.Clone(relays)
if arg != "" {
prefix, data, err := nip19.Decode(arg)
if err != nil {
logf("invalid argument '%s': %s\n", arg, err)
continue
}
switch prefix {
case "npub":
filter.Authors = append(filter.Authors, data.(string))
filter.Tags["a"] = []string{fmt.Sprintf("%d:%s:%s", RepoAnnouncementKind, pk, id)}
case "nprofile":
pp := data.(nostr.ProfilePointer)
filter.Authors = append(filter.Authors, pp.PublicKey)
filter.Tags["a"] = []string{fmt.Sprintf("%d:%s:%s", RepoAnnouncementKind, pk, id)}
relays = append(relays, pp.Relays...)
case "nevent":
ep := data.(nostr.EventPointer)
if ep.Kind != 0 && ep.Kind != PatchKind {
logf("invalid argument %s: expected an encoded kind %d or nothing\n", arg, PatchKind)
continue
}
filter = nostr.Filter{IDs: []string{ep.ID}}
relays = append(relays, ep.Relays...)
case "naddr":
ep := data.(nostr.EntityPointer)
if ep.Kind != RepoAnnouncementKind {
logf("invalid argument %s: expected an encoded kind %d\n", arg, RepoAnnouncementKind)
continue
}
filter = nostr.Filter{
Limit: int(limit),
Kinds: []int{PatchKind},
Tags: nostr.TagMap{
"a": []string{fmt.Sprintf("%d:%s:%s", RepoAnnouncementKind, ep.PublicKey, ep.Identifier)},
},
}
relays = append(relays, ep.Relays...)
default:
continue
}
}
gitRoot, err := git("rev-parse", "--show-toplevel")
base := filepath.Join(gitRoot, ".git/str/patches")
if err != nil {
return fmt.Errorf("failed to find git root: %w", err)
} else if err := os.MkdirAll(base, 0755); err != nil {
return fmt.Errorf("failed to create .git/str directory")
}
for ie := range pool.SubManyEose(ctx, relays, nostr.Filters{filter}) {
nevent, _ := nip19.EncodeEvent(ie.ID, nil, "")
npub, _ := nip19.EncodePublicKey(ie.PubKey)
subjectMatch := subjectRegex.FindStringSubmatch(ie.Event.Content)
if len(subjectMatch) == 0 {
continue
}
subject := subjectMatch[1]
subject = strings.ReplaceAll(strings.ReplaceAll(subject, "/", "_"), "'", "")
fileName := base + "/" + fmt.Sprintf("%s [%s] %s",
ie.CreatedAt.Time().Format(time.DateOnly), nevent[65:], subject)
if _, err := os.Stat(fileName); os.IsNotExist(err) {
logf("- downloaded patch %s from %s, saved as '%s'\n",
ie.Event.ID, npub, color.New(color.Underline).Sprint(fileName))
if err := os.WriteFile(fileName, []byte(ie.Event.Content), 0644); err != nil {
return fmt.Errorf("failed to write '%s': %w", fileName, err)
}
os.Chtimes(fileName, time.Time{}, ie.Event.CreatedAt.Time())
}
}
}
return nil
},
}