瀏覽代碼

cscli hub list: show only non-empty tables with -o human

* agent config: remove unused LintOnly bool
* Item.IsLocal() -> Item.State.IsLocal(); split method InstallStatus()
* cscli hub list: show only non-empty tables with -o human
mmetc 1 年之前
父節點
當前提交
1ab4487b65

+ 2 - 2
cmd/crowdsec-cli/config_backup.go

@@ -46,7 +46,7 @@ func backupHub(dirPath string) error {
 			}
 
 			//for the local/tainted ones, we back up the full file
-			if v.State.Tainted || v.IsLocal() || !v.State.UpToDate {
+			if v.State.Tainted || v.State.IsLocal() || !v.State.UpToDate {
 				//we need to backup stages for parsers
 				if itemType == cwhub.PARSERS || itemType == cwhub.POSTOVERFLOWS {
 					fstagedir := fmt.Sprintf("%s%s", itemDirectory, v.Stage)
@@ -54,7 +54,7 @@ func backupHub(dirPath string) error {
 						return fmt.Errorf("error while creating stage dir %s : %s", fstagedir, err)
 					}
 				}
-				clog.Debugf("[%s]: backing up file (tainted:%t local:%t up-to-date:%t)", k, v.State.Tainted, v.IsLocal(), v.State.UpToDate)
+				clog.Debugf("[%s]: backing up file (tainted:%t local:%t up-to-date:%t)", k, v.State.Tainted, v.State.IsLocal(), v.State.UpToDate)
 				tfile := fmt.Sprintf("%s%s/%s", itemDirectory, v.Stage, v.FileName)
 				if err = CopyFile(v.State.LocalPath, tfile); err != nil {
 					return fmt.Errorf("failed copy %s %s to %s : %s", itemType, v.State.LocalPath, tfile, err)

+ 1 - 1
cmd/crowdsec-cli/hub.go

@@ -66,7 +66,7 @@ func runHubList(cmd *cobra.Command, args []string) error {
 		}
 	}
 
-	err = listItems(color.Output, cwhub.ItemTypes, items)
+	err = listItems(color.Output, cwhub.ItemTypes, items, true)
 	if err != nil {
 		return err
 	}

+ 1 - 1
cmd/crowdsec-cli/itemcommands.go

@@ -580,7 +580,7 @@ func itemsListRunner(it hubItemType) func(cmd *cobra.Command, args []string) err
 			return err
 		}
 
-		if err = listItems(color.Output, []string{it.name}, items); err != nil {
+		if err = listItems(color.Output, []string{it.name}, items, false); err != nil {
 			return err
 		}
 

+ 13 - 5
cmd/crowdsec-cli/items.go

@@ -53,11 +53,19 @@ func selectItems(hub *cwhub.Hub, itemType string, args []string, installedOnly b
 	return items, nil
 }
 
-func listItems(out io.Writer, itemTypes []string, items map[string][]*cwhub.Item) error {
+func listItems(out io.Writer, itemTypes []string, items map[string][]*cwhub.Item, omitIfEmpty bool) error {
 	switch csConfig.Cscli.Output {
 	case "human":
+		nothingToDisplay := true
 		for _, itemType := range itemTypes {
+			if omitIfEmpty && len(items[itemType]) == 0 {
+				continue
+			}
 			listHubItemTable(out, "\n"+strings.ToUpper(itemType), items[itemType])
+			nothingToDisplay = false
+		}
+		if nothingToDisplay {
+			fmt.Println("No items to display")
 		}
 	case "json":
 		type itemHubStatus struct {
@@ -75,14 +83,15 @@ func listItems(out io.Writer, itemTypes []string, items map[string][]*cwhub.Item
 			hubStatus[itemType] = make([]itemHubStatus, len(items[itemType]))
 
 			for i, item := range items[itemType] {
-				status, emo := item.InstallStatus()
+				status := item.State.Text()
+				status_emo := item.State.Emoji()
 				hubStatus[itemType][i] = itemHubStatus{
 					Name:         item.Name,
 					LocalVersion: item.State.LocalVersion,
 					LocalPath:    item.State.LocalPath,
 					Description:  item.Description,
 					Status:       status,
-					UTF8Status:   fmt.Sprintf("%v  %s", emo, status),
+					UTF8Status:   fmt.Sprintf("%v  %s", status_emo, status),
 				}
 			}
 		}
@@ -107,10 +116,9 @@ func listItems(out io.Writer, itemTypes []string, items map[string][]*cwhub.Item
 
 		for _, itemType := range itemTypes {
 			for _, item := range items[itemType] {
-				status, _ := item.InstallStatus()
 				row := []string{
 					item.Name,
-					status,
+					item.State.Text(),
 					item.State.LocalVersion,
 					item.Description,
 				}

+ 1 - 1
cmd/crowdsec-cli/support.go

@@ -140,7 +140,7 @@ func collectHubItems(hub *cwhub.Hub, itemType string) []byte {
 		log.Warnf("could not collect %s list: %s", itemType, err)
 	}
 
-	if err := listItems(out, []string{itemType}, items); err != nil {
+	if err := listItems(out, []string{itemType}, items, false); err != nil {
 		log.Warnf("could not collect %s list: %s", itemType, err)
 	}
 	return out.Bytes()

+ 2 - 2
cmd/crowdsec-cli/utils_table.go

@@ -18,8 +18,8 @@ func listHubItemTable(out io.Writer, title string, items []*cwhub.Item) {
 	t.SetAlignment(table.AlignLeft, table.AlignLeft, table.AlignLeft, table.AlignLeft)
 
 	for _, item := range items {
-		status, emo := item.InstallStatus()
-		t.AddRow(item.Name, fmt.Sprintf("%v  %s", emo, status), item.State.LocalVersion, item.State.LocalPath)
+		status := fmt.Sprintf("%v  %s", item.State.Emoji(), item.State.Text())
+		t.AddRow(item.Name, status, item.State.LocalVersion, item.State.LocalPath)
 	}
 	renderTableTitle(out, title)
 	t.Render()

+ 0 - 4
cmd/crowdsec/main.go

@@ -262,10 +262,6 @@ func LoadConfig(configFile string, disableAgent bool, disableAPI bool, quiet boo
 		return nil, errors.New("You must run at least the API Server or crowdsec")
 	}
 
-	if flags.TestMode && !cConfig.DisableAgent {
-		cConfig.Crowdsec.LintOnly = true
-	}
-
 	if flags.OneShotDSN != "" && flags.SingleFileType == "" {
 		return nil, errors.New("-dsn requires a -type argument")
 	}

+ 0 - 1
pkg/csconfig/crowdsec_service.go

@@ -23,7 +23,6 @@ type CrowdsecServiceCfg struct {
 	BucketsRoutinesCount      int               `yaml:"buckets_routines"`
 	OutputRoutinesCount       int               `yaml:"output_routines"`
 	SimulationConfig          *SimulationConfig `yaml:"-"`
-	LintOnly                  bool              `yaml:"-"`                          // if set to true, exit after loading configs
 	BucketStateFile           string            `yaml:"state_input_file,omitempty"` // if we need to unserialize buckets at start
 	BucketStateDumpDir        string            `yaml:"state_output_dir,omitempty"` // if we need to unserialize buckets on shutdown
 	BucketsGCEnabled          bool              `yaml:"-"`                          // we need to garbage collect buckets when in forensic mode

+ 1 - 1
pkg/cwhub/hub.go

@@ -109,7 +109,7 @@ func (h *Hub) ItemStats() []string {
 		loaded += fmt.Sprintf("%d %s, ", len(h.GetItemMap(itemType)), itemType)
 
 		for _, item := range h.GetItemMap(itemType) {
-			if item.IsLocal() {
+			if item.State.IsLocal() {
 				local++
 			}
 

+ 44 - 49
pkg/cwhub/item.go

@@ -53,6 +53,48 @@ type ItemState struct {
 	BelongsToCollections []string `json:"belongs_to_collections,omitempty" yaml:"belongs_to_collections,omitempty"`
 }
 
+// IsLocal returns true if the item has been create by a user (not downloaded from the hub).
+func (s *ItemState) IsLocal() bool {
+	return s.Installed && !s.Downloaded
+}
+
+// Text returns the status of the item as a string (eg. "enabled,update-available").
+func (s *ItemState) Text() string {
+	ret := "disabled"
+
+	if s.Installed {
+		ret = "enabled"
+	}
+
+	if s.IsLocal() {
+		ret += ",local"
+	}
+
+	if s.Tainted {
+		ret += ",tainted"
+	} else if !s.UpToDate && !s.IsLocal() {
+		ret += ",update-available"
+	}
+
+	return ret
+}
+
+// Emoji returns the status of the item as an emoji (eg. emoji.Warning).
+func (s *ItemState) Emoji() emoji.Emoji {
+	switch {
+	case s.IsLocal():
+		return emoji.House
+	case !s.Installed:
+		return emoji.Prohibited
+	case s.Tainted || (!s.UpToDate && !s.IsLocal()):
+		return emoji.Warning
+	case s.Installed:
+		return emoji.CheckMark
+	default:
+		return emoji.QuestionMark
+	}
+}
+
 // Item is created from an index file and enriched with local info.
 type Item struct {
 	hub *Hub // back pointer to the hub, to retrieve other items and call install/remove methods
@@ -107,11 +149,6 @@ func (i *Item) HasSubItems() bool {
 	return i.Type == COLLECTIONS
 }
 
-// IsLocal returns true if the item has been create by a user (not downloaded from the hub).
-func (i *Item) IsLocal() bool {
-	return i.State.Installed && !i.State.Downloaded
-}
-
 // MarshalJSON is used to prepare the output for "cscli ... inspect -o json".
 // It must not use a pointer receiver.
 func (i Item) MarshalJSON() ([]byte, error) {
@@ -139,7 +176,7 @@ func (i Item) MarshalJSON() ([]byte, error) {
 		UpToDate:             i.State.UpToDate,
 		Tainted:              i.State.Tainted,
 		BelongsToCollections: i.State.BelongsToCollections,
-		Local:                i.IsLocal(),
+		Local:                i.State.IsLocal(),
 	})
 }
 
@@ -155,7 +192,7 @@ func (i Item) MarshalYAML() (interface{}, error) {
 	}{
 		Alias: Alias(i),
 		State: i.State,
-		Local: i.IsLocal(),
+		Local: i.State.IsLocal(),
 	}, nil
 }
 
@@ -290,48 +327,6 @@ func (i *Item) descendants() ([]*Item, error) {
 	return ret, nil
 }
 
-// InstallStatus returns the status of the item as a string and an emoji
-// (eg. "enabled,update-available" and emoji.Warning).
-func (i *Item) InstallStatus() (string, emoji.Emoji) {
-	status := "disabled"
-	ok := false
-
-	if i.State.Installed {
-		ok = true
-		status = "enabled"
-	}
-
-	managed := true
-	if i.IsLocal() {
-		managed = false
-		status += ",local"
-	}
-
-	warning := false
-	if i.State.Tainted {
-		warning = true
-		status += ",tainted"
-	} else if !i.State.UpToDate && !i.IsLocal() {
-		warning = true
-		status += ",update-available"
-	}
-
-	emo := emoji.QuestionMark
-
-	switch {
-	case !managed:
-		emo = emoji.House
-	case !i.State.Installed:
-		emo = emoji.Prohibited
-	case warning:
-		emo = emoji.Warning
-	case ok:
-		emo = emoji.CheckMark
-	}
-
-	return status, emo
-}
-
 // versionStatus returns the status of the item version compared to the hub version.
 // semver requires the 'v' prefix.
 func (i *Item) versionStatus() int {

+ 2 - 2
pkg/cwhub/item_test.go

@@ -23,7 +23,7 @@ func TestItemStatus(t *testing.T) {
 		item.State.Tainted = false
 		item.State.Downloaded = true
 
-		txt, _ := item.InstallStatus()
+		txt := item.State.Text()
 		require.Equal(t, "enabled,update-available", txt)
 
 		item.State.Installed = true
@@ -31,7 +31,7 @@ func TestItemStatus(t *testing.T) {
 		item.State.Tainted = false
 		item.State.Downloaded = false
 
-		txt, _ = item.InstallStatus()
+		txt = item.State.Text()
 		require.Equal(t, "enabled,local", txt)
 	}
 

+ 1 - 1
pkg/cwhub/iteminstall.go

@@ -13,7 +13,7 @@ func (i *Item) enable() error {
 			return fmt.Errorf("%s is tainted, won't enable unless --force", i.Name)
 		}
 
-		if i.IsLocal() {
+		if i.State.IsLocal() {
 			return fmt.Errorf("%s is local, won't enable", i.Name)
 		}
 

+ 1 - 1
pkg/cwhub/itemremove.go

@@ -66,7 +66,7 @@ func (i *Item) disable(purge bool, force bool) (bool, error) {
 
 // Remove disables the item, optionally removing the downloaded content.
 func (i *Item) Remove(purge bool, force bool) (bool, error) {
-	if i.IsLocal() {
+	if i.State.IsLocal() {
 		log.Warningf("%s is a local item, please delete manually", i.Name)
 		return false, nil
 	}

+ 2 - 2
pkg/cwhub/itemupgrade.go

@@ -20,7 +20,7 @@ import (
 func (i *Item) Upgrade(force bool) (bool, error) {
 	updated := false
 
-	if i.IsLocal() {
+	if i.State.IsLocal() {
 		log.Infof("not upgrading %s: local item", i.Name)
 		return false, nil
 	}
@@ -155,7 +155,7 @@ func (i *Item) fetch() ([]byte, error) {
 
 // download downloads the item from the hub and writes it to the hub directory.
 func (i *Item) download(overwrite bool) (string, error) {
-	if i.IsLocal() {
+	if i.State.IsLocal() {
 		return "", fmt.Errorf("%s is local, can't download", i.Name)
 	}
 	// if user didn't --force, don't overwrite local, tainted, up-to-date files

+ 1 - 1
pkg/cwhub/sync.go

@@ -420,7 +420,7 @@ func (h *Hub) localSync() error {
 		case versionFuture:
 			warnings = append(warnings, fmt.Sprintf("collection %s is in the future (currently:%s, latest:%s)", item.Name, item.State.LocalVersion, item.Version))
 		case versionUnknown:
-			if !item.IsLocal() {
+			if !item.State.IsLocal() {
 				warnings = append(warnings, fmt.Sprintf("collection %s is tainted (latest:%s)", item.Name, item.Version))
 			}
 		}

+ 5 - 3
test/bats/20_hub.bats

@@ -34,17 +34,19 @@ teardown() {
 
     # no items
     rune -0 cscli hub list
-    assert_output --regexp ".*PARSERS.*POSTOVERFLOWS.*SCENARIOS.*COLLECTIONS.*"
+    assert_output "No items to display"
     rune -0 cscli hub list -o json
     assert_json '{parsers:[],scenarios:[],collections:[],postoverflows:[]}'
     rune -0 cscli hub list -o raw
     assert_output 'name,status,version,description,type'
 
-    # some items
+    # some items: with output=human, show only non-empty tables
     rune -0 cscli parsers install crowdsecurity/whitelists
     rune -0 cscli scenarios install crowdsecurity/telnet-bf
     rune -0 cscli hub list
-    assert_output --regexp ".*PARSERS.*crowdsecurity/whitelists.*POSTOVERFLOWS.*SCENARIOS.*crowdsecurity/telnet-bf.*COLLECTIONS.*"
+    assert_output --regexp ".*PARSERS.*crowdsecurity/whitelists.*SCENARIOS.*crowdsecurity/telnet-bf.*"
+    refute_output --partial 'POSTOVERFLOWS'
+    refute_output --partial 'COLLECTIONS'
     rune -0 cscli hub list -o json
     rune -0 jq -e '(.parsers | length == 1) and (.scenarios | length == 1)' <(output)
     rune -0 cscli hub list -o raw