summaryrefslogtreecommitdiff
path: root/internal/git/utils.go
blob: 68e4497875138c56e316cf428e1dfcb698c2eeb3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
package git

import (
	"fmt"
	"strconv"
	"strings"
)

// ParseFileMode converts a git-style file mode (e.g. "100644")
// into a human-readable string like "rw-r--r--".
func ParseFileMode(modeStr string) (string, error) {
	// Git modes are typically 6 digits. The last 3 represent permissions.
	// e.g. 100644 → 644
	if len(modeStr) < 3 {
		return "", fmt.Errorf("invalid mode: %s", modeStr)
	}

	permStr := modeStr[len(modeStr)-3:]
	permVal, err := strconv.Atoi(permStr)
	if err != nil {
		return "", err
	}

	return numericPermToLetters(permVal), nil
}

func numericPermToLetters(perm int) string {
	// Map each octal digit to rwx letters
	lookup := map[int]string{
		0: "---",
		1: "--x",
		2: "-w-",
		3: "-wx",
		4: "r--",
		5: "r-x",
		6: "rw-",
		7: "rwx",
	}

	u := perm / 100       // user
	g := (perm / 10) % 10 // group
	o := perm % 10        // others

	return lookup[u] + lookup[g] + lookup[o]
}

// IsBinary performs a heuristic check to determine if data is binary.
// Rules:
//   - Any NUL byte => binary
//   - Consider only a sample (up to 8 KiB). If >30% of bytes are control characters
//     outside the common whitespace/newline range, treat as binary.
func IsBinary(b []byte) bool {
	n := len(b)
	if n == 0 {
		return false
	}
	if n > 8192 {
		n = 8192
	}
	sample := b[:n]
	bad := 0
	for _, c := range sample {
		if c == 0x00 {
			return true
		}
		// Allow common whitespace and control: tab(9), LF(10), CR(13)
		if c == 9 || c == 10 || c == 13 {
			continue
		}
		// Count other control chars and DEL as non-text
		if c < 32 || c == 127 {
			bad++
		}
	}
	// If more than 30% of sampled bytes are non-text, consider binary
	return bad*100 > n*30
}

func RefToFileName(ref string) string {
	var result strings.Builder
	for _, c := range ref {
		if (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '-' || c == '.' {
			result.WriteByte(byte(c))
		} else if c >= 'A' && c <= 'Z' {
			result.WriteByte(byte(c - 'A' + 'a'))
		} else {
			result.WriteByte('-')
		}
	}
	return result.String()
}