Merge pull request #29 from Myzel394/improve-fstab-documentation

This commit is contained in:
Myzel394 2024-11-13 14:57:35 +01:00 committed by GitHub
commit 558da3ba15
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 175 additions and 52 deletions

View File

@ -14,17 +14,23 @@ type analyzerContext struct {
func Analyze( func Analyze(
document *shared.FstabDocument, document *shared.FstabDocument,
) []protocol.Diagnostic { ) []protocol.Diagnostic {
ctx := analyzerContext{ ctx := &analyzerContext{
document: document, document: document,
} }
analyzeFieldAreFilled(&ctx) analyzeFieldAreFilled(ctx)
if len(ctx.diagnostics) > 0 { if len(ctx.diagnostics) > 0 {
return ctx.diagnostics return ctx.diagnostics
} }
analyzeValuesAreValid(&ctx) analyzeValuesAreValid(ctx)
if len(ctx.diagnostics) > 0 {
return ctx.diagnostics
}
analyzeFSCKField(ctx)
return ctx.diagnostics return ctx.diagnostics
} }

View File

@ -0,0 +1,49 @@
package analyzer
import (
"config-lsp/common"
"config-lsp/handlers/fstab/ast"
"config-lsp/handlers/fstab/fields"
"fmt"
"strings"
protocol "github.com/tliron/glsp/protocol_3_16"
)
func analyzeFSCKField(ctx *analyzerContext) {
it := ctx.document.Config.Entries.Iterator()
var rootEntry *ast.FstabEntry
for it.Next() {
entry := it.Value().(*ast.FstabEntry)
if entry.Fields != nil && entry.Fields.Fsck != nil && entry.Fields.Fsck.Value.Value == "1" {
fileSystem := strings.ToLower(entry.Fields.FilesystemType.Value.Value)
if _, found := fields.FsckOneDisabledFilesystems[fileSystem]; found {
// From https://wiki.archlinux.org/title/Fstab
ctx.diagnostics = append(ctx.diagnostics, protocol.Diagnostic{
Range: entry.Fields.Fsck.ToLSPRange(),
Message: "If the root file system is btrfs or XFS, the fsck order should be set to 0 instead of 1. See fsck.btrfs(8) and fsck.xfs(8).",
Severity: &common.SeverityWarning,
})
continue
}
if entry.Fields.Fsck.Value.Value == "1" {
if rootEntry != nil {
ctx.diagnostics = append(ctx.diagnostics, protocol.Diagnostic{
Range: entry.Fields.Fsck.ToLSPRange(),
Message: fmt.Sprintf("Only the root file system should have a fsck of 1. Other file systems should have a fsck of 2 or 0. The root file system is already using a fsck=1 on line %d", rootEntry.Fields.Start.Line),
Severity: &common.SeverityWarning,
})
} else {
rootEntry = entry
}
}
}
}
}

View File

@ -0,0 +1,44 @@
package analyzer
import (
testutils_test "config-lsp/handlers/fstab/test_utils"
"testing"
)
func TestFSCKMultipleRoots(
t *testing.T,
) {
document := testutils_test.DocumentFromInput(t, `
UUID=12345678-1234-1234-1234-123456789012 /boot ext4 defaults 0 1
UUID=12345678-1234-1234-1234-123456789012 / btrfs defaults 0 1
UUID=12345678-1234-1234-1234-123456789012 /home ext4 defaults 0 2
`)
ctx := &analyzerContext{
document: document,
}
analyzeFSCKField(ctx)
if len(ctx.diagnostics) != 1 {
t.Errorf("Expected 1 error, got %v", len(ctx.diagnostics))
}
}
func TestFSCKBtrfsUsingRoot(
t *testing.T,
) {
document := testutils_test.DocumentFromInput(t, `
UUID=12345678-1234-1234-1234-123456789012 /boot btrfs defaults 0 1
`)
ctx := &analyzerContext{
document: document,
}
analyzeFSCKField(ctx)
if len(ctx.diagnostics) != 1 {
t.Errorf("Expected 1 error, got %v", len(ctx.diagnostics))
}
}

View File

@ -33,8 +33,8 @@ func analyzeValuesAreValid(
checkField(ctx, entry.Fields.Freq, fields.FreqField) checkField(ctx, entry.Fields.Freq, fields.FreqField)
} }
if entry.Fields.Pass != nil { if entry.Fields.Fsck != nil {
checkField(ctx, entry.Fields.Pass, fields.PassField) checkField(ctx, entry.Fields.Fsck, fields.FsckField)
} }
} }
} }

View File

@ -14,7 +14,7 @@ const (
FstabFieldFileSystemType FstabFieldName = "filesystemtype" FstabFieldFileSystemType FstabFieldName = "filesystemtype"
FstabFieldOptions FstabFieldName = "options" FstabFieldOptions FstabFieldName = "options"
FstabFieldFreq FstabFieldName = "freq" FstabFieldFreq FstabFieldName = "freq"
FstabFieldPass FstabFieldName = "pass" FstabFieldFsck FstabFieldName = "fsck"
) )
type FstabField struct { type FstabField struct {
@ -29,7 +29,7 @@ type FstabFields struct {
FilesystemType *FstabField FilesystemType *FstabField
Options *FstabField Options *FstabField
Freq *FstabField Freq *FstabField
Pass *FstabField Fsck *FstabField
} }
type FstabEntry struct { type FstabEntry struct {

View File

@ -20,7 +20,7 @@ import (
// LABEL=test ext4 defaults 0 0 // LABEL=test ext4 defaults 0 0
func (e FstabEntry) GetFieldAtPosition(position common.Position) FstabFieldName { func (e FstabEntry) GetFieldAtPosition(position common.Position) FstabFieldName {
// No fields defined, empty line // No fields defined, empty line
if e.Fields.Spec == nil && e.Fields.MountPoint == nil && e.Fields.FilesystemType == nil && e.Fields.Options == nil && e.Fields.Freq == nil && e.Fields.Pass == nil { if e.Fields.Spec == nil && e.Fields.MountPoint == nil && e.Fields.FilesystemType == nil && e.Fields.Options == nil && e.Fields.Freq == nil && e.Fields.Fsck == nil {
return FstabFieldSpec return FstabFieldSpec
} }
@ -41,8 +41,8 @@ func (e FstabEntry) GetFieldAtPosition(position common.Position) FstabFieldName
if e.Fields.Freq != nil && e.Fields.Freq.ContainsPosition(position) { if e.Fields.Freq != nil && e.Fields.Freq.ContainsPosition(position) {
return FstabFieldFreq return FstabFieldFreq
} }
if e.Fields.Pass != nil && e.Fields.Pass.ContainsPosition(position) { if e.Fields.Fsck != nil && e.Fields.Fsck.ContainsPosition(position) {
return FstabFieldPass return FstabFieldFsck
} }
// Okay let's try to fetch the field by assuming the user is typing from left to right normally // Okay let's try to fetch the field by assuming the user is typing from left to right normally
@ -63,8 +63,8 @@ func (e FstabEntry) GetFieldAtPosition(position common.Position) FstabFieldName
return FstabFieldFreq return FstabFieldFreq
} }
if e.Fields.Freq != nil && e.Fields.Freq.IsPositionAfterEnd(position) && (e.Fields.Pass == nil || e.Fields.Pass.IsPositionBeforeEnd(position)) { if e.Fields.Freq != nil && e.Fields.Freq.IsPositionAfterEnd(position) && (e.Fields.Fsck == nil || e.Fields.Fsck.IsPositionBeforeEnd(position)) {
return FstabFieldPass return FstabFieldFsck
} }
// Okay shit no idea, let's just give whatever is missing // Okay shit no idea, let's just give whatever is missing
@ -89,7 +89,7 @@ func (e FstabEntry) GetFieldAtPosition(position common.Position) FstabFieldName
return FstabFieldFreq return FstabFieldFreq
} }
return FstabFieldPass return FstabFieldFsck
} }
// LABEL=test /mnt/test btrfs subvol=backup,fat=32 [0] [0] // LABEL=test /mnt/test btrfs subvol=backup,fat=32 [0] [0]
@ -122,7 +122,7 @@ func (e FstabEntry) getDefinedFieldsAmount() uint8 {
if e.Fields.Freq != nil { if e.Fields.Freq != nil {
definedAmount++ definedAmount++
} }
if e.Fields.Pass != nil { if e.Fields.Fsck != nil {
definedAmount++ definedAmount++
} }

View File

@ -128,7 +128,7 @@ func (s *fstabParserListener) EnterPass(ctx *parser.PassContext) {
text := ctx.GetText() text := ctx.GetText()
value := commonparser.ParseRawString(text, commonparser.FullFeatures) value := commonparser.ParseRawString(text, commonparser.FullFeatures)
s.fstabContext.currentEntry.Fields.Pass = &FstabField{ s.fstabContext.currentEntry.Fields.Fsck = &FstabField{
LocationRange: location, LocationRange: location,
Value: value, Value: value,
} }

View File

@ -161,7 +161,7 @@ func (c *FstabConfig) parseStatement(
// FilesystemType: filesystemType, // FilesystemType: filesystemType,
// Options: options, // Options: options,
// Freq: freq, // Freq: freq,
// Pass: pass, // Fsck: pass,
// }, // },
// } // }
// //

View File

@ -27,7 +27,7 @@ LABEL=example /mnt/example fat32 defaults 0 2
rawFirstEntry, _ := c.Entries.Get(uint32(0)) rawFirstEntry, _ := c.Entries.Get(uint32(0))
firstEntry := rawFirstEntry.(*FstabEntry) firstEntry := rawFirstEntry.(*FstabEntry)
if !(firstEntry.Fields.Spec.Value.Value == "LABEL=test" && firstEntry.Fields.MountPoint.Value.Value == "/mnt/test" && firstEntry.Fields.FilesystemType.Value.Value == "ext4" && firstEntry.Fields.Options.Value.Value == "defaults" && firstEntry.Fields.Freq.Value.Value == "0" && firstEntry.Fields.Pass.Value.Value == "0") { if !(firstEntry.Fields.Spec.Value.Value == "LABEL=test" && firstEntry.Fields.MountPoint.Value.Value == "/mnt/test" && firstEntry.Fields.FilesystemType.Value.Value == "ext4" && firstEntry.Fields.Options.Value.Value == "defaults" && firstEntry.Fields.Freq.Value.Value == "0" && firstEntry.Fields.Fsck.Value.Value == "0") {
t.Fatalf("Expected entry to be LABEL=test /mnt/test ext4 defaults 0 0, got %v", firstEntry) t.Fatalf("Expected entry to be LABEL=test /mnt/test ext4 defaults 0 0, got %v", firstEntry)
} }
@ -71,8 +71,8 @@ LABEL=example /mnt/example fat32 defaults 0 2
t.Errorf("Expected freq end to be 0:36, got %v", firstEntry.Fields.Freq.LocationRange.End) t.Errorf("Expected freq end to be 0:36, got %v", firstEntry.Fields.Freq.LocationRange.End)
} }
if !(firstEntry.Fields.Pass.LocationRange.Start.Line == 0 && firstEntry.Fields.Pass.LocationRange.Start.Character == 37) { if !(firstEntry.Fields.Fsck.LocationRange.Start.Line == 0 && firstEntry.Fields.Fsck.LocationRange.Start.Character == 37) {
t.Errorf("Expected pass start to be 0:37, got %v", firstEntry.Fields.Pass.LocationRange.Start) t.Errorf("Expected pass start to be 0:37, got %v", firstEntry.Fields.Fsck.LocationRange.Start)
} }
field := firstEntry.GetFieldAtPosition(common.IndexPosition(0)) field := firstEntry.GetFieldAtPosition(common.IndexPosition(0))

View File

@ -0,0 +1,40 @@
package fields
import docvalues "config-lsp/doc-values"
var FsckField = docvalues.EnumValue{
EnforceValues: false,
Values: []docvalues.EnumString{
docvalues.CreateEnumStringWithDoc(
"0",
"Defaults to zero (dont check the filesystem) if not present.",
),
docvalues.CreateEnumStringWithDoc(
"1",
"The root filesystem should be specified with a fs_passno of 1.",
),
docvalues.CreateEnumStringWithDoc(
"2",
"Other filesystems [than the root filesystem] should have a fs_passno of 2.",
),
},
}
var FsckFieldWhenDisabledFilesystems = docvalues.EnumValue{
EnforceValues: false,
Values: []docvalues.EnumString{
docvalues.CreateEnumStringWithDoc(
"0",
"Defaults to zero (dont check the filesystem) if not present.",
),
docvalues.CreateEnumStringWithDoc(
"2",
"Other filesystems [than the root filesystem] should have a fs_passno of 2.",
),
},
}
var FsckOneDisabledFilesystems = map[string]struct{}{
"btrfs": {},
"xfs": {},
}

View File

@ -1,26 +0,0 @@
package fields
import docvalues "config-lsp/doc-values"
var PassField = docvalues.OrValue{
Values: []docvalues.DeprecatedValue{
docvalues.EnumValue{
EnforceValues: false,
Values: []docvalues.EnumString{
docvalues.CreateEnumStringWithDoc(
"0",
"Defaults to zero (dont check the filesystem) if not present.",
),
docvalues.CreateEnumStringWithDoc(
"1",
"The root filesystem should be specified with a fs_passno of 1.",
),
docvalues.CreateEnumStringWithDoc(
"2",
"Other filesystems [than the root filesystem] should have a fs_passno of 2.",
),
},
},
docvalues.NumberValue{},
},
}

View File

@ -4,7 +4,9 @@ import (
"config-lsp/common" "config-lsp/common"
"config-lsp/handlers/fstab/ast" "config-lsp/handlers/fstab/ast"
"config-lsp/handlers/fstab/fields" "config-lsp/handlers/fstab/fields"
"config-lsp/utils"
"fmt" "fmt"
"strings"
"github.com/tliron/glsp/protocol_3_16" "github.com/tliron/glsp/protocol_3_16"
) )
@ -84,13 +86,21 @@ func GetCompletion(
value, value,
cursor, cursor,
), nil ), nil
case ast.FstabFieldPass: case ast.FstabFieldFsck:
value, cursor := getFieldSafely(entry.Fields.Pass, cursor) value, cursor := getFieldSafely(entry.Fields.Fsck, cursor)
return fields.PassField.DeprecatedFetchCompletions( if entry.Fields.FilesystemType != nil &&
utils.KeyExists(fields.FsckOneDisabledFilesystems, strings.ToLower(entry.Fields.FilesystemType.Value.Value)) {
return fields.FsckFieldWhenDisabledFilesystems.DeprecatedFetchCompletions(
value, value,
cursor, cursor,
), nil ), nil
} else {
return fields.FsckField.DeprecatedFetchCompletions(
value,
cursor,
), nil
}
} }
return nil, nil return nil, nil

View File

@ -42,7 +42,7 @@ func GetHoverInfo(
return &hover, nil return &hover, nil
case ast.FstabFieldFreq: case ast.FstabFieldFreq:
return &FreqHoverField, nil return &FreqHoverField, nil
case ast.FstabFieldPass: case ast.FstabFieldFsck:
return &PassHoverField, nil return &PassHoverField, nil
} }