mirror of
https://github.com/roddhjav/apparmor.d.git
synced 2024-11-14 23:43:56 +01:00
feat(aa): add implementation of the new rule methods.
This commit is contained in:
parent
8b24f3521d
commit
0e0f87611a
@ -39,5 +39,11 @@ func (r *All) Compare(other Rule) int {
|
|||||||
func (r *All) Merge(other Rule) bool {
|
func (r *All) Merge(other Rule) bool {
|
||||||
o, _ := other.(*All)
|
o, _ := other.(*All)
|
||||||
b := &r.Base
|
b := &r.Base
|
||||||
return b.merge(o.Base)
|
return b.merge(o.Base) // Always merge all rules
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *All) Lengths() []int {
|
||||||
|
return []int{} // No len for all
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *All) setPaddings(max []int) {} // No paddings for all
|
||||||
|
@ -39,3 +39,9 @@ func (r *Hat) Compare(other Rule) int {
|
|||||||
func (r *Hat) Merge(other Rule) bool {
|
func (r *Hat) Merge(other Rule) bool {
|
||||||
return false // Never merge hat blocks
|
return false // Never merge hat blocks
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Hat) Lengths() []int {
|
||||||
|
return []int{} // No len for hat
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Hat) setPaddings(max []int) {} // No paddings for hat
|
||||||
|
@ -81,3 +81,17 @@ func (r *Capability) Compare(other Rule) int {
|
|||||||
func (r *Capability) Merge(other Rule) bool {
|
func (r *Capability) Merge(other Rule) bool {
|
||||||
return false // Never merge capabilities
|
return false // Never merge capabilities
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Capability) Lengths() []int {
|
||||||
|
return []int{
|
||||||
|
r.Qualifier.getLenAudit(),
|
||||||
|
r.Qualifier.getLenAccess(),
|
||||||
|
length("", r.Names),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Capability) setPaddings(max []int) {
|
||||||
|
r.Paddings = append(r.Qualifier.setPaddings(max[:2]), setPaddings(
|
||||||
|
max[2:], []string{""}, []any{r.Names})...,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
@ -103,3 +103,20 @@ func (r *ChangeProfile) Compare(other Rule) int {
|
|||||||
func (r *ChangeProfile) Merge(other Rule) bool {
|
func (r *ChangeProfile) Merge(other Rule) bool {
|
||||||
return false // Never merge change_profile
|
return false // Never merge change_profile
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *ChangeProfile) Lengths() []int {
|
||||||
|
return []int{
|
||||||
|
r.Qualifier.getLenAudit(),
|
||||||
|
r.Qualifier.getLenAccess(),
|
||||||
|
length("", r.ExecMode),
|
||||||
|
length("", r.Exec),
|
||||||
|
length("", r.ProfileName),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *ChangeProfile) setPaddings(max []int) {
|
||||||
|
r.Paddings = append(r.Qualifier.setPaddings(max[:2]), setPaddings(
|
||||||
|
max[2:], []string{"", "", ""},
|
||||||
|
[]any{r.ExecMode, r.Exec, r.ProfileName})...,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
@ -137,3 +137,9 @@ func (r *Dbus) Merge(other Rule) bool {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Dbus) Lengths() []int {
|
||||||
|
return []int{} // No len for dbus
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Dbus) setPaddings(max []int) {} // No paddings for dbus
|
||||||
|
@ -8,6 +8,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"slices"
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/roddhjav/apparmor.d/pkg/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -156,6 +158,42 @@ func (r *File) Merge(other Rule) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *File) Lengths() []int {
|
||||||
|
// Add padding to align with other transition rule
|
||||||
|
lenPath := 0
|
||||||
|
isTransition := util.Intersect(
|
||||||
|
append(requirements[FILE]["transition"], "m"), r.Access,
|
||||||
|
)
|
||||||
|
if len(isTransition) > 0 {
|
||||||
|
lenPath = length("", r.Path)
|
||||||
|
}
|
||||||
|
return []int{
|
||||||
|
r.Qualifier.getLenAudit(),
|
||||||
|
r.Qualifier.getLenAccess(),
|
||||||
|
length("owner", r.Owner),
|
||||||
|
lenPath,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *File) setPaddings(max []int) {
|
||||||
|
r.Paddings = append(r.Qualifier.setPaddings(max[:2]), setPaddings(
|
||||||
|
max[2:], []string{"owner", ""},
|
||||||
|
[]any{r.Owner, r.Path})...,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *File) addLine(other Rule) bool {
|
||||||
|
if other.Kind() != r.Kind() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
letterI := getLetterIn(fileAlphabet, r.Path)
|
||||||
|
letterJ := getLetterIn(fileAlphabet, other.(*File).Path)
|
||||||
|
groupI, ok1 := fileAlphabetGroups[letterI]
|
||||||
|
groupJ, ok2 := fileAlphabetGroups[letterJ]
|
||||||
|
return letterI != letterJ && !(ok1 && ok2 && groupI == groupJ)
|
||||||
|
}
|
||||||
|
|
||||||
type Link struct {
|
type Link struct {
|
||||||
Base
|
Base
|
||||||
Qualifier
|
Qualifier
|
||||||
|
@ -88,3 +88,19 @@ func (r *IOUring) Merge(other Rule) bool {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *IOUring) Lengths() []int {
|
||||||
|
return []int{
|
||||||
|
r.Qualifier.getLenAudit(),
|
||||||
|
r.Qualifier.getLenAccess(),
|
||||||
|
length("", r.Access),
|
||||||
|
length("label=", r.Label),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *IOUring) setPaddings(max []int) {
|
||||||
|
r.Paddings = append(r.Qualifier.setPaddings(max[:2]), setPaddings(
|
||||||
|
max[2:], []string{"", "label="},
|
||||||
|
[]any{r.Access, r.Label})...,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
@ -73,6 +73,21 @@ func (m *MountConditions) Merge(other MountConditions) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m MountConditions) getLenFsType() int {
|
||||||
|
return length("fstype=", m.FsType)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m MountConditions) getLenOptions() int {
|
||||||
|
return length("options=", m.Options)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m MountConditions) setPaddings(max []int) []string {
|
||||||
|
return setPaddings(max,
|
||||||
|
[]string{"fstype=", "options="},
|
||||||
|
[]any{m.FsType, m.Options},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
type Mount struct {
|
type Mount struct {
|
||||||
Base
|
Base
|
||||||
Qualifier
|
Qualifier
|
||||||
@ -168,6 +183,24 @@ func (r *Mount) Merge(other Rule) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Mount) Lengths() []int {
|
||||||
|
return []int{
|
||||||
|
r.Qualifier.getLenAudit(),
|
||||||
|
r.Qualifier.getLenAccess(),
|
||||||
|
r.MountConditions.getLenFsType(),
|
||||||
|
r.MountConditions.getLenOptions(),
|
||||||
|
length("", r.Source),
|
||||||
|
length("", r.MountPoint),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Mount) setPaddings(max []int) {
|
||||||
|
r.Paddings = append(r.Qualifier.setPaddings(max[:2]), r.MountConditions.setPaddings(max[2:4])...)
|
||||||
|
r.Paddings = append(r.Paddings,
|
||||||
|
setPaddings(max[4:], []string{"", ""}, []any{r.Source, r.MountPoint})...,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
type Umount struct {
|
type Umount struct {
|
||||||
Base
|
Base
|
||||||
Qualifier
|
Qualifier
|
||||||
@ -246,6 +279,23 @@ func (r *Umount) Merge(other Rule) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Umount) Lengths() []int {
|
||||||
|
return []int{
|
||||||
|
r.Qualifier.getLenAudit(),
|
||||||
|
r.Qualifier.getLenAccess(),
|
||||||
|
r.MountConditions.getLenFsType(),
|
||||||
|
r.MountConditions.getLenOptions(),
|
||||||
|
length("", r.MountPoint),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Umount) setPaddings(max []int) {
|
||||||
|
r.Paddings = append(r.Qualifier.setPaddings(max[:2]), r.MountConditions.setPaddings(max[2:4])...)
|
||||||
|
r.Paddings = append(r.Paddings,
|
||||||
|
setPaddings(max[4:], []string{""}, []any{r.MountPoint})...,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
type Remount struct {
|
type Remount struct {
|
||||||
Base
|
Base
|
||||||
Qualifier
|
Qualifier
|
||||||
@ -324,3 +374,20 @@ func (r *Remount) Merge(other Rule) bool {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Remount) Lengths() []int {
|
||||||
|
return []int{
|
||||||
|
r.Qualifier.getLenAudit(),
|
||||||
|
r.Qualifier.getLenAccess(),
|
||||||
|
r.MountConditions.getLenFsType(),
|
||||||
|
r.MountConditions.getLenOptions(),
|
||||||
|
length("", r.MountPoint),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Remount) setPaddings(max []int) {
|
||||||
|
r.Paddings = append(r.Qualifier.setPaddings(max[:2]), r.MountConditions.setPaddings(max[2:4])...)
|
||||||
|
r.Paddings = append(r.Paddings,
|
||||||
|
setPaddings(max[4:], []string{""}, []any{r.MountPoint})...,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
@ -122,3 +122,21 @@ func (r *Mqueue) Merge(other Rule) bool {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Mqueue) Lengths() []int {
|
||||||
|
return []int{
|
||||||
|
r.Qualifier.getLenAudit(),
|
||||||
|
r.Qualifier.getLenAccess(),
|
||||||
|
length("", r.Access),
|
||||||
|
length("type=", r.Type),
|
||||||
|
length("label=", r.Label),
|
||||||
|
length("", r.Name),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Mqueue) setPaddings(max []int) {
|
||||||
|
r.Paddings = append(r.Qualifier.setPaddings(max[:2]), setPaddings(
|
||||||
|
max[2:], []string{"", "type=", "label=", ""},
|
||||||
|
[]any{r.Access, r.Type, r.Label, r.Name})...,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
@ -144,3 +144,20 @@ func (r *Network) Compare(other Rule) int {
|
|||||||
func (r *Network) Merge(other Rule) bool {
|
func (r *Network) Merge(other Rule) bool {
|
||||||
return false // Never merge network
|
return false // Never merge network
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Network) Lengths() []int {
|
||||||
|
return []int{
|
||||||
|
r.Qualifier.getLenAudit(),
|
||||||
|
r.Qualifier.getLenAccess(),
|
||||||
|
length("", r.Domain),
|
||||||
|
length("", r.Type),
|
||||||
|
length("", r.Protocol),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Network) setPaddings(max []int) {
|
||||||
|
r.Paddings = append(r.Qualifier.setPaddings(max[:2]), setPaddings(
|
||||||
|
max[2:], []string{"", "", ""},
|
||||||
|
[]any{r.Domain, r.Type, r.Protocol})...,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
@ -83,3 +83,20 @@ func (r *PivotRoot) Compare(other Rule) int {
|
|||||||
func (r *PivotRoot) Merge(other Rule) bool {
|
func (r *PivotRoot) Merge(other Rule) bool {
|
||||||
return false // Never merge pivot root
|
return false // Never merge pivot root
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *PivotRoot) Lengths() []int {
|
||||||
|
return []int{
|
||||||
|
r.Qualifier.getLenAudit(),
|
||||||
|
r.Qualifier.getLenAccess(),
|
||||||
|
length("oldroot=", r.OldRoot),
|
||||||
|
length("", r.NewRoot),
|
||||||
|
length("", r.TargetProfile),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *PivotRoot) setPaddings(max []int) {
|
||||||
|
r.Paddings = append(r.Qualifier.setPaddings(max[:2]), setPaddings(
|
||||||
|
max[2:], []string{"oldroot=", "", ""},
|
||||||
|
[]any{r.OldRoot, r.NewRoot, r.TargetProfile})...,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
@ -53,6 +53,12 @@ func (r *Comment) Merge(other Rule) bool {
|
|||||||
return false // Never merge comments
|
return false // Never merge comments
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Comment) Lengths() []int {
|
||||||
|
return []int{} // No len for comments
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Comment) setPaddings(max []int) {} // No paddings for comments
|
||||||
|
|
||||||
type Abi struct {
|
type Abi struct {
|
||||||
Base
|
Base
|
||||||
Path string
|
Path string
|
||||||
@ -109,6 +115,12 @@ func (r *Abi) Merge(other Rule) bool {
|
|||||||
return false // Never merge abi
|
return false // Never merge abi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Abi) Lengths() []int {
|
||||||
|
return []int{} // No len for abi
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Abi) setPaddings(max []int) {} // No paddings for abi
|
||||||
|
|
||||||
type Alias struct {
|
type Alias struct {
|
||||||
Base
|
Base
|
||||||
Path string
|
Path string
|
||||||
@ -157,6 +169,12 @@ func (r *Alias) Merge(other Rule) bool {
|
|||||||
return false // Never merge alias
|
return false // Never merge alias
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Alias) Lengths() []int {
|
||||||
|
return []int{} // No len for alias
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Alias) setPaddings(max []int) {} // No paddings for alias
|
||||||
|
|
||||||
type Include struct {
|
type Include struct {
|
||||||
Base
|
Base
|
||||||
IfExists bool
|
IfExists bool
|
||||||
@ -234,6 +252,12 @@ func (r *Include) Merge(other Rule) bool {
|
|||||||
return false // Never merge include
|
return false // Never merge include
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Include) Lengths() []int {
|
||||||
|
return []int{} // No len for include
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Include) setPaddings(max []int) {} // No paddings for include
|
||||||
|
|
||||||
type Variable struct {
|
type Variable struct {
|
||||||
Base
|
Base
|
||||||
Name string
|
Name string
|
||||||
@ -305,3 +329,9 @@ func (r *Variable) Merge(other Rule) bool {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Variable) Lengths() []int {
|
||||||
|
return []int{} // No len for variable
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Variable) setPaddings(max []int) {} // No paddings for variable
|
||||||
|
@ -103,6 +103,12 @@ func (p *Profile) Merge(other Rule) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Profile) Lengths() []int {
|
||||||
|
return []int{} // No len for profile
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Profile) setPaddings(max []int) {} // No paddings for profile
|
||||||
|
|
||||||
func (p *Profile) Sort() {
|
func (p *Profile) Sort() {
|
||||||
p.Rules = p.Rules.Sort()
|
p.Rules = p.Rules.Sort()
|
||||||
}
|
}
|
||||||
|
@ -90,3 +90,19 @@ func (r *Ptrace) Merge(other Rule) bool {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Ptrace) Lengths() []int {
|
||||||
|
return []int{
|
||||||
|
r.Qualifier.getLenAudit(),
|
||||||
|
r.Qualifier.getLenAccess(),
|
||||||
|
length("", r.Access),
|
||||||
|
length("peer=", r.Peer),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Ptrace) setPaddings(max []int) {
|
||||||
|
r.Paddings = append(r.Qualifier.setPaddings(max[:2]), setPaddings(
|
||||||
|
max[2:], []string{"", "peer="},
|
||||||
|
[]any{r.Access, r.Peer})...,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
@ -84,3 +84,18 @@ func (r *Rlimit) Compare(other Rule) int {
|
|||||||
func (r *Rlimit) Merge(other Rule) bool {
|
func (r *Rlimit) Merge(other Rule) bool {
|
||||||
return false // Never merge rlimit
|
return false // Never merge rlimit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Rlimit) Lengths() []int {
|
||||||
|
return []int{
|
||||||
|
length("", r.Key),
|
||||||
|
length("", r.Op),
|
||||||
|
length("", r.Value),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Rlimit) setPaddings(max []int) {
|
||||||
|
r.Paddings = setPaddings(
|
||||||
|
max, []string{"", "", ""},
|
||||||
|
[]any{r.Key, r.Op, r.Value},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
@ -121,3 +121,20 @@ func (r *Signal) Merge(other Rule) bool {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Signal) Lengths() []int {
|
||||||
|
return []int{
|
||||||
|
r.Qualifier.getLenAudit(),
|
||||||
|
r.Qualifier.getLenAccess(),
|
||||||
|
length("", r.Access),
|
||||||
|
length("set=", r.Set),
|
||||||
|
length("peer=", r.Peer),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Signal) setPaddings(max []int) {
|
||||||
|
r.Paddings = append(r.Qualifier.setPaddings(max[:2]), setPaddings(
|
||||||
|
max[2:], []string{"", "set=", "peer="},
|
||||||
|
[]any{r.Access, r.Set, r.Peer})...,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
@ -136,3 +136,22 @@ func (r *Unix) Merge(other Rule) bool {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Unix) Lengths() []int {
|
||||||
|
return []int{
|
||||||
|
r.Qualifier.getLenAudit(),
|
||||||
|
r.Qualifier.getLenAccess(),
|
||||||
|
length("", r.Access),
|
||||||
|
length("type=", r.Type),
|
||||||
|
length("protocol=", r.Protocol),
|
||||||
|
length("addr=", r.Address),
|
||||||
|
length("label=", r.Label),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Unix) setPaddings(max []int) {
|
||||||
|
r.Paddings = append(r.Qualifier.setPaddings(max[:2]), setPaddings(
|
||||||
|
max[2:], []string{"", "type=", "protocol=", "addr=", "label="},
|
||||||
|
[]any{r.Access, r.Type, r.Protocol, r.Address, r.Label})...,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
@ -69,5 +69,11 @@ func (r *Userns) Compare(other Rule) int {
|
|||||||
func (r *Userns) Merge(other Rule) bool {
|
func (r *Userns) Merge(other Rule) bool {
|
||||||
o, _ := other.(*Userns)
|
o, _ := other.(*Userns)
|
||||||
b := &r.Base
|
b := &r.Base
|
||||||
return b.merge(o.Base)
|
return b.merge(o.Base) // Always merge userns rules
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Userns) Lengths() []int {
|
||||||
|
return []int{} // No len for userns
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Userns) setPaddings(max []int) {} // No paddings for userns
|
||||||
|
@ -43,6 +43,53 @@ func merge(kind Kind, key string, a, b []string) []string {
|
|||||||
return slices.Compact(a)
|
return slices.Compact(a)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func length(prefix string, value any) int {
|
||||||
|
var res int
|
||||||
|
switch value := value.(type) {
|
||||||
|
case bool:
|
||||||
|
if value {
|
||||||
|
return len(prefix) + 1
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
case string:
|
||||||
|
if value != "" {
|
||||||
|
res = len(value) + len(prefix) + 1
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
case []string:
|
||||||
|
for _, v := range value {
|
||||||
|
lenV := len(v)
|
||||||
|
if lenV > 0 {
|
||||||
|
res += lenV + 1 // Space between values
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(value) > 1 {
|
||||||
|
res += 2 // Brackets on slices
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
default:
|
||||||
|
panic("length: unsupported type")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func setPaddings(max []int, prefixes []string, values []any) []string {
|
||||||
|
if len(max) != len(values) || len(max) != len(prefixes) {
|
||||||
|
panic("setPaddings: max, prefix, and values must have the same length")
|
||||||
|
}
|
||||||
|
res := make([]string, len(max))
|
||||||
|
for i, v := range values {
|
||||||
|
if max[i] == 0 {
|
||||||
|
res[i] = ""
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
count := max[i] - length(prefixes[i], v)
|
||||||
|
if count > 0 {
|
||||||
|
res[i] = strings.Repeat(" ", count)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
func compare(a, b any) int {
|
func compare(a, b any) int {
|
||||||
switch a := a.(type) {
|
switch a := a.(type) {
|
||||||
case int:
|
case int:
|
||||||
|
Loading…
Reference in New Issue
Block a user