package cmd import ( "fmt" "os" "sort" "github.com/evil7/hostsync/core" "github.com/evil7/hostsync/utils" "github.com/spf13/cobra" ) var ( rawOutput bool ) // listCmd 列表命令 var listCmd = &cobra.Command{ Use: "list [blockName]", Short: "查看 Hosts 配置", Long: `查看 Hosts 配置,可以列出所有块或指定块的配置。 示例: hostsync list # 列出所有块配置 hostsync list github # 列出指定块配置 hostsync list --raw # 原始格式输出,便于导出`, Run: runList, } func init() { listCmd.Flags().BoolVar(&rawOutput, "raw", false, "原始格式输出") } func runList(cmd *cobra.Command, args []string) { hm := core.NewHostsManager() if err := hm.Load(); err != nil { utils.LogError("加载hosts文件失败: %v", err) os.Exit(1) } if len(args) == 0 { // 列出所有块 listAllBlocks(hm) } else { // 列出指定块 blockName := args[0] listBlock(hm, blockName) } } func listAllBlocks(hm *core.HostsManager) { if len(hm.Blocks) == 0 { utils.LogInfo("没有找到任何配置块") return } if rawOutput { // 获取排序后的块名称列表用于原始输出 var blockNames []string for name := range hm.Blocks { blockNames = append(blockNames, name) } sort.Strings(blockNames) // 原始格式输出 for _, name := range blockNames { block := hm.Blocks[name] utils.LogResult("# %s:\n", name) for _, entry := range block.Entries { prefix := "" if !entry.Enabled { prefix = "# " } if entry.Comment != "" { utils.LogResult("%s%-16s %s # %s\n", prefix, entry.IP, entry.Domain, entry.Comment) } else { utils.LogResult("%s%-16s %s\n", prefix, entry.IP, entry.Domain) } } if block.DNS != "" { utils.LogResult("# useDns: %s\n", block.DNS) } if block.DoH != "" { utils.LogResult("# useDoh: %s\n", block.DoH) } if block.Server != "" { utils.LogResult("# useSrv: %s\n", block.Server) } if block.CronJob != "" { utils.LogResult("# cronJob: %s\n", block.CronJob) } if !block.UpdateAt.IsZero() { utils.LogResult("# updateAt: %s\n", block.UpdateAt.Format("2006-01-02 15:04:05")) } utils.LogResult("# %s;\n\n", name) } return } // 表格格式输出 headers := []string{"块名称", "状态", "条目数", "DNS配置", "最后更新"} var rows [][]string // 获取排序后的块名称列表 var blockNames []string for name := range hm.Blocks { blockNames = append(blockNames, name) } sort.Strings(blockNames) for _, name := range blockNames { block := hm.Blocks[name] // 计算启用的条目数 enabledCount := 0 for _, entry := range block.Entries { if entry.Enabled { enabledCount++ } } // 根据块状态和条目状态确定显示状态 var status string if len(block.Entries) == 0 { status = "空块" } else if enabledCount == 0 { status = "全部禁用" } else if enabledCount == len(block.Entries) { status = "全部启用" } else { status = "部分启用" } entryInfo := fmt.Sprintf("%d/%d", enabledCount, len(block.Entries)) dnsConfig := "" if block.DNS != "" { dnsConfig = fmt.Sprintf("DNS: %s", block.DNS) } else if block.DoH != "" { dnsConfig = fmt.Sprintf("DoH: %s", utils.TruncateWithWidth(block.DoH, 30)) } else if block.Server != "" { dnsConfig = fmt.Sprintf("服务器: %s", block.Server) } else { dnsConfig = "系统默认" } updateTime := "从未更新" if !block.UpdateAt.IsZero() { updateTime = block.UpdateAt.Format("2006-01-02 15:04") } rows = append(rows, []string{name, status, entryInfo, dnsConfig, updateTime}) } utils.LogInfo("Hosts 配置块列表 (%d 个块)\n", len(hm.Blocks)) // 设置合适的列宽 columnWidths := []int{12, 12, 8, 35, 17} utils.FormatTable(headers, rows, columnWidths) } func listBlock(hm *core.HostsManager, blockName string) { block := hm.GetBlock(blockName) if block == nil { utils.LogError("块不存在: %s", blockName) os.Exit(1) } if rawOutput { // 原始格式输出 fmt.Printf("# %s:\n", blockName) for _, entry := range block.Entries { prefix := "" if !entry.Enabled { prefix = "# " } if entry.Comment != "" { fmt.Printf("%s%-16s %s # %s\n", prefix, entry.IP, entry.Domain, entry.Comment) } else { fmt.Printf("%s%-16s %s\n", prefix, entry.IP, entry.Domain) } } if block.DNS != "" { fmt.Printf("# useDns: %s\n", block.DNS) } if block.DoH != "" { fmt.Printf("# useDoh: %s\n", block.DoH) } if block.Server != "" { fmt.Printf("# useSrv: %s\n", block.Server) } if block.CronJob != "" { fmt.Printf("# cronJob: %s\n", block.CronJob) } if !block.UpdateAt.IsZero() { fmt.Printf("# updateAt: %s\n", block.UpdateAt.Format("2006-01-02 15:04:05")) } fmt.Printf("# %s;\n", blockName) return } // 计算启用的条目数 enabledCount := 0 for _, entry := range block.Entries { if entry.Enabled { enabledCount++ } } // 详细信息显示 fmt.Printf("名称: %s\n", blockName) // 根据块状态和条目状态确定显示状态 if !block.Enabled { fmt.Printf("状态: 禁用\n") } else if len(block.Entries) == 0 { fmt.Printf("状态: 空块\n") } else if enabledCount == 0 { fmt.Printf("状态: 全部禁用 (0/%d)\n", len(block.Entries)) } else if enabledCount == len(block.Entries) { fmt.Printf("状态: 全部启用 (%d/%d)\n", enabledCount, len(block.Entries)) } else { fmt.Printf("状态: 部分启用 (%d/%d)\n", enabledCount, len(block.Entries)) } if block.DNS != "" { fmt.Printf("DNS服务器: %s\n", block.DNS) } if block.DoH != "" { fmt.Printf("DoH服务器: %s\n", block.DoH) } if block.Server != "" { fmt.Printf("预设服务器: %s\n", block.Server) } if block.CronJob != "" { fmt.Printf("定时任务: %s\n", block.CronJob) } if !block.UpdateAt.IsZero() { fmt.Printf("最后更新: %s\n", block.UpdateAt.Format("2006-01-02 15:04:05")) } if len(block.Entries) == 0 { utils.LogInfo("\n没有域名记录") return } utils.LogInfo("\n域名记录 (%d 个条目):\n", len(block.Entries)) // 域名记录表格 headers := []string{"状态", "IP地址", "域名", "备注"} var rows [][]string for _, entry := range block.Entries { status := "启用" if !entry.Enabled { status = "禁用" } comment := entry.Comment if comment == "" { comment = "-" } rows = append(rows, []string{status, entry.IP, entry.Domain, comment}) } // 设置合适的列宽 columnWidths := []int{8, 16, 30, 20} utils.FormatTable(headers, rows, columnWidths) }