AuraRepo > Tree [f8c6941]
/context.go/
package aurarepo
import (
"bufio"
"errors"
"fmt"
"net/url"
"path/filepath"
"strconv"
"strings"
"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing/format/diff"
sis "gitlab.com/sis-suite/smallnetinformationservices"
"gitlab.com/sis-suite/smallnetinformationservices/bitset"
)
type AuraRepoType uint
const (
AuraRepoType_Git AuraRepoType = iota
AuraRepoType_Prism
)
// The features enabled on the application server
type AuraRepoFeature uint
const (
AuraRepoFeature_Users_Groups AuraRepoFeature = iota
AuraRepoFeature_Registration
AuraRepoFeature_Private_Internal
AuraRepoFeature_Releases
AuraRepoFeature_Issues
AuraRepoFeature_PRs
AuraRepoFeature_Projects
AuraRepoFeature_Forks
AuraRepoFeature_Docs
AuraRepoFeature_AutoMirror
AuraRepoFeature_LFS
AuraRepoFeature_Wiki
AuraRepoFeature_Pages
AuraRepoFeature_Email
AuraRepoFeature_Misfin
)
type AuraRepoContext struct {
title string
repos map[string]*Repo
repos_directory string
http_clone_prefix string
//repo *git.Repository // TODO: Set config values, like committer/user (for when repo is modified in interface).
enabled_features bitset.BitSet[AuraRepoFeature, AuraRepoFeature]
}
type Repo struct {
*git.Repository
Type AuraRepoType
Id string // Could be just repo name, or username/repo_name in multi-user system
Title string
Path string // Relative to AuraRepoContext.repos_directory
Description string
}
func (repo *Repo) EscapedId() string {
return url.PathEscape(repo.Id)
}
func NewAuraRepoContext(title string, directory string, http_clone_prefix string) *AuraRepoContext {
context := &AuraRepoContext{title: title, repos_directory: directory}
context.repos = make(map[string]*Repo)
/*var err error
context.repo, err = git.PlainOpen("./test-repo/")
if errors.Is(err, git.ErrRepositoryNotExists) {
context.repo, err = git.PlainInit("./test-repo/", true)
}*/
/*c := config.NewConfig()
c.Core.IsBare = true
c.Init.DefaultBranch = "main"
c.Branches["main"] = &config.Branch{Name: "main"}
context.repo.SetConfig(c)*/
return context
}
// Given path is relative to repos directory.
func (c *AuraRepoContext) AddRepo(t AuraRepoType, id string, title string, path string, description string) (*Repo, error) {
var gitRepo *git.Repository = nil
if t == AuraRepoType_Git {
var err error
gitRepo, err = git.PlainOpen(filepath.Join(c.repos_directory, path))
if errors.Is(err, git.ErrRepositoryNotExists) {
gitRepo, err = git.PlainInit(filepath.Join(c.repos_directory, path), true)
if err != nil {
return nil, err
}
}
}
r := &Repo{Repository: gitRepo, Type: t, Title: title, Id: id, Path: path, Description: description}
c.repos[id] = r
return r, nil
}
func (c *AuraRepoContext) Attach(s sis.ServeMux) {
s.AddRoute("/", c.Homepage)
repoGroup := s.Group("/:reponame/")
repoGroup.AddRoute("/", func(request *sis.Request) {
if !strings.HasSuffix(request.Path(), "/") {
request.Redirect("/")
return
}
repo := c.repos[request.GetParam("reponame")]
if repo.Type == AuraRepoType_Git {
c.GitRepoHomepage(request, repo)
} else if repo.Type == AuraRepoType_Prism {
c.PrismRepoHomepage(request, repo)
}
})
repoGroup.AddRoute("/branches/", func(request *sis.Request) {
repo := c.repos[request.GetParam("reponame")]
if repo.Type == AuraRepoType_Git {
c.GitRepoBranches(request, repo)
} else if repo.Type == AuraRepoType_Prism {
c.PrismRepoBranches(request, repo)
}
})
repoGroup.AddRoute("/tags/", func(request *sis.Request) {
repo := c.repos[request.GetParam("reponame")]
if repo.Type == AuraRepoType_Git {
c.GitRepoTags(request, repo)
} else if repo.Type == AuraRepoType_Prism {
c.PrismRepoTags(request, repo)
}
})
repoGroup.AddRoute("/commit/:ref", func(request *sis.Request) {
repo := c.repos[request.GetParam("reponame")]
if repo.Type == AuraRepoType_Git {
c.GitRepoCommitDetails(request, repo)
} else if repo.Type == AuraRepoType_Prism {
c.PrismRepoCommitDetails(request, repo)
}
})
repoGroup.AddRoute("/commits/*", func(request *sis.Request) {
repo := c.repos[request.GetParam("reponame")]
if repo.Type == AuraRepoType_Git {
c.GitRepoCommitsRedirect(request, repo)
} else if repo.Type == AuraRepoType_Prism {
c.PrismRepoCommitsRedirect(request, repo)
}
})
repoGroup.AddRoute("/commits/:ref/*", func(request *sis.Request) {
repo := c.repos[request.GetParam("reponame")]
if repo.Type == AuraRepoType_Git {
c.GitRepoCommitsList(request, repo)
} else if repo.Type == AuraRepoType_Prism {
c.PrismRepoCommitsList(request, repo)
}
})
repoGroup.AddRoute("/notes/", func(request *sis.Request) {
repo := c.repos[request.GetParam("reponame")]
if repo.Type == AuraRepoType_Git {
c.GitRepoNotespaces(request, repo)
} else if repo.Type == AuraRepoType_Prism {
c.PrismRepoNotespaces(request, repo)
}
})
repoGroup.AddRoute("/notes/:name", func(request *sis.Request) {
repo := c.repos[request.GetParam("reponame")]
if repo.Type == AuraRepoType_Git {
c.GitRepoNotespaceNotes(request, repo)
} else if repo.Type == AuraRepoType_Prism {
c.PrismRepoNotespaceNotes(request, repo)
}
})
repoGroup.AddRoute("/tree/:ref/*", func(request *sis.Request) {
repo := c.repos[request.GetParam("reponame")]
if repo.Type == AuraRepoType_Git {
c.GitRepoTree(request, repo)
} else if repo.Type == AuraRepoType_Prism {
c.PrismRepoTree(request, repo)
}
})
repoGroup.AddRoute("/blob/:ref/*", func(request *sis.Request) {
repo := c.repos[request.GetParam("reponame")]
if repo.Type == AuraRepoType_Git {
c.GitRepoBlob(request, repo)
} else if repo.Type == AuraRepoType_Prism {
c.PrismRepoBlob(request, repo)
}
})
repoGroup.AddRoute("/blame/:ref/*", func(request *sis.Request) {
repo := c.repos[request.GetParam("reponame")]
if repo.Type == AuraRepoType_Git {
c.GitRepoBlame(request, repo)
} else if repo.Type == AuraRepoType_Prism {
c.PrismRepoBlame(request, repo)
}
})
repoGroup.AddRoute("/raw/:ref/*", func(request *sis.Request) {
repo := c.repos[request.GetParam("reponame")]
if repo.Type == AuraRepoType_Git {
c.GitRepoRaw(request, repo)
} else if repo.Type == AuraRepoType_Prism {
c.PrismRepoRaw(request, repo)
}
})
repoGroup.AddRoute("/archive/refs/heads/:name", func(request *sis.Request) {
repo := c.repos[request.GetParam("reponame")]
if repo.Type == AuraRepoType_Git {
c.GitRepoArchiveHead(request, repo)
} else if repo.Type == AuraRepoType_Prism {
c.PrismRepoArchiveHead(request, repo)
}
})
repoGroup.AddRoute("/archive/refs/tags/:name", func(request *sis.Request) {
repo := c.repos[request.GetParam("reponame")]
if repo.Type == AuraRepoType_Git {
c.GitRepoArchiveTag(request, repo)
} else if repo.Type == AuraRepoType_Prism {
c.PrismRepoArchiveTag(request, repo)
}
})
repoGroup.AddRoute("/wiki/*", func(request *sis.Request) {
if strings.HasSuffix(request.Path(), "wiki") {
request.Redirect("wiki/")
return
}
repo := c.repos[request.GetParam("reponame")]
if repo.Type == AuraRepoType_Git {
c.GitRepoWiki(request, repo)
} else if repo.Type == AuraRepoType_Prism {
c.PrismRepoWiki(request, repo)
}
})
}
func (c *AuraRepoContext) Homepage(request *sis.Request) {
request.Gemini(fmt.Sprintf("# %s\n\n", c.title))
// List all repos
for _, repo := range c.repos {
request.Link("/"+repo.EscapedId()+"/", repo.Title)
request.Gemini(fmt.Sprintf("> %s\n", repo.Description))
request.Gemini("\n")
}
}
func GetLastFiveLinesOfString(content string) string {
if len(content) < 100 { // For small contents, keep original approach
return content
} else {
lastNewlines := 0
i := len(content) - 1
startPos := i
// Scan backwards until we find 5 newlines
for i >= 0 && lastNewlines < 6 {
if content[i] == '\n' {
lastNewlines++
if lastNewlines == 6 {
startPos = i + 1
break
}
}
i--
}
if lastNewlines < 6 {
return content
} else {
return content[startPos:]
}
}
}
func GetFirstFiveLinesOfString(content string) string {
if len(content) < 100 { // For small contents, return all
return content
} else {
nextNewlines := 0
i := 0
endPos := len(content) - 1
// Scan forwards until we find 5 newlines
for i < len(content) && nextNewlines < 5 {
if content[i] == '\n' {
nextNewlines++
if nextNewlines == 5 {
endPos = i + 1
break
}
}
i++
}
if nextNewlines < 5 {
return content
} else {
return content[:endPos]
}
}
}
func PrintIndentedLinesFromNumber(request *sis.Request, content string, startLine int, operation diff.Operation) {
prefix := " "
if operation == diff.Add {
prefix = "+"
} else if operation == diff.Delete {
prefix = "-"
}
scanner := bufio.NewScanner(strings.NewReader(content))
lineNum := startLine
for scanner.Scan() {
request.PlainText("%s%5s | %s\n", prefix, strconv.Itoa(lineNum), scanner.Text())
lineNum++
}
}