diff options
author | ᴜɴᴋɴᴡᴏɴ <u@gogs.io> | 2020-03-10 22:15:55 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-03-10 22:15:55 +0800 |
commit | 880d0ec19f488001a90b3e370a992eaabac89e70 (patch) | |
tree | 97bcb926b3c94f56cc0367a7a405df1a2d6ad06a /internal/route/api/v1/repo | |
parent | 2430612ad4190fe81bfb8b64c92fe1883188f856 (diff) |
api: overhaul `/repos/owner/repos/contents` (#5980)
* Fix import path renaming
* api: overhaul /repos/owner/repos/contents
Diffstat (limited to 'internal/route/api/v1/repo')
-rw-r--r-- | internal/route/api/v1/repo/contents.go | 251 |
1 files changed, 115 insertions, 136 deletions
diff --git a/internal/route/api/v1/repo/contents.go b/internal/route/api/v1/repo/contents.go index 40303921..e5a9277d 100644 --- a/internal/route/api/v1/repo/contents.go +++ b/internal/route/api/v1/repo/contents.go @@ -7,128 +7,141 @@ package repo import ( "encoding/base64" "fmt" + "path" + + "github.com/gogs/git-module" + "github.com/pkg/errors" "gogs.io/gogs/internal/context" "gogs.io/gogs/internal/gitutil" ) -type repoContent struct { - Type string `json:"type"` - Target string `json:"target,omitempty"` - SubmoduleGitURL string `json:"submodule_git_url,omitempty"` - Encoding string `json:"encoding,omitempty"` - Size int64 `json:"size"` - Name string `json:"name"` - Path string `json:"path"` - Content string `json:"content,omitempty"` - Sha string `json:"sha"` - URL string `json:"url"` - GitURL string `json:"git_url"` - HTMLURL string `json:"html_url"` - DownloadURL string `json:"download_url"` - Links Links `json:"_links"` -} +func GetContents(c *context.APIContext) { + gitRepo, err := git.Open(c.Repo.Repository.RepoPath()) + if err != nil { + c.ServerError("open repository", err) + return + } -type Links struct { - Git string `json:"git"` - Self string `json:"self"` - HTML string `json:"html"` -} + ref := c.Query("ref") + if ref == "" { + ref = c.Repo.Repository.DefaultBranch + } -func GetContents(c *context.APIContext) { - treeEntry, err := c.Repo.Commit.TreeEntry(c.Repo.TreePath) + commit, err := gitRepo.CatFileCommit(ref) + if err != nil { + c.NotFoundOrServerError("get commit", gitutil.IsErrRevisionNotExist, err) + return + } + + treePath := c.Params("*") + entry, err := commit.TreeEntry(treePath) if err != nil { c.NotFoundOrServerError("get tree entry", gitutil.IsErrRevisionNotExist, err) return } - username := c.Params(":username") - reponame := c.Params(":reponame") - - // TODO: figure out the best way to do this - // :base-url/:username/:project/raw/:refs/:path - templateDownloadURL := "%s/%s/%s/raw/%s" - // :base-url/repos/:username/:project/contents/:path - templateSelfLink := "%s/repos/%s/%s/contents/%s" - // :baseurl/repos/:username/:project/git/trees/:sha - templateGitURLLink := "%s/repos/%s/%s/trees/%s" - // :baseurl/repos/:username/:project/tree/:sha - templateHTMLLLink := "%s/repos/%s/%s/tree/%s" - - gitURL := fmt.Sprintf(templateGitURLLink, c.BaseURL, username, reponame, treeEntry.ID().String()) - htmlURL := fmt.Sprintf(templateHTMLLLink, c.BaseURL, username, reponame, treeEntry.ID().String()) - selfURL := fmt.Sprintf(templateSelfLink, c.BaseURL, username, reponame, c.Repo.TreePath) - - // TODO(unknwon): Make a treeEntryToRepoContent helper. - contents := &repoContent{ - Size: treeEntry.Size(), - Name: treeEntry.Name(), - Path: c.Repo.TreePath, - Sha: treeEntry.ID().String(), - URL: selfURL, - GitURL: gitURL, - HTMLURL: htmlURL, - DownloadURL: fmt.Sprintf(templateDownloadURL, c.BaseURL, username, reponame, c.Repo.TreePath), - Links: Links{ - Git: gitURL, - Self: selfURL, - HTML: htmlURL, - }, + + type links struct { + Git string `json:"git"` + Self string `json:"self"` + HTML string `json:"html"` + } + type repoContent struct { + Type string `json:"type"` + Target string `json:"target,omitempty"` + SubmoduleGitURL string `json:"submodule_git_url,omitempty"` + Encoding string `json:"encoding,omitempty"` + Size int64 `json:"size"` + Name string `json:"name"` + Path string `json:"path"` + Content string `json:"content,omitempty"` + Sha string `json:"sha"` + URL string `json:"url"` + GitURL string `json:"git_url"` + HTMLURL string `json:"html_url"` + DownloadURL string `json:"download_url"` + Links links `json:"_links"` } - // A tree entry can only be one of the following types: - // 1. Tree (directory) - // 2. SubModule - // 3. SymLink - // 4. Blob (file) - if treeEntry.IsCommit() { - // TODO(unknwon): submoduleURL is not set as current git-module doesn't handle it properly - contents.Type = "submodule" - c.JSONSuccess(contents) - return + toRepoContent := func(subpath string, entry *git.TreeEntry) (*repoContent, error) { + repoURL := fmt.Sprintf("%s/repos/%s/%s", c.BaseURL, c.Params(":username"), c.Params(":reponame")) + selfURL := fmt.Sprintf("%s/contents/%s", repoURL, subpath) + htmlURL := fmt.Sprintf("%s/src/%s/%s", c.Repo.Repository.HTMLURL(), ref, entry.Name()) + downloadURL := fmt.Sprintf("%s/raw/%s/%s", c.Repo.Repository.HTMLURL(), ref, entry.Name()) - } else if treeEntry.IsSymlink() { - contents.Type = "symlink" - blob, err := c.Repo.Commit.Blob(c.Repo.TreePath) - if err != nil { - c.ServerError("GetBlobByPath", err) - return - } - p, err := blob.Bytes() - if err != nil { - c.ServerError("Data", err) - return + content := &repoContent{ + Size: entry.Size(), + Name: entry.Name(), + Path: subpath, + Sha: entry.ID().String(), + URL: selfURL, + HTMLURL: htmlURL, + DownloadURL: downloadURL, + Links: links{ + Self: selfURL, + HTML: htmlURL, + }, } - contents.Target = string(p) - c.JSONSuccess(contents) - return - } else if treeEntry.IsBlob() { - blob, err := c.Repo.Commit.Blob(c.Repo.TreePath) - if err != nil { - c.ServerError("GetBlobByPath", err) - return + switch { + case entry.IsBlob(), entry.IsExec(): + content.Type = "file" + p, err := entry.Blob().Bytes() + if err != nil { + return nil, errors.Wrap(err, "get blob content") + } + content.Encoding = "base64" + content.Content = base64.StdEncoding.EncodeToString(p) + content.GitURL = fmt.Sprintf("%s/git/blobs/%s", repoURL, entry.ID().String()) + + case entry.IsTree(): + content.Type = "dir" + content.GitURL = fmt.Sprintf("%s/git/trees/%s", repoURL, entry.ID().String()) + + case entry.IsSymlink(): + content.Type = "symlink" + p, err := entry.Blob().Bytes() + if err != nil { + return nil, errors.Wrap(err, "get blob content") + } + content.Target = string(p) + + case entry.IsCommit(): + content.Type = "submodule" + mod, err := commit.Submodule(subpath) + if err != nil { + return nil, errors.Wrap(err, "get submodule") + } + content.SubmoduleGitURL = mod.URL + + default: + panic("unreachable") } - p, err := blob.Bytes() + + content.Links.Git = content.GitURL + + return content, nil + } + + if !entry.IsTree() { + content, err := toRepoContent(treePath, entry) if err != nil { - c.ServerError("Data", err) + c.Errorf(err, "convert %q to repoContent", treePath) return } - contents.Content = base64.StdEncoding.EncodeToString(p) - contents.Type = "file" - c.JSONSuccess(contents) + + c.JSONSuccess(content) return } - // TODO: treeEntry.IsExec() - - // treeEntry is a directory - dirTree, err := c.Repo.GitRepo.LsTree(treeEntry.ID().String()) + // The entry is a directory + dir, err := gitRepo.LsTree(entry.ID().String()) if err != nil { c.NotFoundOrServerError("get tree", gitutil.IsErrRevisionNotExist, err) return } - entries, err := dirTree.Entries() + entries, err := dir.Entries() if err != nil { c.NotFoundOrServerError("list entries", gitutil.IsErrRevisionNotExist, err) return @@ -139,50 +152,16 @@ func GetContents(c *context.APIContext) { return } - var results = make([]*repoContent, 0, len(entries)) + contents := make([]*repoContent, 0, len(entries)) for _, entry := range entries { - gitURL := fmt.Sprintf(templateGitURLLink, c.BaseURL, username, reponame, entry.ID().String()) - htmlURL := fmt.Sprintf(templateHTMLLLink, c.BaseURL, username, reponame, entry.ID().String()) - selfURL := fmt.Sprintf(templateSelfLink, c.BaseURL, username, reponame, c.Repo.TreePath) - var contentType string - if entry.IsTree() { - contentType = "dir" - } else if entry.IsCommit() { - // TODO(unknwon): submoduleURL is not set as current git-module doesn't handle it properly - contentType = "submodule" - } else if entry.IsSymlink() { - contentType = "symlink" - blob, err := c.Repo.Commit.Blob(c.Repo.TreePath) - if err != nil { - c.ServerError("GetBlobByPath", err) - return - } - p, err := blob.Bytes() - if err != nil { - c.ServerError("Data", err) - return - } - contents.Target = string(p) - } else { - contentType = "file" + subpath := path.Join(treePath, entry.Name()) + content, err := toRepoContent(subpath, entry) + if err != nil { + c.Errorf(err, "convert %q to repoContent", subpath) + return } - results = append(results, &repoContent{ - Type: contentType, - Size: entry.Size(), - Name: entry.Name(), - Path: c.Repo.TreePath, - Sha: entry.ID().String(), - URL: selfURL, - GitURL: gitURL, - HTMLURL: htmlURL, - DownloadURL: fmt.Sprintf(templateDownloadURL, c.BaseURL, username, reponame, c.Repo.TreePath), - Links: Links{ - Git: gitURL, - Self: selfURL, - HTML: htmlURL, - }, - }) + contents = append(contents, content) } - c.JSONSuccess(results) + c.JSONSuccess(contents) } |