Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion grml.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
version: 1
version: 2
project: grml

env:
Expand Down
7 changes: 6 additions & 1 deletion internal/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,12 @@ func (a *app) load() (err error) {
if err != nil {
return
}
a.Println("parsed grml file and reloaded successfully")

_, err = a.Println("parsed grml file and reloaded successfully")
if err != nil {
return err
}

a.printOptions()
return
},
Expand Down
100 changes: 76 additions & 24 deletions internal/app/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,22 +45,75 @@ func (a *app) initOptions() {
cmd.AddCommand(&grumble.Command{
Name: "check",
Help: "select options",
Args: func(a *grumble.Args) {
a.String("option", "name of option", grumble.Default(""))
},
Run: func(c *grumble.Context) error {
l := len(a.options.Bools)

// Multiple args are provided.
if len(c.Args) > 1 {
return fmt.Errorf("invalid args: arg should be a path")
}
path := c.Args.String("option")

// No arg is provided.
if path == "" {
l := len(a.options.Bools)
if l == 0 {
return fmt.Errorf("no check options available")
}

options := make([]string, l)
var defaults []string

i := 0
for name, o := range a.options.Bools {
options[i] = name
if o {
defaults = append(defaults, name)
}
i++
}

var selected []string
prompt := &survey.MultiSelect{
Message: "Select Options:",
Options: options,
Default: defaults,
}
err := survey.AskOne(prompt, &selected, nil)
if err != nil {
return err
}

Loop:
for _, o := range options {
for _, s := range selected {
if s == o {
a.options.Bools[o] = true
continue Loop
}
}
a.options.Bools[o] = false
}
return nil
}

// Arg is provided but not a valid option.
val, ok := a.options.Choices[path]
if !ok {
return fmt.Errorf("invalid option: %v", path)
}

l := len(val.Options)
if l == 0 {
return fmt.Errorf("no check options available")
return fmt.Errorf("folder is empty")
}

options := make([]string, l)
var defaults []string

i := 0
for name, o := range a.options.Bools {
defaults := strings.Split(val.Active, ";")
for i, name := range a.options.Choices[path].Options {
options[i] = name
if o {
defaults = append(defaults, name)
}
i++
}

var selected []string
Expand All @@ -69,18 +122,13 @@ func (a *app) initOptions() {
Options: options,
Default: defaults,
}
survey.AskOne(prompt, &selected, nil)

Loop:
for _, o := range options {
for _, s := range selected {
if s == o {
a.options.Bools[o] = true
continue Loop
}
}
a.options.Bools[o] = false

err := survey.AskOne(prompt, &selected, nil)
if err != nil {
return err
}

val.Active = strings.Join(selected, ";")
return nil
},
})
Expand Down Expand Up @@ -115,7 +163,11 @@ func (a *app) initOptions() {
Message: "Select Option:",
Options: o.Options,
}
survey.AskOne(prompt, &o.Active, nil)
err := survey.AskOne(prompt, &o.Active, nil)
if err != nil {
return err
}

return nil
},
})
Expand All @@ -138,7 +190,7 @@ func (a *app) printOptions() {
config.Prefix = " "

// Print all check options sorted.
for k, _ := range a.options.Bools {
for k := range a.options.Bools {
keys = append(keys, k)
}
sort.Strings(keys)
Expand All @@ -155,7 +207,7 @@ func (a *app) printOptions() {
// Print all choice options sorted.
output = nil
keys = nil
for k, _ := range a.options.Choices {
for k := range a.options.Choices {
keys = append(keys, k)
}
sort.Strings(keys)
Expand Down
24 changes: 20 additions & 4 deletions internal/manifest/manifest.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@ package manifest

import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"sort"
"strings"

"github.com/desertbit/grml/internal/options"
Expand Down Expand Up @@ -118,6 +119,21 @@ func (m *Manifest) ParseOptions() (o *options.Options, err error) {
Options: list,
}

case string:
entries, err := filepath.Glob(v)
if err != nil || len(entries) == 0 {
return nil, fmt.Errorf("failed reading path: %v: %v", name, v)
}

sort.Slice(entries, func(i, j int) bool {
return naturalLess(entries[i], entries[j])
})

o.Choices[name] = &options.Choice{
Active: entries[0],
Options: entries,
}

default:
err = fmt.Errorf("invalid option: %v: %v", name, i)
return
Expand All @@ -128,7 +144,7 @@ func (m *Manifest) ParseOptions() (o *options.Options, err error) {

// Parse a grml build file.
func Parse(path string) (m *Manifest, err error) {
data, err := ioutil.ReadFile(path)
data, err := os.ReadFile(path)
if err != nil {
return
}
Expand All @@ -148,7 +164,7 @@ func Parse(path string) (m *Manifest, err error) {
return
}

// Parse inlcudes.
// Parse includes.
rootPath := filepath.Dir(path)
err = parseIncludes(rootPath, m.Commands)
if err != nil {
Expand All @@ -165,7 +181,7 @@ func parseIncludes(rootPath string, cmds Commands) (err error) {
}

var data []byte
data, err = ioutil.ReadFile(filepath.Join(rootPath, cmd.Include))
data, err = os.ReadFile(filepath.Join(rootPath, cmd.Include))
if err != nil {
return
}
Expand Down
66 changes: 66 additions & 0 deletions internal/manifest/utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* grml - A simple build automation tool written in Go
* Copyright (C) 2017 Roland Singer <roland.singer[at]desertbit.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package manifest

import (
"path/filepath"
"regexp"
"strconv"
)

var numberRegex = regexp.MustCompile(`(\d+)`)

// naturalLess compares two strings in a natural way.
func naturalLess(a, b string) bool {
aBase := filepath.Base(a)
bBase := filepath.Base(b)

// Split into text and numeric segments
aParts := numberRegex.Split(aBase, -1)
bParts := numberRegex.Split(bBase, -1)
aNums := numberRegex.FindAllString(aBase, -1)
bNums := numberRegex.FindAllString(bBase, -1)

minLen := len(aParts)
if len(bParts) < minLen {
minLen = len(bParts)
}

for i := 0; i < minLen; i++ {
// Compare text segments first
if aParts[i] != bParts[i] {
return aParts[i] < bParts[i]
}

// If we have numeric segments at this position, compare them
if i < len(aNums) && i < len(bNums) {
aNum, _ := strconv.Atoi(aNums[i])
bNum, _ := strconv.Atoi(bNums[i])
if aNum != bNum {
return aNum < bNum
}
} else if i < len(aNums) {
return false
} else if i < len(bNums) {
return true
}
}

return aBase < bBase
}