Sync a declarative package list with the pacman package manager
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

115 lines
2.1 KiB

package input
import (
"bufio"
"errors"
"os"
"path/filepath"
"strings"
"github.com/Riyyi/declpac/pkg/lib"
)
var ErrEmptyList = errors.New("package list is empty")
// -----------------------------------------
// public
func Merge(packages map[string]bool) ([]string, error) {
result := make([]string, 0, len(packages))
for name := range packages {
result = append(result, name)
}
if len(result) == 0 {
return nil, ErrEmptyList
}
return result, nil
}
func ReadPackages(stateFiles []string) (map[string]bool, error) {
packages := make(map[string]bool)
for _, file := range stateFiles {
expanded := lib.ExpandPath(file)
if err := readStateFile(expanded, packages); err != nil {
return nil, err
}
}
implicitStateFile := getImplicitStateFile()
if fileExists(implicitStateFile) {
if err := readStateFile(implicitStateFile, packages); err != nil {
return nil, err
}
}
if err := readStdin(packages); err != nil {
return nil, err
}
return packages, nil
}
// -----------------------------------------
// private
func fileExists(path string) bool {
_, err := os.Stat(path)
return err == nil
}
func getImplicitStateFile() string {
cfgDir := os.Getenv("XDG_CONFIG_HOME")
if cfgDir == "" {
cfgDir = "~/.config"
}
cfgDir = lib.ExpandPath(cfgDir)
return filepath.Join(cfgDir, "declpac")
}
func normalizePackageName(name string) string {
name = strings.TrimSpace(name)
if name == "" || strings.HasPrefix(name, "#") {
return ""
}
return name
}
func readStateFile(path string, packages map[string]bool) error {
file, err := os.Open(path)
if err != nil {
return err
}
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
name := normalizePackageName(scanner.Text())
if name != "" {
packages[name] = true
}
}
return scanner.Err()
}
func readStdin(packages map[string]bool) error {
info, err := os.Stdin.Stat()
if err != nil {
return err
}
if (info.Mode() & os.ModeCharDevice) != 0 {
return nil
}
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
name := normalizePackageName(scanner.Text())
if name != "" {
packages[name] = true
}
}
return scanner.Err()
}