diff --git a/routers/hat/hat.go b/routers/hat/hat.go index fdae4d2..837de5b 100644 --- a/routers/hat/hat.go +++ b/routers/hat/hat.go @@ -132,6 +132,7 @@ func Routers(ctx gocontext.Context) *web.Route { m.Post("", bind(hat_api.BatchChangeFileOptions{}), repo.BatchChangeFile) }, reqRepoWriter(unit.TypeCode), reqToken()) }, reqRepoReader(unit.TypeCode)) + m.Get("/find", reqRepoReader(unit.TypeCode), repo.FindFiles) m.Group("/git", func() { m.Group("/commits", func() { m.Get("/{sha}", repo.GetSingleCommit) diff --git a/routers/hat/repo/file.go b/routers/hat/repo/file.go index 05dee17..4be468a 100644 --- a/routers/hat/repo/file.go +++ b/routers/hat/repo/file.go @@ -4,6 +4,8 @@ import ( "encoding/base64" "fmt" "net/http" + "net/url" + "path/filepath" "strings" "time" @@ -246,3 +248,116 @@ func GetContents(ctx *context.APIContext) { func GetContentsList(ctx *context.APIContext) { GetContents(ctx) } + +func FindFiles(ctx *context.APIContext) { + treePath := ctx.Repo.TreePath + + ref := ctx.FormString("ref") + if ref == "" { + ref = ctx.Repo.Repository.DefaultBranch + } + + keyWords := ctx.FormString("q") + var fileList []*SearchFileItem + var err error + if keyWords != "" { + fileList, err = FindFileFromPath(ctx, treePath, ref, keyWords) + if err != nil { + ctx.Error(http.StatusInternalServerError, "FindFileFromPath", err) + return + } + } + ctx.JSON(http.StatusOK, fileList) +} + +type SearchFileItem struct { + Name string `json:"name"` + Path string `json:"path"` + SHA string `json:"sha"` + Type string `json:"type"` + Size int64 `json:"size"` + URL *string `json:"url"` + HTMLURL *string `json:"html_url"` +} + +func FindFileFromPath(ctx *context.APIContext, treePath, ref, key string) (fileList []*SearchFileItem, err error) { + if ctx.Repo.GitRepo == nil { + ctx.Repo.GitRepo, err = git.OpenRepository(ctx, ctx.Repo.Repository.RepoPath()) + if err != nil { + ctx.ServerError("OpenRepository", err) + return nil, err + } + defer func() { + if ctx.Repo.GitRepo != nil { + ctx.Repo.GitRepo.Close() + } + }() + } + // get the commit object for the ref + commit, err := ctx.Repo.GitRepo.GetCommit(ref) + if err != nil { + ctx.ServerError("GetCommit", err) + return nil, err + } + tree, err2 := commit.SubTree(treePath) + if err2 != nil { + ctx.ServerError("SubTree", err) + return nil, err2 + } + entries, err3 := tree.ListEntriesRecursiveFast() + if err3 != nil { + ctx.ServerError("ListEntries", err3) + return nil, err3 + } + fileList = make([]*SearchFileItem, 0, 0) + + for _, entry := range entries { + if entry.IsDir() { + continue + } + filename := filepath.Base(entry.Name()) + if strings.Contains(strings.ToLower(filename), strings.ToLower(key)) || key == "" { + name := entry.Name() + treePath = name + + selfURL, err := url.Parse(fmt.Sprintf("%s/contents/%s?ref=%s", ctx.Repo.Repository.APIURL(), treePath, ref)) + if err != nil { + return nil, err + } + selfURLString := selfURL.String() + + refType := ctx.Repo.GitRepo.GetRefType(ref) + if refType == "invalid" { + return nil, fmt.Errorf("no commit found for the ref [ref: %s]", ref) + } + htmlURL, err := url.Parse(fmt.Sprintf("%s/src/%s/%s/%s", ctx.Repo.Repository.HTMLURL(), refType, ref, treePath)) + if err != nil { + return nil, err + } + htmlURLString := htmlURL.String() + item := &SearchFileItem{ + Name: filename, + Path: treePath, + SHA: entry.ID.String(), + Type: entry.Type(), + Size: entry.Size(), + URL: &selfURLString, + HTMLURL: &htmlURLString, + } + // Now populate the rest of the ContentsResponse based on entry type + if entry.IsRegular() || entry.IsExecutable() { + item.Type = "file" + } else if entry.IsDir() { + item.Type = "dir" + } else if entry.IsLink() { + item.Type = "symlink" + } else if entry.IsSubModule() { + item.Type = "submodule" + } + fileList = append(fileList, item) + + } + } + return + +}