From f1a153a78213bfa33bb070c05580a916ffc1e9e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Ri=C3=9Fe?= Date: Fri, 9 Aug 2024 11:51:11 +0000 Subject: [PATCH] Improve views for annexed but missing files (#28) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, trying to view files that were annexed, but missing, just led to an uninformative error 500. This was rather confusing. With these changes it now shows the pointer target instead of the (missing) content of the file, and also indicates this situation in the "stored with git-annex" message. For semantic correctness views for missing files return a 404 instead of a 200, as they would with the content present. Fixes #7, fixes #13. Reviewed-on: https://codeberg.org/matrss/forgejo-aneksajo/pulls/28 Co-authored-by: Matthias Riße Co-committed-by: Matthias Riße --- options/locale/locale_de-DE.ini | 1 + options/locale/locale_en-US.ini | 1 + routers/web/repo/view.go | 54 +++++++++++++++++++++++---------- templates/repo/file_info.tmpl | 2 +- 4 files changed, 41 insertions(+), 17 deletions(-) diff --git a/options/locale/locale_de-DE.ini b/options/locale/locale_de-DE.ini index 5b8f115b63..04de4f26c3 100644 --- a/options/locale/locale_de-DE.ini +++ b/options/locale/locale_de-DE.ini @@ -1304,6 +1304,7 @@ video_not_supported_in_browser=Dein Browser unterstützt das HTML5-„video“-T audio_not_supported_in_browser=Dein Browser unterstützt das HTML5-„audio“-Tag nicht. stored_lfs=Gespeichert mit Git LFS stored_annex=Gespeichert mit Git Annex +stored_annex_not_present = hier nicht vorhanden, versuche git annex whereis symbolic_link=Softlink executable_file=Ausführbare Datei commit_graph=Commit-Graph diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 2d2dcfdd9c..439617cead 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -1306,6 +1306,7 @@ video_not_supported_in_browser = Your browser does not support the HTML5 "video" audio_not_supported_in_browser = Your browser does not support the HTML5 "audio" tag. stored_lfs = Stored with Git LFS stored_annex = Stored with Git Annex +stored_annex_not_present = not present here, try using git annex whereis symbolic_link = Symbolic link executable_file = Executable file vendored = Vendored diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go index ec02b0ea45..e3d52b2dc3 100644 --- a/routers/web/repo/view.go +++ b/routers/web/repo/view.go @@ -209,12 +209,13 @@ func localizedExtensions(ext, languageCode string) (localizedExts []string) { } type fileInfo struct { - isTextFile bool - isLFSFile bool - isAnnexFile bool - fileSize int64 - lfsMeta *lfs.Pointer - st typesniffer.SniffedType + isTextFile bool + isLFSFile bool + isAnnexFile bool + isAnnexFilePresent bool + fileSize int64 + lfsMeta *lfs.Pointer + st typesniffer.SniffedType } func getFileReader(ctx gocontext.Context, repoID int64, blob *git.Blob) ([]byte, io.ReadCloser, *fileInfo, error) { @@ -229,11 +230,22 @@ func getFileReader(ctx gocontext.Context, repoID int64, blob *git.Blob) ([]byte, annexContent, err := annex.Content(blob) if err != nil { - // in the case where annex content is missing, what should happen? - // do we render the page with an error message? - // actually that's not a bad idea, there's some sort of error message situation - // TODO: display an error to the user explaining that their data is missing - return nil, nil, nil, err + // If annex.Content returns an error it can mean that the blob does not + // refer to an annexed file or that it is not present here. Since we already + // checked that it is annexed the latter must be the case. So we return the + // content of the blob instead and indicate that the file is indeed annexed, + // but not present here. The template can then communicate the situation. + dataRc, err := blob.DataAsync() + if err != nil { + return nil, nil, nil, err + } + + buf := make([]byte, 1024) + n, _ := util.ReadAtMost(dataRc, buf) + buf = buf[:n] + + st := typesniffer.DetectContentType(buf) + return buf, dataRc, &fileInfo{st.IsText(), false, true, false, blob.Size(), nil, st}, nil } stat, err := annexContent.Stat() @@ -247,7 +259,7 @@ func getFileReader(ctx gocontext.Context, repoID int64, blob *git.Blob) ([]byte, st := typesniffer.DetectContentType(buf) - return buf, annexContent, &fileInfo{st.IsText(), false, true, stat.Size(), nil, st}, nil + return buf, annexContent, &fileInfo{st.IsText(), false, true, true, stat.Size(), nil, st}, nil } dataRc, err := blob.DataAsync() @@ -264,17 +276,17 @@ func getFileReader(ctx gocontext.Context, repoID int64, blob *git.Blob) ([]byte, // FIXME: what happens when README file is an image? if !isTextFile || !setting.LFS.StartServer { - return buf, dataRc, &fileInfo{isTextFile, false, false, blob.Size(), nil, st}, nil + return buf, dataRc, &fileInfo{isTextFile, false, false, false, blob.Size(), nil, st}, nil } pointer, _ := lfs.ReadPointerFromBuffer(buf) if !pointer.IsValid() { // fallback to plain file - return buf, dataRc, &fileInfo{isTextFile, false, false, blob.Size(), nil, st}, nil + return buf, dataRc, &fileInfo{isTextFile, false, false, false, blob.Size(), nil, st}, nil } meta, err := git_model.GetLFSMetaObjectByOid(ctx, repoID, pointer.Oid) if err != nil && err != git_model.ErrLFSObjectNotExist { // fallback to plain file - return buf, dataRc, &fileInfo{isTextFile, false, false, blob.Size(), nil, st}, nil + return buf, dataRc, &fileInfo{isTextFile, false, false, false, blob.Size(), nil, st}, nil } dataRc.Close() @@ -297,7 +309,7 @@ func getFileReader(ctx gocontext.Context, repoID int64, blob *git.Blob) ([]byte, st = typesniffer.DetectContentType(buf) - return buf, dataRc, &fileInfo{st.IsText(), true, false, meta.Size, &meta.Pointer, st}, nil + return buf, dataRc, &fileInfo{st.IsText(), true, false, false, meta.Size, &meta.Pointer, st}, nil } func renderReadmeFile(ctx *context.Context, subfolder string, readmeFile *git.TreeEntry) { @@ -498,6 +510,7 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry) { } ctx.Data["IsLFSFile"] = fInfo.isLFSFile ctx.Data["IsAnnexFile"] = fInfo.isAnnexFile + ctx.Data["IsAnnexFilePresent"] = fInfo.isAnnexFilePresent ctx.Data["FileSize"] = fInfo.fileSize ctx.Data["IsTextFile"] = fInfo.isTextFile ctx.Data["IsRepresentableAsText"] = isRepresentableAsText @@ -1194,6 +1207,15 @@ PostRecentBranchCheck: ctx.Data["TreeNames"] = treeNames ctx.Data["BranchLink"] = branchLink ctx.Data["CodeIndexerDisabled"] = !setting.Indexer.RepoIndexerEnabled + isAnnexFile, okAnnexFile := ctx.Data["IsAnnexFile"] + isAnnexFilePresent, okAnnexFilePresent := ctx.Data["IsAnnexFilePresent"] + if okAnnexFile && okAnnexFilePresent && isAnnexFile.(bool) && !isAnnexFilePresent.(bool) { + // If the file to be viewed is annexed but not present then render it normally + // (which will show the plain git blob content, i.e. the symlink or pointer target) + // but make the status code a 404. + ctx.HTML(http.StatusNotFound, tplRepoHome) + return + } ctx.HTML(http.StatusOK, tplRepoHome) } diff --git a/templates/repo/file_info.tmpl b/templates/repo/file_info.tmpl index 05d9825cfb..8655404394 100644 --- a/templates/repo/file_info.tmpl +++ b/templates/repo/file_info.tmpl @@ -17,7 +17,7 @@ {{if .FileSize}}
{{ctx.Locale.TrSize .FileSize}}{{if .IsLFSFile}} ({{ctx.Locale.Tr "repo.stored_lfs"}}){{end}} - {{if .IsAnnexFile}} ({{ctx.Locale.Tr "repo.stored_annex"}}){{end}} + {{if .IsAnnexFile}} ({{ctx.Locale.Tr "repo.stored_annex"}}{{if not .IsAnnexFilePresent}} - {{ctx.Locale.Tr "repo.stored_annex_not_present"}}{{end}}){{end}}
{{end}} {{if .LFSLock}}