mirror of
https://github.com/Myzel394/config-lsp.git
synced 2025-06-18 23:15:26 +02:00
Merge pull request #29 from Myzel394/improve-fstab-documentation
This commit is contained in:
commit
558da3ba15
@ -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
|
||||||
}
|
}
|
||||||
|
49
server/handlers/fstab/analyzer/fsck.go
Normal file
49
server/handlers/fstab/analyzer/fsck.go
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
44
server/handlers/fstab/analyzer/fsck_test.go
Normal file
44
server/handlers/fstab/analyzer/fsck_test.go
Normal 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))
|
||||||
|
}
|
||||||
|
}
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
@ -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++
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,
|
||||||
}
|
}
|
||||||
|
@ -161,7 +161,7 @@ func (c *FstabConfig) parseStatement(
|
|||||||
// FilesystemType: filesystemType,
|
// FilesystemType: filesystemType,
|
||||||
// Options: options,
|
// Options: options,
|
||||||
// Freq: freq,
|
// Freq: freq,
|
||||||
// Pass: pass,
|
// Fsck: pass,
|
||||||
// },
|
// },
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
|
@ -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))
|
||||||
|
40
server/handlers/fstab/fields/fsck.go
Normal file
40
server/handlers/fstab/fields/fsck.go
Normal 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 (don’t 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 (don’t 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": {},
|
||||||
|
}
|
@ -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 (don’t 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{},
|
|
||||||
},
|
|
||||||
}
|
|
@ -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
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user