mirror of
https://github.com/fiatjaf/nak.git
synced 2025-12-08 16:48:51 +00:00
Compare commits
2 Commits
16916d7d95
...
210cf66d5f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
210cf66d5f | ||
|
|
f9335b0ab4 |
421
git.go
421
git.go
@@ -8,6 +8,7 @@ import (
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"fiatjaf.com/nostr"
|
||||
"fiatjaf.com/nostr/nip19"
|
||||
@@ -92,6 +93,9 @@ aside from those, there is also:
|
||||
}
|
||||
}
|
||||
|
||||
var defaultOwner string
|
||||
var defaultIdentifier string
|
||||
|
||||
// check if nip34.json already exists
|
||||
existingConfig, err := readNip34ConfigFile("")
|
||||
if err == nil {
|
||||
@@ -99,47 +103,118 @@ aside from those, there is also:
|
||||
if !c.Bool("force") && !c.Bool("interactive") {
|
||||
return fmt.Errorf("nip34.json already exists, use --force to overwrite or --interactive to update")
|
||||
}
|
||||
}
|
||||
|
||||
// get repository base directory name for defaults
|
||||
cwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get current directory: %w", err)
|
||||
}
|
||||
baseName := filepath.Base(cwd)
|
||||
|
||||
// get earliest unique commit
|
||||
var earliestCommit string
|
||||
if output, err := exec.Command("git", "rev-list", "--max-parents=0", "HEAD").Output(); err == nil {
|
||||
earliest := strings.Split(strings.TrimSpace(string(output)), "\n")
|
||||
if len(earliest) > 0 {
|
||||
earliestCommit = earliest[0]
|
||||
}
|
||||
}
|
||||
|
||||
// extract clone URLs from nostr:// git remotes
|
||||
// (this is just for migrating from ngit)
|
||||
var defaultCloneURLs []string
|
||||
if output, err := exec.Command("git", "remote", "-v").Output(); err == nil {
|
||||
remotes := strings.Split(strings.TrimSpace(string(output)), "\n")
|
||||
for _, remote := range remotes {
|
||||
if strings.Contains(remote, "nostr://") {
|
||||
parts := strings.Fields(remote)
|
||||
if len(parts) >= 2 {
|
||||
nostrURL := parts[1]
|
||||
// parse nostr://npub.../relay_hostname/identifier
|
||||
if owner, identifier, relays, err := parseRepositoryAddress(ctx, nostrURL); err == nil && len(relays) > 0 {
|
||||
relayURL := relays[0]
|
||||
// convert to https://relay_hostname/npub.../identifier.git
|
||||
cloneURL := fmt.Sprintf("http%s/%s/%s.git",
|
||||
relayURL[2:], nip19.EncodeNpub(owner), identifier)
|
||||
defaultCloneURLs = appendUnique(defaultCloneURLs, cloneURL)
|
||||
defaultIdentifier = existingConfig.Identifier
|
||||
defaultOwner = existingConfig.Owner
|
||||
} else {
|
||||
// extract info from nostr:// git remotes (this is just for migrating from ngit)
|
||||
if output, err := exec.Command("git", "remote", "-v").Output(); err == nil {
|
||||
remotes := strings.Split(strings.TrimSpace(string(output)), "\n")
|
||||
for _, remote := range remotes {
|
||||
if strings.Contains(remote, "nostr://") {
|
||||
parts := strings.Fields(remote)
|
||||
if len(parts) >= 2 {
|
||||
nostrURL := parts[1]
|
||||
// parse nostr://npub.../relay_hostname/identifier
|
||||
if remoteOwner, remoteIdentifier, relays, err := parseRepositoryAddress(ctx, nostrURL); err == nil && len(relays) > 0 {
|
||||
defaultIdentifier = remoteIdentifier
|
||||
defaultOwner = nip19.EncodeNpub(remoteOwner)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// get repository base directory name for defaults
|
||||
if defaultIdentifier == "" {
|
||||
cwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get current directory: %w", err)
|
||||
}
|
||||
defaultIdentifier = filepath.Base(cwd)
|
||||
}
|
||||
|
||||
// prompt for identifier first
|
||||
var identifier string
|
||||
if c.String("identifier") != "" {
|
||||
identifier = c.String("identifier")
|
||||
} else if c.Bool("interactive") {
|
||||
if err := survey.AskOne(&survey.Input{
|
||||
Message: "identifier",
|
||||
Default: defaultIdentifier,
|
||||
}, &identifier); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
identifier = defaultIdentifier
|
||||
}
|
||||
|
||||
// prompt for owner pubkey
|
||||
var owner nostr.PubKey
|
||||
var ownerStr string
|
||||
if c.String("owner") != "" {
|
||||
owner, err = parsePubKey(ownerStr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid owner pubkey: %w", err)
|
||||
}
|
||||
ownerStr = nip19.EncodeNpub(owner)
|
||||
} else if c.Bool("interactive") {
|
||||
for {
|
||||
if err := survey.AskOne(&survey.Input{
|
||||
Message: "owner (npub or hex)",
|
||||
Default: defaultOwner,
|
||||
}, &ownerStr); err != nil {
|
||||
return err
|
||||
}
|
||||
owner, err = parsePubKey(ownerStr)
|
||||
if err == nil {
|
||||
ownerStr = nip19.EncodeNpub(owner)
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return fmt.Errorf("owner pubkey is required (use --owner or --interactive)")
|
||||
}
|
||||
|
||||
// try to fetch existing repository announcement (kind 30617)
|
||||
var fetchedRepo *nip34.Repository
|
||||
if existingConfig.Identifier == "" {
|
||||
log(" searching for existing events... ")
|
||||
repo, _, err := fetchRepositoryAndState(ctx, owner, identifier, nil)
|
||||
if err == nil && repo.Event.ID != nostr.ZeroID {
|
||||
fetchedRepo = &repo
|
||||
log("found one from %s.\n", repo.Event.CreatedAt.Time().Format(time.DateOnly))
|
||||
} else {
|
||||
log("none found.\n")
|
||||
}
|
||||
}
|
||||
|
||||
// set config with fetched values or defaults
|
||||
var config Nip34Config
|
||||
if fetchedRepo != nil {
|
||||
config = RepositoryToConfig(*fetchedRepo)
|
||||
} else if existingConfig.Identifier != "" {
|
||||
config = existingConfig
|
||||
} else {
|
||||
// get earliest unique commit
|
||||
var earliestCommit string
|
||||
if output, err := exec.Command("git", "rev-list", "--max-parents=0", "HEAD").Output(); err == nil {
|
||||
earliestCommit = strings.TrimSpace(string(output))
|
||||
}
|
||||
|
||||
config = Nip34Config{
|
||||
Identifier: identifier,
|
||||
Owner: ownerStr,
|
||||
Name: identifier,
|
||||
Description: "",
|
||||
Web: []string{},
|
||||
GraspServers: []string{"gitnostr.com", "relay.ngit.dev"},
|
||||
EarliestUniqueCommit: earliestCommit,
|
||||
Maintainers: []string{},
|
||||
}
|
||||
}
|
||||
|
||||
// helper to get value from flags, existing config, or default
|
||||
getValue := func(existingVal, flagVal, defaultVal string) string {
|
||||
if flagVal != "" {
|
||||
@@ -161,21 +236,84 @@ aside from those, there is also:
|
||||
return defaultVals
|
||||
}
|
||||
|
||||
config := Nip34Config{
|
||||
Identifier: getValue(existingConfig.Identifier, c.String("identifier"), baseName),
|
||||
Name: getValue(existingConfig.Name, c.String("name"), baseName),
|
||||
Description: getValue(existingConfig.Description, c.String("description"), ""),
|
||||
Web: getSliceValue(existingConfig.Web, c.StringSlice("web"), []string{}),
|
||||
Owner: getValue(existingConfig.Owner, c.String("owner"), ""),
|
||||
GraspServers: getSliceValue(existingConfig.GraspServers, c.StringSlice("grasp-servers"), []string{"gitnostr.com", "relay.ngit.dev"}),
|
||||
EarliestUniqueCommit: getValue(existingConfig.EarliestUniqueCommit, c.String("earliest-unique-commit"), earliestCommit),
|
||||
Maintainers: getSliceValue(existingConfig.Maintainers, c.StringSlice("maintainers"), []string{}),
|
||||
}
|
||||
// override with flags and existing config
|
||||
config.Identifier = getValue(existingConfig.Identifier, c.String("identifier"), config.Identifier)
|
||||
config.Name = getValue(existingConfig.Name, c.String("name"), config.Name)
|
||||
config.Description = getValue(existingConfig.Description, c.String("description"), config.Description)
|
||||
config.Web = getSliceValue(existingConfig.Web, c.StringSlice("web"), config.Web)
|
||||
config.Owner = getValue(existingConfig.Owner, c.String("owner"), config.Owner)
|
||||
config.GraspServers = getSliceValue(existingConfig.GraspServers, c.StringSlice("grasp-servers"), config.GraspServers)
|
||||
config.EarliestUniqueCommit = getValue(existingConfig.EarliestUniqueCommit, c.String("earliest-unique-commit"), config.EarliestUniqueCommit)
|
||||
config.Maintainers = getSliceValue(existingConfig.Maintainers, c.StringSlice("maintainers"), config.Maintainers)
|
||||
|
||||
if c.Bool("interactive") {
|
||||
if err := promptForConfig(&config); err != nil {
|
||||
// prompt for name
|
||||
if err := survey.AskOne(&survey.Input{
|
||||
Message: "name",
|
||||
Default: config.Name,
|
||||
}, &config.Name); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// prompt for description
|
||||
if err := survey.AskOne(&survey.Input{
|
||||
Message: "description",
|
||||
Default: config.Description,
|
||||
}, &config.Description); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// prompt for grasp servers
|
||||
graspServers, err := promptForStringList("grasp servers", config.GraspServers, []string{
|
||||
"gitnostr.com",
|
||||
"relay.ngit.dev",
|
||||
"pyramid.fiatjaf.com",
|
||||
"git.shakespeare.dyi",
|
||||
}, graspServerHost, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
config.GraspServers = graspServers
|
||||
|
||||
// prompt for web URLs
|
||||
webURLs, err := promptForStringList("web URLs", config.Web, []string{
|
||||
fmt.Sprintf("https://gitworkshop.dev/%s/%s",
|
||||
nip19.EncodeNpub(nostr.MustPubKeyFromHex(config.Owner)),
|
||||
config.Identifier,
|
||||
),
|
||||
}, func(s string) string {
|
||||
return "http" + nostr.NormalizeURL(s)[2:]
|
||||
}, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
config.Web = webURLs
|
||||
|
||||
// prompt for earliest unique commit
|
||||
if err := survey.AskOne(&survey.Input{
|
||||
Message: "earliest unique commit",
|
||||
Default: config.EarliestUniqueCommit,
|
||||
}, &config.EarliestUniqueCommit); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Prompt for maintainers
|
||||
maintainers, err := promptForStringList("maintainers", config.Maintainers, []string{}, nil, func(s string) bool {
|
||||
pk, err := parsePubKey(s)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
if pk.Hex() == config.Owner {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
config.Maintainers = maintainers
|
||||
|
||||
log("\n")
|
||||
}
|
||||
|
||||
if err := config.Validate(); err != nil {
|
||||
@@ -197,7 +335,7 @@ aside from those, there is also:
|
||||
|
||||
log("edit %s if needed, then run %s to publish.\n",
|
||||
color.CyanString("nip34.json"),
|
||||
color.CyanString("nak git announce"))
|
||||
color.CyanString("nak git sync"))
|
||||
|
||||
return nil
|
||||
},
|
||||
@@ -266,22 +404,7 @@ aside from those, there is also:
|
||||
}
|
||||
|
||||
// write nip34.json inside cloned directory
|
||||
localConfig := Nip34Config{
|
||||
Identifier: repo.ID,
|
||||
Name: repo.Name,
|
||||
Description: repo.Description,
|
||||
Web: repo.Web,
|
||||
Owner: nip19.EncodeNpub(repo.Event.PubKey),
|
||||
GraspServers: make([]string, 0, len(repo.Relays)),
|
||||
EarliestUniqueCommit: repo.EarliestUniqueCommitID,
|
||||
Maintainers: make([]string, 0, len(repo.Maintainers)),
|
||||
}
|
||||
for _, r := range repo.Relays {
|
||||
localConfig.GraspServers = append(localConfig.GraspServers, nostr.NormalizeURL(r))
|
||||
}
|
||||
for _, m := range repo.Maintainers {
|
||||
localConfig.Maintainers = append(localConfig.Maintainers, nip19.EncodeNpub(m))
|
||||
}
|
||||
localConfig := RepositoryToConfig(repo)
|
||||
|
||||
if err := localConfig.Validate(); err != nil {
|
||||
return fmt.Errorf("invalid config: %w", err)
|
||||
@@ -423,8 +546,7 @@ aside from those, there is also:
|
||||
pushSuccesses := 0
|
||||
for _, relay := range repo.Relays {
|
||||
relayURL := nostr.NormalizeURL(relay)
|
||||
remoteName := "nip34/grasp/" + strings.TrimPrefix(relayURL, "wss://")
|
||||
remoteName = strings.TrimPrefix(remoteName, "ws://")
|
||||
remoteName := gitRemoteName(relayURL)
|
||||
|
||||
log("pushing to %s...\n", color.CyanString(remoteName))
|
||||
pushArgs := []string{"push", remoteName, fmt.Sprintf("%s:refs/heads/%s", localBranch, remoteBranch)}
|
||||
@@ -617,50 +739,45 @@ aside from those, there is also:
|
||||
|
||||
func promptForStringList(
|
||||
name string,
|
||||
existing []string,
|
||||
defaults []string,
|
||||
alternatives []string,
|
||||
normalize func(string) string,
|
||||
validate func(string) bool,
|
||||
) ([]string, error) {
|
||||
options := make([]string, 0, len(defaults)+len(existing)+1)
|
||||
options := make([]string, 0, len(defaults)+len(alternatives)+1)
|
||||
options = append(options, defaults...)
|
||||
options = append(options, "add another")
|
||||
|
||||
// add existing not in options
|
||||
for _, item := range existing {
|
||||
for _, item := range alternatives {
|
||||
if !slices.Contains(options, item) {
|
||||
options = append(options, item)
|
||||
}
|
||||
}
|
||||
|
||||
selected := make([]string, len(existing))
|
||||
copy(selected, existing)
|
||||
options = append(options, "add another")
|
||||
|
||||
selected := make([]string, len(defaults))
|
||||
copy(selected, defaults)
|
||||
|
||||
for {
|
||||
prompt := &survey.MultiSelect{
|
||||
newSelected := []string{}
|
||||
if err := survey.AskOne(&survey.MultiSelect{
|
||||
Message: name,
|
||||
Options: options,
|
||||
Default: selected,
|
||||
PageSize: 20,
|
||||
}
|
||||
|
||||
if err := survey.AskOne(prompt, &selected); err != nil {
|
||||
}, &newSelected); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
selected = newSelected
|
||||
|
||||
if slices.Contains(selected, "add another") {
|
||||
selected = slices.DeleteFunc(selected, func(s string) bool { return s == "add another" })
|
||||
|
||||
singular := name
|
||||
if strings.HasSuffix(singular, "s") {
|
||||
singular = singular[:len(singular)-1]
|
||||
}
|
||||
|
||||
newPrompt := &survey.Input{
|
||||
Message: fmt.Sprintf("enter new %s", singular),
|
||||
}
|
||||
var newItem string
|
||||
if err := survey.AskOne(newPrompt, &newItem); err != nil {
|
||||
if err := survey.AskOne(&survey.Input{
|
||||
Message: fmt.Sprintf("enter new %s", strings.TrimSuffix(name, "s")),
|
||||
}, &newItem); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -690,97 +807,6 @@ func promptForStringList(
|
||||
return selected, nil
|
||||
}
|
||||
|
||||
func promptForConfig(config *Nip34Config) error {
|
||||
log("\nenter repository details (use arrow keys to navigate, space to select/deselect, enter to confirm):\n\n")
|
||||
|
||||
// prompt for identifier
|
||||
identifierPrompt := &survey.Input{
|
||||
Message: "identifier",
|
||||
Default: config.Identifier,
|
||||
}
|
||||
if err := survey.AskOne(identifierPrompt, &config.Identifier); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// prompt for name
|
||||
namePrompt := &survey.Input{
|
||||
Message: "name",
|
||||
Default: config.Name,
|
||||
}
|
||||
if err := survey.AskOne(namePrompt, &config.Name); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// prompt for description
|
||||
descPrompt := &survey.Input{
|
||||
Message: "description",
|
||||
Default: config.Description,
|
||||
}
|
||||
if err := survey.AskOne(descPrompt, &config.Description); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// prompt for owner
|
||||
for {
|
||||
ownerPrompt := &survey.Input{
|
||||
Message: "owner (npub or hex)",
|
||||
Default: config.Owner,
|
||||
}
|
||||
if err := survey.AskOne(ownerPrompt, &config.Owner); err != nil {
|
||||
return err
|
||||
}
|
||||
if pubkey, err := parsePubKey(config.Owner); err == nil {
|
||||
config.Owner = pubkey.Hex()
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// prompt for grasp servers
|
||||
graspServers, err := promptForStringList("grasp servers", config.GraspServers, []string{
|
||||
"gitnostr.com",
|
||||
"relay.ngit.dev",
|
||||
"pyramid.fiatjaf.com",
|
||||
"git.shakespeare.dyi",
|
||||
}, graspServerHost, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
config.GraspServers = graspServers
|
||||
|
||||
// prompt for web URLs
|
||||
webURLs, err := promptForStringList("web URLs", config.Web, []string{
|
||||
fmt.Sprintf("https://gitworkshop.dev/%s/%s",
|
||||
nip19.EncodeNpub(nostr.MustPubKeyFromHex(config.Owner)),
|
||||
config.Identifier,
|
||||
),
|
||||
}, func(s string) string {
|
||||
return "http" + nostr.NormalizeURL(s)[2:]
|
||||
}, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
config.Web = webURLs
|
||||
|
||||
// Prompt for maintainers
|
||||
maintainers, err := promptForStringList("maintainers", config.Maintainers, []string{}, nil, func(s string) bool {
|
||||
pk, err := parsePubKey(s)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
if pk.Hex() == config.Owner {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
config.Maintainers = maintainers
|
||||
|
||||
log("\n")
|
||||
return nil
|
||||
}
|
||||
|
||||
func gitSync(ctx context.Context, signer nostr.Keyer) (nip34.Repository, *nip34.RepositoryState, error) {
|
||||
// read current nip34.json
|
||||
localConfig, err := readNip34ConfigFile("")
|
||||
@@ -914,7 +940,7 @@ func gitSync(ctx context.Context, signer nostr.Keyer) (nip34.Repository, *nip34.
|
||||
func fetchFromRemotes(ctx context.Context, targetDir string, repo nip34.Repository) {
|
||||
// fetch from each grasp remote
|
||||
for _, grasp := range repo.Relays {
|
||||
remoteName := "nip34/grasp/" + strings.Split(grasp, "/")[2]
|
||||
remoteName := gitRemoteName(grasp)
|
||||
|
||||
logverbose("fetching from %s...\n", remoteName)
|
||||
fetchCmd := exec.Command("git", "fetch", remoteName)
|
||||
@@ -940,14 +966,16 @@ func gitSetupRemotes(ctx context.Context, dir string, repo nip34.Repository) {
|
||||
return
|
||||
}
|
||||
|
||||
// delete all nip34/grasp/ remotes
|
||||
// delete all nip34/grasp/ remotes that we don't have anymore in repo
|
||||
remotes := strings.Split(strings.TrimSpace(string(output)), "\n")
|
||||
for i, remote := range remotes {
|
||||
remote = strings.TrimSpace(remote)
|
||||
remotes[i] = remote
|
||||
|
||||
if strings.HasPrefix(remote, "nip34/grasp/") {
|
||||
if !slices.Contains(repo.Relays, nostr.NormalizeURL(remote[12:])) {
|
||||
graspURL := rebuildGraspURLFromRemote(remote)
|
||||
|
||||
if !slices.Contains(repo.Relays, nostr.NormalizeURL(graspURL)) {
|
||||
delCmd := exec.Command("git", "remote", "remove", remote)
|
||||
if dir != "" {
|
||||
delCmd.Dir = dir
|
||||
@@ -961,7 +989,7 @@ func gitSetupRemotes(ctx context.Context, dir string, repo nip34.Repository) {
|
||||
|
||||
// create new remotes for each grasp server
|
||||
for _, relay := range repo.Relays {
|
||||
remote := "nip34/grasp/" + strings.TrimPrefix(relay, "wss://")
|
||||
remote := gitRemoteName(relay)
|
||||
|
||||
if !slices.Contains(remotes, remote) {
|
||||
// construct the git URL
|
||||
@@ -1367,8 +1395,6 @@ func figureOutBranches(c *cli.Command, refspec string, isPush bool) (
|
||||
return localBranch, remoteBranch, nil
|
||||
}
|
||||
|
||||
func graspServerHost(s string) string { return strings.SplitN(nostr.NormalizeURL(s), "/", 3)[2] }
|
||||
|
||||
type Nip34Config struct {
|
||||
Identifier string `json:"identifier"`
|
||||
Name string `json:"name"`
|
||||
@@ -1380,6 +1406,26 @@ type Nip34Config struct {
|
||||
Maintainers []string `json:"maintainers"`
|
||||
}
|
||||
|
||||
func RepositoryToConfig(repo nip34.Repository) Nip34Config {
|
||||
config := Nip34Config{
|
||||
Identifier: repo.ID,
|
||||
Name: repo.Name,
|
||||
Description: repo.Description,
|
||||
Web: repo.Web,
|
||||
Owner: nip19.EncodeNpub(repo.Event.PubKey),
|
||||
GraspServers: make([]string, 0, len(repo.Relays)),
|
||||
EarliestUniqueCommit: repo.EarliestUniqueCommitID,
|
||||
Maintainers: make([]string, 0, len(repo.Maintainers)),
|
||||
}
|
||||
for _, r := range repo.Relays {
|
||||
config.GraspServers = append(config.GraspServers, graspServerHost(r))
|
||||
}
|
||||
for _, m := range repo.Maintainers {
|
||||
config.Maintainers = append(config.Maintainers, nip19.EncodeNpub(m))
|
||||
}
|
||||
return config
|
||||
}
|
||||
|
||||
func (localConfig Nip34Config) Validate() error {
|
||||
_, err := parsePubKey(localConfig.Owner)
|
||||
if err != nil {
|
||||
@@ -1430,3 +1476,18 @@ func (localConfig Nip34Config) ToRepository() nip34.Repository {
|
||||
|
||||
return localRepo
|
||||
}
|
||||
|
||||
func gitRemoteName(graspURL string) string {
|
||||
host := graspServerHost(graspURL)
|
||||
host = strings.Replace(host, ":", "__", 1)
|
||||
return "nip34/grasp/" + host
|
||||
}
|
||||
|
||||
func rebuildGraspURLFromRemote(remoteName string) string {
|
||||
host := strings.TrimPrefix(remoteName, "nip34/grasp/")
|
||||
return strings.Replace(host, "__", ":", 1)
|
||||
}
|
||||
|
||||
func graspServerHost(s string) string {
|
||||
return strings.SplitN(nostr.NormalizeURL(s), "/", 3)[2]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user