mirror of
https://github.com/ipfs/kubo.git
synced 2026-03-10 18:57:57 +08:00
fix(ls): improve --long flag docs and fix minor issues
- improved godocs for formatMode and formatModTime functions - fixed permBit signature: char rune → char byte (avoids unnecessary cast) - clarified help text: mode/mtime are optional UnixFS metadata - documented that times are displayed in UTC - fixed flaky time test by using 1 month ago instead of 1 hour - removed hardcoded CID assertion that would break on DAG changes
This commit is contained in:
parent
e66fa0dbc4
commit
97562d1423
@ -58,21 +58,23 @@ var LsCmd = &cmds.Command{
|
||||
Displays the contents of an IPFS or IPNS object(s) at the given path, with
|
||||
the following format:
|
||||
|
||||
<link base58 hash> <link size in bytes> <link name>
|
||||
<cid> <size> <name>
|
||||
|
||||
With the --long (-l) option, also display file mode (permissions) and
|
||||
modification time for files that were added with --preserve-mode and
|
||||
--preserve-mtime flags. Format similar to Unix 'ls -l':
|
||||
With the --long (-l) option, display optional file mode (permissions) and
|
||||
modification time in a format similar to Unix 'ls -l':
|
||||
|
||||
<mode> <link base58 hash> <size> <mtime> <name>
|
||||
<mode> <cid> <size> <mtime> <name>
|
||||
|
||||
Example output with --long:
|
||||
Mode and mtime are optional UnixFS metadata. They are only present if the
|
||||
content was imported with 'ipfs add --preserve-mode' and '--preserve-mtime'.
|
||||
Without preserved metadata, mode shows '----------' and mtime shows '-'.
|
||||
Times are displayed in UTC.
|
||||
|
||||
Example output with --long (content imported with preserved metadata):
|
||||
|
||||
-rw-r--r-- QmZULkCELmmk5XNf... 1234 Jan 15 10:30 document.txt
|
||||
-rwxr-xr-x QmaRGe7bVmVaLmxb... 5678 Dec 01 2023 script.sh
|
||||
drwxr-xr-x QmWWEQhcLufF3qPm... - Nov 20 2023 subdir/
|
||||
|
||||
Files without preserved metadata show '----------' for mode and '-' for mtime.
|
||||
The JSON output contains type information.
|
||||
`,
|
||||
},
|
||||
@ -230,7 +232,16 @@ The JSON output contains type information.
|
||||
Type: LsOutput{},
|
||||
}
|
||||
|
||||
// formatMode formats os.FileMode to Unix-style permission string (e.g., "-rw-r--r--").
|
||||
// formatMode converts os.FileMode to a 10-character Unix ls-style string.
|
||||
//
|
||||
// Format: [type][owner rwx][group rwx][other rwx]
|
||||
//
|
||||
// Type indicators: - (regular), d (directory), l (symlink), p (named pipe),
|
||||
// s (socket), c (char device), b (block device).
|
||||
//
|
||||
// Special bits replace the execute position: setuid on owner (s/S),
|
||||
// setgid on group (s/S), sticky on other (t/T). Lowercase when the
|
||||
// underlying execute bit is also set, uppercase when not.
|
||||
func formatMode(mode os.FileMode) string {
|
||||
var buf [10]byte
|
||||
|
||||
@ -300,15 +311,20 @@ func formatMode(mode os.FileMode) string {
|
||||
}
|
||||
|
||||
// permBit returns the permission character if the bit is set.
|
||||
func permBit(mode os.FileMode, bit os.FileMode, char rune) byte {
|
||||
func permBit(mode os.FileMode, bit os.FileMode, char byte) byte {
|
||||
if mode&bit != 0 {
|
||||
return byte(char)
|
||||
return char
|
||||
}
|
||||
return '-'
|
||||
}
|
||||
|
||||
// formatModTime formats time.Time for display.
|
||||
// Returns empty string if time is zero.
|
||||
// formatModTime formats time.Time for display, following Unix ls conventions.
|
||||
//
|
||||
// Returns "-" for zero time. Otherwise returns a 12-character string:
|
||||
// recent files (within 6 months) show "Jan 02 15:04",
|
||||
// older or future files show "Jan 02 2006".
|
||||
//
|
||||
// The output uses the timezone embedded in t (UTC for IPFS metadata).
|
||||
func formatModTime(t time.Time) string {
|
||||
if t.IsZero() {
|
||||
return "-"
|
||||
|
||||
@ -181,9 +181,8 @@ func TestFormatModTime(t *testing.T) {
|
||||
oldResult := formatModTime(oldTime)
|
||||
assert.Len(t, oldResult, 12, "old time format should be 12 chars")
|
||||
|
||||
// Recent time (use a fixed time to avoid flakiness)
|
||||
// We test the format length by checking a definitely-recent time
|
||||
recentTime := time.Now().Add(-1 * time.Hour)
|
||||
// Recent time: use 1 month ago to ensure it's always within the 6-month window
|
||||
recentTime := time.Now().AddDate(0, -1, 0)
|
||||
recentResult := formatModTime(recentTime)
|
||||
assert.Len(t, recentResult, 12, "recent time format should be 12 chars")
|
||||
})
|
||||
|
||||
@ -57,11 +57,6 @@ func TestLsLongFormat(t *testing.T) {
|
||||
assert.Contains(t, lines[1], "-rw-r--r--", "readable file should have 644 permissions")
|
||||
assert.Contains(t, lines[1], "Jun 15 2020", "should show mtime with year format")
|
||||
assert.Contains(t, lines[1], "readable.txt", "should show filename")
|
||||
|
||||
// Explicit full output check to catch any formatting regressions
|
||||
expectedOutput := `-rwxr-xr-x QmNmu36VhUL46L1ebS7pjGNBhBWNhL6kERHiswK6fg2HJz 17 Jun 15 2020 executable.sh
|
||||
-rw-r--r-- QmUHndqmVyXbCS4FkEAQRZ4FeoBZMn8NBsy86bAVR8JhYQ 5 Jun 15 2020 readable.txt`
|
||||
assert.Equal(t, expectedOutput, strings.TrimSpace(output), "output format must remain stable")
|
||||
})
|
||||
|
||||
t.Run("long format shows dash for files without preserved metadata", func(t *testing.T) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user