initial
This commit is contained in:
commit
8d15fa9731
9 changed files with 287 additions and 0 deletions
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
mix.lock
|
||||
*.mix.hjson
|
||||
*.exe
|
11
README.md
Normal file
11
README.md
Normal file
|
@ -0,0 +1,11 @@
|
|||
# 🍜 mix
|
||||
> ` a declerative file-based package manager for windows.`
|
||||
|
||||
|
||||
## features
|
||||
- uses winget 😭
|
||||
|
||||
## requirements
|
||||
- windows 10+ ofc
|
||||
- recent version of [Go](https://golang.org/)
|
||||
- [winget](https://github.com/microsoft/winget-cli)
|
115
cmd/sync.go
Normal file
115
cmd/sync.go
Normal file
|
@ -0,0 +1,115 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os/exec"
|
||||
|
||||
"git.iwakura.rip/grng/mix/mix"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var SyncCommand = &cli.Command{
|
||||
Name: "sync",
|
||||
Action: func(context.Context, *cli.Command) error {
|
||||
config := mix.Config
|
||||
if len(config) == 0 {
|
||||
return cli.Exit("No configuration files found", 1)
|
||||
}
|
||||
|
||||
if mix.Lock == nil {
|
||||
return cli.Exit("No lockfile found", 1)
|
||||
}
|
||||
|
||||
var cfg mix.MixConfig
|
||||
for _, c := range config {
|
||||
cfg = c
|
||||
break
|
||||
}
|
||||
|
||||
desired := make(map[string]mix.MixPackage)
|
||||
for _, group := range cfg {
|
||||
for _, pkg := range group.Packages {
|
||||
desired[pkg.Id] = pkg
|
||||
}
|
||||
}
|
||||
|
||||
var newLock mix.MixLock
|
||||
for _, lockPkg := range mix.Lock {
|
||||
if _, ok := desired[lockPkg.Id]; !ok {
|
||||
rmPackage(lockPkg.Id)
|
||||
} else {
|
||||
newLock = append(newLock, lockPkg)
|
||||
}
|
||||
}
|
||||
mix.Lock = newLock
|
||||
|
||||
for _, pkg := range desired {
|
||||
found := false
|
||||
for _, lockPkg := range mix.Lock {
|
||||
if lockPkg.Id == pkg.Id {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
err := syncPackage(pkg)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to add package %s: %w", pkg.Id, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
err := mix.SaveLockFile()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to save lock file: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
func syncPackage(pkg mix.MixPackage) error {
|
||||
isInstalled := false
|
||||
for _, lockPkg := range mix.Lock {
|
||||
if lockPkg.Id == pkg.Id {
|
||||
isInstalled = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if isInstalled {
|
||||
return nil
|
||||
}
|
||||
|
||||
fmt.Printf("Installing package %s...\n", pkg.Id)
|
||||
cmd := exec.Command("winget", "install", "-h", "-e", "--id", pkg.Id, "-v", pkg.Version)
|
||||
cmd.Stdout = nil
|
||||
cmd.Stderr = nil
|
||||
err := cmd.Run()
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to install package %s: %w", pkg.Id, err)
|
||||
}
|
||||
|
||||
fmt.Printf("Package %s installed successfully!\n", pkg.Id)
|
||||
mix.Lock = append(mix.Lock, mix.MixLockPackage{
|
||||
Id: pkg.Id,
|
||||
Version: pkg.Version,
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func rmPackage(id string) {
|
||||
fmt.Printf("Removing package %s...\n", id)
|
||||
cmd := exec.Command("winget", "uninstall", "-h", "-e", "--id", id)
|
||||
cmd.Stdout = nil
|
||||
cmd.Stderr = nil
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to uninstall package %s: %v\n", id, err)
|
||||
} else {
|
||||
fmt.Printf("Package %s removed successfully!\n", id)
|
||||
}
|
||||
}
|
8
go.mod
Normal file
8
go.mod
Normal file
|
@ -0,0 +1,8 @@
|
|||
module git.iwakura.rip/grng/mix
|
||||
|
||||
go 1.23.4
|
||||
|
||||
require (
|
||||
github.com/hjson/hjson-go/v4 v4.5.0 // indirect
|
||||
github.com/urfave/cli/v3 v3.3.8 // indirect
|
||||
)
|
4
go.sum
Normal file
4
go.sum
Normal file
|
@ -0,0 +1,4 @@
|
|||
github.com/hjson/hjson-go/v4 v4.5.0 h1:ZHLiZ+HaGqPOtEe8T6qY8QHnoEsAeBv8wqxniQAp+CY=
|
||||
github.com/hjson/hjson-go/v4 v4.5.0/go.mod h1:4zx6c7Y0vWcm8IRyVoQJUHAPJLXLvbG6X8nk1RLigSo=
|
||||
github.com/urfave/cli/v3 v3.3.8 h1:BzolUExliMdet9NlJ/u4m5vHSotJ3PzEqSAZ1oPMa/E=
|
||||
github.com/urfave/cli/v3 v3.3.8/go.mod h1:FJSKtM/9AiiTOJL4fJ6TbMUkxBXn7GO9guZqoZtpYpo=
|
17
main.go
Normal file
17
main.go
Normal file
|
@ -0,0 +1,17 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
|
||||
"git.iwakura.rip/grng/mix/cmd"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
func main() {
|
||||
(&cli.Command{
|
||||
Commands: []*cli.Command{
|
||||
cmd.SyncCommand,
|
||||
},
|
||||
}).Run(context.Background(), os.Args)
|
||||
}
|
21
mix.hjson.example
Normal file
21
mix.hjson.example
Normal file
|
@ -0,0 +1,21 @@
|
|||
default: {
|
||||
packages: [
|
||||
{
|
||||
id: "wez.wezterm"
|
||||
version: "20240203-110809-5046fc22"
|
||||
config: [
|
||||
{
|
||||
type: "raw"
|
||||
path: "~/.wezterm.lua"
|
||||
data:
|
||||
'''
|
||||
local wezterm = require 'wezterm'
|
||||
local config = {}
|
||||
config.color_scheme = 'Batman'
|
||||
return config
|
||||
'''
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
1
mix.lock.example
Normal file
1
mix.lock.example
Normal file
|
@ -0,0 +1 @@
|
|||
[]
|
107
mix/files.go
Normal file
107
mix/files.go
Normal file
|
@ -0,0 +1,107 @@
|
|||
package mix
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
hjson "github.com/hjson/hjson-go/v4"
|
||||
)
|
||||
|
||||
var Config = ConfigFiles()
|
||||
var Lock = LockFile()
|
||||
|
||||
// *.mix.hjson
|
||||
func ConfigFiles() map[string]MixConfig {
|
||||
dir, err := os.ReadDir(".")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
files := []string{}
|
||||
|
||||
for _, file := range dir {
|
||||
if file.IsDir() {
|
||||
continue
|
||||
}
|
||||
|
||||
if strings.HasSuffix(file.Name(), ".mix.hjson") {
|
||||
files = append(files, file.Name())
|
||||
}
|
||||
}
|
||||
|
||||
config := make(map[string]MixConfig)
|
||||
|
||||
for _, file := range files {
|
||||
f, err := os.ReadFile(file)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
var cfg MixConfig
|
||||
err = hjson.Unmarshal(f, &cfg)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if len(cfg) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
config[file] = cfg
|
||||
}
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
func SaveLockFile() error {
|
||||
data, err := hjson.Marshal(Lock)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = os.WriteFile("mix.lock", data, 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type MixConfig map[string]MixGroup
|
||||
|
||||
type MixGroup struct {
|
||||
Packages []MixPackage `json:"packages"`
|
||||
}
|
||||
|
||||
type MixPackage struct {
|
||||
Id string `json:"id"`
|
||||
Version string `json:"version"`
|
||||
Config []MixPackageConfig `json:"config"`
|
||||
}
|
||||
|
||||
type MixPackageConfig struct {
|
||||
Type string `json:"type"`
|
||||
Path string `json:"path"`
|
||||
Data interface{} `json:"data"`
|
||||
}
|
||||
|
||||
func LockFile() MixLock {
|
||||
file, err := os.ReadFile("mix.lock")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
var lock MixLock
|
||||
err = hjson.Unmarshal(file, &lock)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return lock
|
||||
}
|
||||
|
||||
type MixLock []MixLockPackage
|
||||
type MixLockPackage struct {
|
||||
Id string `json:"id"`
|
||||
Version string `json:"version"`
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue