Convert octal notation file names in Git (#380)

This commit is contained in:
Thomas Miceli 2024-11-17 18:09:44 +01:00 committed by GitHub
parent 92bac3bf8c
commit c1e046f428
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 64 additions and 11 deletions

View file

@ -6,6 +6,7 @@ import (
"context" "context"
"fmt" "fmt"
"io" "io"
"net/url"
"os" "os"
"os/exec" "os/exec"
"path" "path"
@ -115,6 +116,9 @@ func GetFilesOfRepository(user string, gist string, revision string) ([]string,
} }
slice := strings.Split(string(stdout), "\n") slice := strings.Split(string(stdout), "\n")
for i, s := range slice {
slice[i] = convertOctalToUTF8(s)
}
return slice[:len(slice)-1], nil return slice[:len(slice)-1], nil
} }
@ -153,7 +157,7 @@ func CatFileBatch(user string, gist string, revision string, truncate bool) ([]*
fileMap = append(fileMap, &catFileBatch{ fileMap = append(fileMap, &catFileBatch{
Hash: hash, Hash: hash,
Size: size, Size: size,
Name: name, Name: convertOctalToUTF8(name),
}) })
} }
@ -249,7 +253,7 @@ func GetFileContent(user string, gist string, revision string, filename string,
"git", "git",
"--no-pager", "--no-pager",
"show", "show",
revision+":"+filename, revision+":"+convertURLToOctal(filename),
) )
cmd.Dir = repositoryPath cmd.Dir = repositoryPath
@ -273,7 +277,7 @@ func GetFileSize(user string, gist string, revision string, filename string) (ui
"git", "git",
"cat-file", "cat-file",
"-s", "-s",
revision+":"+filename, revision+":"+convertURLToOctal(filename),
) )
cmd.Dir = repositoryPath cmd.Dir = repositoryPath
@ -565,6 +569,48 @@ func removeFilesExceptGit(dir string) error {
}) })
} }
func convertOctalToUTF8(name string) string {
name = strings.Trim(name, `"`)
utf8Name, err := strconv.Unquote(name)
if err != nil {
utf8Name, err = strconv.Unquote(`"` + name + `"`)
if err != nil {
return name
}
}
return utf8Name
}
func convertUTF8ToOctal(name string) string {
if strings.Contains(name, "\\") {
return name
}
needsQuoting := false
for _, r := range name {
if r > 127 {
needsQuoting = true
break
}
}
if !needsQuoting {
return name
}
quoted := fmt.Sprintf("%q", name)
return strings.Trim(quoted, `"`)
}
func convertURLToOctal(name string) string {
decoded, err := url.QueryUnescape(name)
if err != nil {
return name
}
return convertUTF8ToOctal(decoded)
}
const hookTemplate = `#!/bin/sh const hookTemplate = `#!/bin/sh
"$OG_OPENGIST_HOME_INTERNAL/symlinks/opengist" --config=$OG_OPENGIST_HOME_INTERNAL/symlinks/config.yml hook %s "$OG_OPENGIST_HOME_INTERNAL/symlinks/opengist" --config=$OG_OPENGIST_HOME_INTERNAL/symlinks/config.yml hook %s
` `

View file

@ -61,11 +61,12 @@ func TestContent(t *testing.T) {
"my_other_file.txt": `I really "my_other_file.txt": `I really
hate Opengist`, hate Opengist`,
"rip.txt": "byebye", "rip.txt": "byebye",
"中文名.txt": "中文内容",
}) })
files, err := GetFilesOfRepository("thomas", "gist1", "HEAD") files, err := GetFilesOfRepository("thomas", "gist1", "HEAD")
require.NoError(t, err, "Could not get files of repository") require.NoError(t, err, "Could not get files of repository")
require.Subset(t, []string{"my_file.txt", "my_other_file.txt", "rip.txt"}, files, "Files are not correct") require.Subset(t, []string{"my_file.txt", "my_other_file.txt", "rip.txt", "中文名.txt"}, files, "Files are not correct")
content, truncated, err := GetFileContent("thomas", "gist1", "HEAD", "my_file.txt", false) content, truncated, err := GetFileContent("thomas", "gist1", "HEAD", "my_file.txt", false)
require.NoError(t, err, "Could not get content") require.NoError(t, err, "Could not get content")
@ -77,16 +78,22 @@ hate Opengist`,
require.False(t, truncated, "Content should not be truncated") require.False(t, truncated, "Content should not be truncated")
require.Equal(t, "I really\nhate Opengist", content, "Content is not correct") require.Equal(t, "I really\nhate Opengist", content, "Content is not correct")
content, truncated, err = GetFileContent("thomas", "gist1", "HEAD", "中文名.txt", false)
require.NoError(t, err, "Could not get content")
require.False(t, truncated, "Content should not be truncated")
require.Equal(t, "中文内容", content, "Content is not correct")
CommitToBare(t, "thomas", "gist1", map[string]string{ CommitToBare(t, "thomas", "gist1", map[string]string{
"my_renamed_file.txt": "I love Opengist\n", "my_renamed_file.txt": "I love Opengist\n",
"my_other_file.txt": `I really "my_other_file.txt": `I really
like Opengist actually`, like Opengist actually`,
"new_file.txt": "Wait now there is a new file", "new_file.txt": "Wait now there is a new file",
"中文名.txt": "中文内容",
}) })
files, err = GetFilesOfRepository("thomas", "gist1", "HEAD") files, err = GetFilesOfRepository("thomas", "gist1", "HEAD")
require.NoError(t, err, "Could not get files of repository") require.NoError(t, err, "Could not get files of repository")
require.Subset(t, []string{"my_renamed_file.txt", "my_other_file.txt", "new_file.txt"}, files, "Files are not correct") require.Subset(t, []string{"my_renamed_file.txt", "my_other_file.txt", "new_file.txt", "中文名.txt"}, files, "Files are not correct")
content, truncated, err = GetFileContent("thomas", "gist1", "HEAD", "my_other_file.txt", false) content, truncated, err = GetFileContent("thomas", "gist1", "HEAD", "my_other_file.txt", false)
require.NoError(t, err, "Could not get content") require.NoError(t, err, "Could not get content")

View file

@ -193,28 +193,28 @@ loopLog:
case strings.HasPrefix(line, "dissimilarity index"): case strings.HasPrefix(line, "dissimilarity index"):
continue continue
case strings.HasPrefix(line, "rename from "): case strings.HasPrefix(line, "rename from "):
currentFile.OldFilename = line[12 : len(line)-1] currentFile.OldFilename = convertOctalToUTF8(line[12 : len(line)-1])
case strings.HasPrefix(line, "rename to "): case strings.HasPrefix(line, "rename to "):
currentFile.Filename = line[10 : len(line)-1] currentFile.Filename = convertOctalToUTF8(line[10 : len(line)-1])
parseRename = false parseRename = false
case strings.HasPrefix(line, "copy from "): case strings.HasPrefix(line, "copy from "):
currentFile.OldFilename = line[10 : len(line)-1] currentFile.OldFilename = convertOctalToUTF8(line[10 : len(line)-1])
case strings.HasPrefix(line, "copy to "): case strings.HasPrefix(line, "copy to "):
currentFile.Filename = line[8 : len(line)-1] currentFile.Filename = convertOctalToUTF8(line[8 : len(line)-1])
parseRename = false parseRename = false
case strings.HasPrefix(line, "new file"): case strings.HasPrefix(line, "new file"):
currentFile.IsCreated = true currentFile.IsCreated = true
case strings.HasPrefix(line, "deleted file"): case strings.HasPrefix(line, "deleted file"):
currentFile.IsDeleted = true currentFile.IsDeleted = true
case strings.HasPrefix(line, "--- "): case strings.HasPrefix(line, "--- "):
name := line[4 : len(line)-1] name := convertOctalToUTF8(line[4 : len(line)-1])
if parseRename && currentFile.IsDeleted { if parseRename && currentFile.IsDeleted {
currentFile.Filename = name[2:] currentFile.Filename = name[2:]
} else if parseRename && strings.HasPrefix(name, "a/") { } else if parseRename && strings.HasPrefix(name, "a/") {
currentFile.OldFilename = name[2:] currentFile.OldFilename = name[2:]
} }
case strings.HasPrefix(line, "+++ "): case strings.HasPrefix(line, "+++ "):
name := line[4 : len(line)-1] name := convertOctalToUTF8(line[4 : len(line)-1])
if parseRename && strings.HasPrefix(name, "b/") { if parseRename && strings.HasPrefix(name, "b/") {
currentFile.Filename = name[2:] currentFile.Filename = name[2:]
} }