diff --git a/config/block.go b/config/block.go index fd45725..1a51f7d 100644 --- a/config/block.go +++ b/config/block.go @@ -8,6 +8,13 @@ import ( "golang.org/x/exp/slices" ) +const ( + upstreamBlockName = "upstream" + locationBlockName = "location" + httpBlockName = "http" + serverBlockName = "server" +) + type Block struct { FilePath string config *Config @@ -196,8 +203,8 @@ func (b *Block) createComment(rawComment *rawparser.Comment, position CommentPos } } -func (b *Block) addBlock(name string, parameters []string) Block { - return newBlock(b.rawBlock, b.config, name, parameters) +func (b *Block) addBlock(name string, parameters []string, begining bool) Block { + return newBlock(b.rawBlock, b.config, name, parameters, begining) } func (b *Block) setContainer(container entryContainer) { diff --git a/config/blockhelper.go b/config/blockhelper.go index 3fae58a..ecbf673 100644 --- a/config/blockhelper.go +++ b/config/blockhelper.go @@ -21,7 +21,7 @@ type upstreamBlockFinder interface { func findServerBlocks(finder blockFinder) []ServerBlock { var serverBlocks []ServerBlock - for _, block := range finder.FindBlocks("server") { + for _, block := range finder.FindBlocks(serverBlockName) { serverBlocks = append(serverBlocks, ServerBlock{ Block: block, }) @@ -33,7 +33,7 @@ func findServerBlocks(finder blockFinder) []ServerBlock { func findLocationBlocks(finder blockFinder) []LocationBlock { var locationBlocks []LocationBlock - for _, block := range finder.FindBlocks("location") { + for _, block := range finder.FindBlocks(locationBlockName) { locationBlocks = append(locationBlocks, LocationBlock{ Block: block, }) @@ -45,7 +45,7 @@ func findLocationBlocks(finder blockFinder) []LocationBlock { func findHttpBlocks(finder blockFinder) []HttpBlock { var httpBlocks []HttpBlock - for _, block := range finder.FindBlocks("http") { + for _, block := range finder.FindBlocks(httpBlockName) { httpBlocks = append(httpBlocks, HttpBlock{ Block: block, }) @@ -57,7 +57,7 @@ func findHttpBlocks(finder blockFinder) []HttpBlock { func findUpstreamBlocks(finder blockFinder) []UpstreamBlock { var upstreamBlocks []UpstreamBlock - for _, block := range finder.FindBlocks("upstream") { + for _, block := range finder.FindBlocks(upstreamBlockName) { upstreamBlocks = append(upstreamBlocks, UpstreamBlock{ Block: block, }) @@ -92,7 +92,7 @@ func findUpstreamBlocksByName(finder upstreamBlockFinder, upstreamName string) [ return upstreamBlocks } -func newBlock(container entryContainer, config *Config, name string, parameters []string) Block { +func newBlock(container entryContainer, config *Config, name string, parameters []string, begining bool) Block { rawBlock := &rawparser.BlockDirective{ Identifier: name, Content: &rawparser.BlockContent{}, @@ -107,11 +107,43 @@ func newBlock(container entryContainer, config *Config, name string, parameters } entries := container.GetEntries() - entries = append(entries, &rawparser.Entry{ - StartNewLines: []string{"\n"}, + + indexToInsert := -1 + similarBlocksIndexes := []int{} + + for index, entry := range entries { + if entry.BlockDirective != nil && entry.BlockDirective.Identifier == name { + similarBlocksIndexes = append(similarBlocksIndexes, index) + } + } + + if len(similarBlocksIndexes) != 0 { + if begining { + indexToInsert = similarBlocksIndexes[0] + } else { + indexToInsert = similarBlocksIndexes[len(similarBlocksIndexes)-1] + + if indexToInsert == len(entries)-1 { + indexToInsert = -1 + } else { + indexToInsert += 1 + } + } + } + + entry := &rawparser.Entry{ BlockDirective: rawBlock, EndNewLines: []string{"\n"}, - }) + } + + if indexToInsert == -1 { + entries = append(entries, entry) + } else { + if indexToInsert == 0 { + entry.StartNewLines = []string{"\n"} + } + entries = slices.Insert(entries, indexToInsert, entry) + } setEntries(container, entries) @@ -155,7 +187,7 @@ func deleteBlockEntityContainer(c entryContainer, callback func(block *rawparser setEntries(c, dEntries) } -func addLocationBlock(b *Block, modifier, match string) LocationBlock { +func addLocationBlock(b *Block, modifier, match string, begining bool) LocationBlock { parameters := []string{} if modifier != "" { @@ -166,7 +198,7 @@ func addLocationBlock(b *Block, modifier, match string) LocationBlock { parameters = append(parameters, match) } - block := b.addBlock("location", parameters) + block := b.addBlock(locationBlockName, parameters, begining) return LocationBlock{ Block: block, diff --git a/config/configfile.go b/config/configfile.go index aee4d24..e29f4bb 100644 --- a/config/configfile.go +++ b/config/configfile.go @@ -89,7 +89,7 @@ func (c *ConfigFile) DeleteUpstreamBlock(upstreamBlock ServerBlock) { } func (c *ConfigFile) addBlock(name string, parameters []string) Block { - return newBlock(c.configFile, c.config, name, parameters) + return newBlock(c.configFile, c.config, name, parameters, false) } func (c *ConfigFile) Dump() error { diff --git a/config/httpblock.go b/config/httpblock.go index a623626..0c14f90 100644 --- a/config/httpblock.go +++ b/config/httpblock.go @@ -28,8 +28,8 @@ func (b *HttpBlock) FindLocationBlocks() []LocationBlock { return findLocationBlocks(&b.Block) } -func (b *HttpBlock) AddUpstreamBlock(upstreamName string) UpstreamBlock { - block := b.addBlock("upstream", []string{upstreamName}) +func (b *HttpBlock) AddUpstreamBlock(upstreamName string, begining bool) UpstreamBlock { + block := b.addBlock(upstreamBlockName, []string{upstreamName}, begining) return UpstreamBlock{ Block: block, @@ -37,7 +37,7 @@ func (b *HttpBlock) AddUpstreamBlock(upstreamName string) UpstreamBlock { } func (b *HttpBlock) AddServerBlock() ServerBlock { - block := b.addBlock("server", nil) + block := b.addBlock(serverBlockName, nil, false) return ServerBlock{ Block: block, diff --git a/config/locationblock.go b/config/locationblock.go index c8754e2..a15eb2b 100644 --- a/config/locationblock.go +++ b/config/locationblock.go @@ -52,8 +52,8 @@ func (l *LocationBlock) SetLocationMatch(match string) { l.SetParameters(parameters) } -func (l *LocationBlock) AddLocationBlock(modifier, match string) LocationBlock { - return addLocationBlock(&l.Block, modifier, match) +func (l *LocationBlock) AddLocationBlock(modifier, match string, begining bool) LocationBlock { + return addLocationBlock(&l.Block, modifier, match, begining) } func (l *LocationBlock) DeleteLocationBlock(locationBlock LocationBlock) { diff --git a/config/serverblock.go b/config/serverblock.go index 2581c9d..aeaadb0 100644 --- a/config/serverblock.go +++ b/config/serverblock.go @@ -134,8 +134,8 @@ func (s *ServerBlock) FindLocationBlocks() []LocationBlock { return findLocationBlocks(&s.Block) } -func (s *ServerBlock) AddLocationBlock(modifier, match string) LocationBlock { - return addLocationBlock(&s.Block, modifier, match) +func (s *ServerBlock) AddLocationBlock(modifier, match string, begining bool) LocationBlock { + return addLocationBlock(&s.Block, modifier, match, begining) } func (s *ServerBlock) DeleteLocationBlock(locationBlock LocationBlock) { diff --git a/config/serverblock_test.go b/config/serverblock_test.go index 43c4bfb..8fa77bb 100644 --- a/config/serverblock_test.go +++ b/config/serverblock_test.go @@ -4,6 +4,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "golang.org/x/exp/slices" ) func TestFindDirectivesInServerBlock(t *testing.T) { @@ -57,6 +58,21 @@ func TestAddDirectiveInServerBlock(t *testing.T) { }) } +func TestAddLocationBlockInServerBlock(t *testing.T) { + testWithConfigFileRollback(t, example2ConfigFilePath, func(t *testing.T) { + config, serverBlock := getServerBlock(t, "example2.com") + serverBlock.AddLocationBlock("~", "/acme", true) + + err := config.Dump() + assert.Nil(t, err) + + locationExists := slices.ContainsFunc(serverBlock.FindLocationBlocks(), func(block LocationBlock) bool { + return block.GetLocationMatch() == "/acme" && block.GetModifier() == "~" + }) + assert.True(t, locationExists) + }) +} + func TestDeleteDirectiveByNameInServerBlock(t *testing.T) { testWithConfigFileRollback(t, example2ConfigFilePath, func(t *testing.T) { config, serverBlock := getServerBlock(t, "example2.com")