mirror of
https://github.com/acepanel/panel.git
synced 2026-02-04 06:47:20 +08:00
feat: 格式化配置文件
This commit is contained in:
@@ -33,3 +33,149 @@ const DefaultVhostConf = `<VirtualHost *:80>
|
||||
</Directory>
|
||||
</VirtualHost>
|
||||
`
|
||||
|
||||
// order 定义 Apache 指令的排序优先级
|
||||
var order = map[string]int{
|
||||
"Listen": 0,
|
||||
"ServerName": 1,
|
||||
|
||||
"ServerAlias": 10,
|
||||
"ServerAdmin": 11,
|
||||
|
||||
"DocumentRoot": 100,
|
||||
"DirectoryIndex": 101,
|
||||
"Options": 102,
|
||||
"AllowOverride": 103,
|
||||
"Require": 104,
|
||||
"Order": 105,
|
||||
"Allow": 106,
|
||||
"Deny": 107,
|
||||
|
||||
"LimitRequestBody": 200,
|
||||
"LimitRequestFields": 201,
|
||||
"LimitRequestFieldSize": 202,
|
||||
"LimitRequestLine": 203,
|
||||
"LimitXMLRequestBody": 204,
|
||||
|
||||
"AuthType": 300,
|
||||
"AuthName": 301,
|
||||
"AuthUserFile": 302,
|
||||
"AuthGroupFile": 303,
|
||||
"AuthBasicProvider": 304,
|
||||
|
||||
"SSLEngine": 400,
|
||||
"SSLCertificateFile": 401,
|
||||
"SSLCertificateKeyFile": 402,
|
||||
"SSLCertificateChainFile": 403,
|
||||
"SSLCACertificateFile": 404,
|
||||
"SSLCACertificatePath": 405,
|
||||
"SSLProtocol": 406,
|
||||
"SSLCipherSuite": 407,
|
||||
"SSLHonorCipherOrder": 408,
|
||||
"SSLCompression": 409,
|
||||
"SSLSessionCache": 410,
|
||||
"SSLSessionCacheTimeout": 411,
|
||||
"SSLSessionTickets": 412,
|
||||
"SSLUseStapling": 413,
|
||||
"SSLStaplingCache": 414,
|
||||
"SSLStaplingResponderTimeout": 415,
|
||||
"SSLStaplingReturnResponderErrors": 416,
|
||||
"SSLInsecureRenegotiation": 417,
|
||||
"SSLVerifyClient": 418,
|
||||
"SSLVerifyDepth": 419,
|
||||
"SSLOptions": 420,
|
||||
|
||||
"Header": 500,
|
||||
"RequestHeader": 501,
|
||||
"SetEnvIf": 502,
|
||||
"SetEnvIfNoCase": 503,
|
||||
"SetEnv": 504,
|
||||
"UnsetEnv": 505,
|
||||
"PassEnv": 506,
|
||||
"SetOutputFilter": 507,
|
||||
"SetInputFilter": 508,
|
||||
"AddOutputFilter": 509,
|
||||
"AddInputFilter": 510,
|
||||
"AddType": 511,
|
||||
"AddHandler": 512,
|
||||
"AddCharset": 513,
|
||||
"AddEncoding": 514,
|
||||
"AddLanguage": 515,
|
||||
"DefaultType": 516,
|
||||
"ForceType": 517,
|
||||
"RemoveType": 518,
|
||||
"RemoveHandler": 519,
|
||||
"RemoveCharset": 520,
|
||||
"RemoveEncoding": 521,
|
||||
"RemoveLanguage": 522,
|
||||
|
||||
"ProxyPass": 600,
|
||||
"ProxyPassReverse": 601,
|
||||
"ProxyPassMatch": 602,
|
||||
"ProxyPassReverseCookieDomain": 603,
|
||||
"ProxyPassReverseCookiePath": 604,
|
||||
"ProxyPreserveHost": 605,
|
||||
"ProxyRequests": 606,
|
||||
"ProxyVia": 607,
|
||||
"ProxyTimeout": 608,
|
||||
"ProxyAddHeaders": 609,
|
||||
"ProxySet": 610,
|
||||
"BalancerMember": 611,
|
||||
"ProxyPassInherit": 612,
|
||||
"ProxyPassInterpolateEnv": 613,
|
||||
|
||||
"RewriteEngine": 700,
|
||||
"RewriteBase": 701,
|
||||
"RewriteCond": 702,
|
||||
"RewriteRule": 703,
|
||||
"RewriteMap": 704,
|
||||
"RewriteOptions": 705,
|
||||
|
||||
"Redirect": 800,
|
||||
"RedirectMatch": 801,
|
||||
"RedirectTemp": 802,
|
||||
"RedirectPermanent": 803,
|
||||
|
||||
"Alias": 900,
|
||||
"AliasMatch": 901,
|
||||
"ScriptAlias": 902,
|
||||
"ScriptAliasMatch": 903,
|
||||
|
||||
"ErrorDocument": 1000,
|
||||
|
||||
"ExpiresActive": 1100,
|
||||
"ExpiresDefault": 1101,
|
||||
"ExpiresByType": 1102,
|
||||
"DeflateCompressionLevel": 1103,
|
||||
"DeflateMemLevel": 1104,
|
||||
"DeflateWindowSize": 1105,
|
||||
"DeflateBufferSize": 1106,
|
||||
"DeflateFilterNote": 1107,
|
||||
"AddOutputFilterByType": 1108,
|
||||
|
||||
"PHPIniDir": 1200,
|
||||
"SetHandler": 1201,
|
||||
|
||||
"Directory": 1300,
|
||||
"DirectoryMatch": 1301,
|
||||
"Files": 1302,
|
||||
"FilesMatch": 1303,
|
||||
"Location": 1304,
|
||||
"LocationMatch": 1305,
|
||||
"If": 1306,
|
||||
"IfDefine": 1307,
|
||||
"IfModule": 1308,
|
||||
"Else": 1309,
|
||||
"ElseIf": 1310,
|
||||
"Proxy": 1311,
|
||||
"ProxyMatch": 1312,
|
||||
|
||||
"Include": 1400,
|
||||
"IncludeOptional": 1401,
|
||||
|
||||
"ErrorLog": 1500,
|
||||
"CustomLog": 1501,
|
||||
"LogLevel": 1502,
|
||||
"LogFormat": 1503,
|
||||
"TransferLog": 1504,
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package apache
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"slices"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
@@ -32,7 +33,7 @@ func DefaultExportOptions() *ExportOptions {
|
||||
return &ExportOptions{
|
||||
IndentStyle: "spaces",
|
||||
IndentSize: 4,
|
||||
SortDirectives: false,
|
||||
SortDirectives: true,
|
||||
IncludeComments: true,
|
||||
PreserveEmptyLines: true,
|
||||
FormatStyle: "standard",
|
||||
@@ -79,8 +80,10 @@ func (c *Config) ExportWithOptions(options *ExportOptions) string {
|
||||
})
|
||||
}
|
||||
|
||||
// 如果不需要保持原始顺序,按行号排序
|
||||
if !options.SortDirectives {
|
||||
// 排序:如果需要语义排序则按 order 排序,否则按行号排序
|
||||
if options.SortDirectives {
|
||||
sortDirectivesSlice(items, order)
|
||||
} else {
|
||||
sort.Slice(items, func(i, j int) bool {
|
||||
return items[i].line < items[j].line
|
||||
})
|
||||
@@ -186,8 +189,10 @@ func (v *VirtualHost) ExportWithOptions(options *ExportOptions, indent int) stri
|
||||
})
|
||||
}
|
||||
|
||||
// 排序
|
||||
if !options.SortDirectives {
|
||||
// 排序:如果需要语义排序则按 order 排序,否则按行号排序
|
||||
if options.SortDirectives {
|
||||
sortDirectivesSlice(items, order)
|
||||
} else {
|
||||
sort.Slice(items, func(i, j int) bool {
|
||||
return items[i].line < items[j].line
|
||||
})
|
||||
@@ -268,8 +273,10 @@ func (b *Block) ExportWithOptions(options *ExportOptions, indent int) string {
|
||||
}
|
||||
}
|
||||
|
||||
// 按行号排序
|
||||
// 排序:如果需要语义排序则按 order 排序,否则按行号排序
|
||||
if options.SortDirectives {
|
||||
sortDirectivesSlice(allItems, order)
|
||||
} else {
|
||||
sort.Slice(allItems, func(i, j int) bool {
|
||||
return allItems[i].line < allItems[j].line
|
||||
})
|
||||
@@ -345,3 +352,67 @@ func shouldAddEmptyLine(current, next exportItem, options *ExportOptions) bool {
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// sortDirectivesSlice 对指令切片进行语义排序
|
||||
func sortDirectivesSlice(items []exportItem, orderIndex map[string]int) {
|
||||
slices.SortFunc(items, func(a, b exportItem) int {
|
||||
// 跳过注释,注释保持原有位置
|
||||
if a.typ == "comment" || b.typ == "comment" {
|
||||
return a.line - b.line
|
||||
}
|
||||
|
||||
var aName, bName string
|
||||
switch a.typ {
|
||||
case "directive":
|
||||
if dir, ok := a.item.(*Directive); ok {
|
||||
aName = dir.Name
|
||||
}
|
||||
case "virtualhost":
|
||||
if vhost, ok := a.item.(*VirtualHost); ok {
|
||||
aName = vhost.Name
|
||||
}
|
||||
}
|
||||
|
||||
switch b.typ {
|
||||
case "directive":
|
||||
if dir, ok := b.item.(*Directive); ok {
|
||||
bName = dir.Name
|
||||
}
|
||||
case "virtualhost":
|
||||
if vhost, ok := b.item.(*VirtualHost); ok {
|
||||
bName = vhost.Name
|
||||
}
|
||||
}
|
||||
|
||||
// 按照 order 优先级排序
|
||||
if orderIndex[aName] != orderIndex[bName] {
|
||||
return orderIndex[aName] - orderIndex[bName]
|
||||
}
|
||||
|
||||
// 优先级相同时,按照参数排序
|
||||
var aArgs, bArgs []string
|
||||
switch a.typ {
|
||||
case "directive":
|
||||
if dir, ok := a.item.(*Directive); ok {
|
||||
aArgs = dir.Args
|
||||
}
|
||||
case "virtualhost":
|
||||
if vhost, ok := a.item.(*VirtualHost); ok {
|
||||
aArgs = vhost.Args
|
||||
}
|
||||
}
|
||||
|
||||
switch b.typ {
|
||||
case "directive":
|
||||
if dir, ok := b.item.(*Directive); ok {
|
||||
bArgs = dir.Args
|
||||
}
|
||||
case "virtualhost":
|
||||
if vhost, ok := b.item.(*VirtualHost); ok {
|
||||
bArgs = vhost.Args
|
||||
}
|
||||
}
|
||||
|
||||
return slices.Compare(aArgs, bArgs)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -44,3 +44,151 @@ server {
|
||||
error_log /opt/ace/sites/default/log/error.log;
|
||||
}
|
||||
`
|
||||
|
||||
// order 定义 Nginx 指令的排序优先级
|
||||
var order = map[string]int{
|
||||
"listen": 0,
|
||||
"server_name": 1,
|
||||
|
||||
"root": 10,
|
||||
"index": 11,
|
||||
"try_files": 12,
|
||||
"charset": 13,
|
||||
"autoindex": 14,
|
||||
|
||||
"client_max_body_size": 100,
|
||||
"client_body_buffer_size": 101,
|
||||
"limit_except": 102,
|
||||
"limit_req_zone": 103,
|
||||
"limit_req": 104,
|
||||
"limit_conn_zone": 105,
|
||||
"limit_conn": 106,
|
||||
"allow": 107,
|
||||
"deny": 108,
|
||||
"auth_basic": 109,
|
||||
"auth_basic_user_file": 110,
|
||||
|
||||
"ssl": 200,
|
||||
"ssl_certificate": 201,
|
||||
"ssl_certificate_key": 202,
|
||||
"ssl_session_timeout": 203,
|
||||
"ssl_session_cache": 204,
|
||||
"ssl_session_tickets": 205,
|
||||
"ssl_protocols": 206,
|
||||
"ssl_ciphers": 207,
|
||||
"ssl_prefer_server_ciphers": 208,
|
||||
"ssl_early_data": 209,
|
||||
"ssl_dhparam": 210,
|
||||
"ssl_stapling": 211,
|
||||
"ssl_stapling_verify": 212,
|
||||
"ssl_trusted_certificate": 213,
|
||||
|
||||
"resolver": 300,
|
||||
"resolver_timeout": 301,
|
||||
|
||||
"proxy_pass": 400,
|
||||
"proxy_redirect": 401,
|
||||
"proxy_set_header": 402,
|
||||
"proxy_hide_header": 403,
|
||||
"proxy_pass_header": 404,
|
||||
"proxy_http_version": 405,
|
||||
"proxy_method": 406,
|
||||
"proxy_headers_hash_max_size": 407,
|
||||
"proxy_headers_hash_bucket_size": 408,
|
||||
"proxy_buffering": 409,
|
||||
"proxy_buffer_size": 410,
|
||||
"proxy_buffers": 411,
|
||||
"proxy_busy_buffers_size": 412,
|
||||
"proxy_max_temp_file_size": 413,
|
||||
"proxy_read_timeout": 414,
|
||||
"proxy_send_timeout": 415,
|
||||
"proxy_connect_timeout": 416,
|
||||
"proxy_next_upstream": 417,
|
||||
"proxy_next_upstream_tries": 418,
|
||||
"proxy_next_upstream_timeout": 419,
|
||||
"proxy_no_cache": 420,
|
||||
"proxy_cache": 421,
|
||||
"proxy_cache_key": 422,
|
||||
"proxy_cache_valid": 423,
|
||||
"proxy_cache_bypass": 424,
|
||||
"proxy_cache_use_stale": 425,
|
||||
"proxy_cache_lock": 426,
|
||||
"proxy_cache_lock_timeout": 427,
|
||||
"proxy_cache_background_update": 428,
|
||||
"proxy_cache_min_uses": 429,
|
||||
"proxy_ignore_client_abort": 430,
|
||||
"proxy_intercept_errors": 431,
|
||||
"proxy_ssl_server_name": 432,
|
||||
"proxy_ssl_name": 433,
|
||||
"proxy_ssl_protocols": 434,
|
||||
"proxy_ssl_ciphers": 435,
|
||||
"proxy_ssl_verify": 436,
|
||||
"proxy_ssl_verify_depth": 437,
|
||||
"proxy_ssl_trusted_certificate": 438,
|
||||
|
||||
"fastcgi_pass": 500,
|
||||
"fastcgi_index": 501,
|
||||
"fastcgi_param": 502,
|
||||
"fastcgi_split_path_info": 503,
|
||||
"fastcgi_buffers": 504,
|
||||
"fastcgi_buffer_size": 505,
|
||||
"fastcgi_busy_buffers_size": 506,
|
||||
"fastcgi_temp_file_write_size": 507,
|
||||
"fastcgi_read_timeout": 508,
|
||||
"fastcgi_send_timeout": 509,
|
||||
"fastcgi_connect_timeout": 510,
|
||||
"fastcgi_intercept_errors": 511,
|
||||
|
||||
"uwsgi_pass": 600,
|
||||
"uwsgi_param": 601,
|
||||
"uwsgi_read_timeout": 602,
|
||||
"uwsgi_send_timeout": 603,
|
||||
"uwsgi_connect_timeout": 604,
|
||||
|
||||
"grpc_pass": 700,
|
||||
"grpc_read_timeout": 701,
|
||||
"grpc_send_timeout": 702,
|
||||
|
||||
"proxy_cache_path": 800,
|
||||
"fastcgi_cache_path": 801,
|
||||
"uwsgi_cache_path": 802,
|
||||
"proxy_temp_path": 803,
|
||||
"fastcgi_temp_path": 804,
|
||||
"uwsgi_temp_path": 805,
|
||||
|
||||
"gzip": 900,
|
||||
"gzip_comp_level": 901,
|
||||
"gzip_min_length": 902,
|
||||
"gzip_types": 903,
|
||||
"gzip_buffers": 904,
|
||||
"gzip_proxied": 905,
|
||||
"gzip_disable": 906,
|
||||
"gzip_vary": 907,
|
||||
|
||||
"brotli": 910,
|
||||
"brotli_comp_level": 911,
|
||||
"brotli_min_length": 912,
|
||||
"brotli_types": 913,
|
||||
|
||||
"zstd": 920,
|
||||
"zstd_comp_level": 921,
|
||||
"zstd_min_length": 922,
|
||||
"zstd_types": 923,
|
||||
"zstd_static": 924,
|
||||
|
||||
"add_header": 1000,
|
||||
"expires": 1001,
|
||||
|
||||
"rewrite": 1100,
|
||||
"return": 1101,
|
||||
|
||||
"error_page": 1200,
|
||||
|
||||
"if": 1300,
|
||||
"location": 1301,
|
||||
|
||||
"include": 1400,
|
||||
|
||||
"access_log": 1500,
|
||||
"error_log": 1501,
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/tufanbarisyildirim/gonginx/config"
|
||||
@@ -198,6 +199,7 @@ func (p *Parser) Dump() string {
|
||||
|
||||
// Save 保存配置到文件
|
||||
func (p *Parser) Save() error {
|
||||
p.sortDirectives(p.cfg.Directives, order)
|
||||
content := p.Dump()
|
||||
if err := os.WriteFile(p.cfgPath, []byte(content), 0644); err != nil {
|
||||
return fmt.Errorf("failed to save config file: %w", err)
|
||||
@@ -211,6 +213,21 @@ func (p *Parser) SetConfigPath(path string) {
|
||||
p.cfgPath = path
|
||||
}
|
||||
|
||||
func (p *Parser) sortDirectives(directives []config.IDirective, orderIndex map[string]int) {
|
||||
slices.SortFunc(directives, func(a config.IDirective, b config.IDirective) int {
|
||||
if orderIndex[a.GetName()] != orderIndex[b.GetName()] {
|
||||
return orderIndex[a.GetName()] - orderIndex[b.GetName()]
|
||||
}
|
||||
return slices.Compare(p.parameters2Slices(a.GetParameters()), p.parameters2Slices(b.GetParameters()))
|
||||
})
|
||||
|
||||
for _, directive := range directives {
|
||||
if block, ok := directive.GetBlock().(*config.Block); ok {
|
||||
p.sortDirectives(block.Directives, orderIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Parser) slices2Parameters(slices []string) []config.Parameter {
|
||||
var parameters []config.Parameter
|
||||
for _, slice := range slices {
|
||||
|
||||
Reference in New Issue
Block a user