This commit is contained in:
Wanjohi
2024-07-08 04:15:32 +03:00
committed by GitHub
8 changed files with 638 additions and 103 deletions

11
.nestri.yml Normal file
View File

@@ -0,0 +1,11 @@
version: "0.1"
games:
CyberPunk2047:
directory: /path/to/game
executable: CyberPunk2047.exe
gpu: 1
vendor: GPUidhere #(ex: vendor:N) e.g. nvidia:0 or amd:1
resolution:
height: 1080
width: 1920

95
cmd/neofetch.go Normal file
View File

@@ -0,0 +1,95 @@
package cmd
import (
"fmt"
"strings"
"github.com/charmbracelet/lipgloss"
"github.com/charmbracelet/lipgloss/table"
"github.com/muesli/termenv"
"github.com/spf13/cobra"
)
var neoFetchCmd = &cobra.Command{
Use: "neofetch",
Short: "Show important system information",
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
lipgloss.SetColorProfile(termenv.TrueColor)
// baseStyle := lipgloss.NewStyle().
// MarginTop(1).
// MarginRight(4).
// MarginBottom(1).
// MarginLeft(4)
var (
b strings.Builder
lines = strings.Split(art, "\n")
colors = []string{"#CC3D00", "#CC3D00"}
step = len(lines) / len(colors)
)
for i, l := range lines {
n := clamp(0, len(colors)-1, i/step)
b.WriteString(colorize(colors[n], l))
b.WriteRune('\n')
}
t := table.New().
Border(lipgloss.HiddenBorder()).BorderStyle(lipgloss.NewStyle().Width(3))
//TODO: show this specs
// info := &specs.Specs{}
// infoChan := make(chan specs.Specs, 1)
// var wg sync.WaitGroup
// wg.Add(1)
// go getSpecs(info, infoChan, &wg)
// wg.Wait()
// newInfo := <-infoChan
t.Row(b.String())
fmt.Print(t)
return nil
},
}
func init() {
rootCmd.AddCommand(neoFetchCmd)
// Here you will define your flags and configuration settings.
// Cobra supports Persistent Flags which will work for this command
// and all subcommands, e.g.:
// runCmd.PersistentFlags().String("foo", "", "A help for foo")
// Cobra supports local flags which will only run when this command
// is called directly, e.g.:
// runCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}
func colorize(c, s string) string {
return lipgloss.NewStyle().Foreground(lipgloss.Color(c)).Render(s)
}
func clamp(v, low, high int) int {
if high < low {
low, high = high, low
}
return min(high, max(low, v))
}
func min(a, b int) int {
if a < b {
return a
}
return b
}
func max(a, b int) int {
if a > b {
return a
}
return b
}

View File

@@ -7,20 +7,27 @@ import (
_ "embed"
"fmt"
"os"
"strings"
"sync"
"github.com/nestriness/cli/pkg/specs"
"github.com/charmbracelet/lipgloss"
"github.com/charmbracelet/lipgloss/table"
"github.com/muesli/termenv"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
//go:embed nestri.ascii
var art string
var cfgFile string
type GameConfig struct {
Directory string
Executable string
GPU int
Vendor string
Resolution struct {
Height int
Width int
}
}
// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
Use: "nestri",
@@ -31,51 +38,6 @@ var rootCmd = &cobra.Command{
},
}
var neoFetchCmd = &cobra.Command{
Use: "neofetch",
Short: "Show important system information",
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
lipgloss.SetColorProfile(termenv.TrueColor)
// baseStyle := lipgloss.NewStyle().
// MarginTop(1).
// MarginRight(4).
// MarginBottom(1).
// MarginLeft(4)
var (
b strings.Builder
lines = strings.Split(art, "\n")
colors = []string{"#CC3D00", "#CC3D00"}
step = len(lines) / len(colors)
)
for i, l := range lines {
n := clamp(0, len(colors)-1, i/step)
b.WriteString(colorize(colors[n], l))
b.WriteRune('\n')
}
t := table.New().
Border(lipgloss.HiddenBorder()).BorderStyle(lipgloss.NewStyle().Width(3))
//TODO: show this specs
// info := &specs.Specs{}
// infoChan := make(chan specs.Specs, 1)
// var wg sync.WaitGroup
// wg.Add(1)
// go getSpecs(info, infoChan, &wg)
// wg.Wait()
// newInfo := <-infoChan
t.Row(b.String())
fmt.Print(t)
return nil
},
}
// Execute adds all child commands to the root command and sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
@@ -86,55 +48,49 @@ func Execute() {
}
func init() {
cobra.OnInitialize(initConfig)
// Here you will define your flags and configuration settings.
// Cobra supports persistent flags, which, if defined here,
// will be global for your application.
rootCmd.AddCommand(neoFetchCmd)
// rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cli.yaml)")
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.nestri.yaml)")
// Cobra also supports local flags, which will only run
// when this action is called directly.
rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
// rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}
func colorize(c, s string) string {
return lipgloss.NewStyle().Foreground(lipgloss.Color(c)).Render(s)
}
// initConfig reads in config file and ENV variables if set.
func initConfig() {
if cfgFile != "" {
// Use config file from the flag.
viper.SetConfigFile(cfgFile)
} else {
// Search for config in the current directory
viper.AddConfigPath(".")
viper.SetConfigName(".nestri")
viper.SetConfigType("yaml")
// If not found in current directory, check in $HOME/.nestri/
if err := viper.ReadInConfig(); err != nil {
if _, ok := err.(viper.ConfigFileNotFoundError); ok {
// Find home directory.
home, err := os.UserHomeDir()
cobra.CheckErr(err)
// Search config in home directory with name ".nestri" (without extension).
viper.AddConfigPath(home)
viper.SetConfigType("yaml")
viper.SetConfigName(".nestri")
}
}
func clamp(v, low, high int) int {
if high < low {
low, high = high, low
}
return min(high, max(low, v))
}
func min(a, b int) int {
if a < b {
return a
viper.AutomaticEnv() // read in environment variables that match
// If a config file is found, read it in.
if err := viper.ReadInConfig(); err != nil {
fmt.Fprintln(os.Stderr, "Could not find a config file in local directory or in $HOME directory:")
}
return b
}
func max(a, b int) int {
if a > b {
return a
}
return b
}
func getSpecs(info *specs.Specs, infoChan chan specs.Specs, wg *sync.WaitGroup) {
defer wg.Done()
sys := specs.New()
// info.Userhost = getUserHostname()
// info.OS = getOSName()
// info.Kernel = getKernelVersion()
// info.Uptime = getUptime()
// info.Shell = getShell()
// info.CPU = getCPUName()
// info.RAM = getMemStats()
info.GPU, _ = sys.GetGPUInfo()
// info.SystemArch, _ = getSystemArch()
// info.DiskUsage, _ = getDiskUsage()
infoChan <- *info
}

90
cmd/run.go Normal file
View File

@@ -0,0 +1,90 @@
package cmd
import (
"fmt"
"runtime"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
// this is the "nestri run" subcommand, takes no arguments for now
var runCmd = &cobra.Command{
Use: "run",
Short: "Run a game using nestri",
Args: cobra.MinimumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
if runtime.GOOS != "linux" {
//make sure os is linux
fmt.Println("This command is only supported on Linux.")
return nil
}
//The main job here is to:
//1. look for an exe in a certain directory,
//2. mount the directory inside the container
//3. Run the nestri docker container
//4. SSH into the container and set up everything
//5. Run the game
//6. Provide the URL to play or throw an error otherwise.
// The last argument is the game to run
game := args[len(args)-1]
// Load game configuration
var gameConfig GameConfig
if err := viper.UnmarshalKey(fmt.Sprintf("games.%s", game), &gameConfig); err != nil {
return fmt.Errorf("error parsing game configuration: %w", err)
}
flags := cmd.Flags()
if flags.Changed("directory") || flags.Changed("d") {
gameConfig.Directory, _ = flags.GetString("directory")
}
if flags.Changed("executable") || flags.Changed("x") {
gameConfig.Executable, _ = flags.GetString("executable")
}
if flags.Changed("gpu") {
gameConfig.GPU, _ = flags.GetInt("gpu")
}
if flags.Changed("vendor") || flags.Changed("v") {
gameConfig.Vendor, _ = flags.GetString("vendor")
}
if flags.Changed("height") || flags.Changed("H") {
gameConfig.Resolution.Height, _ = flags.GetInt("height")
}
if flags.Changed("width") || flags.Changed("W") {
gameConfig.Resolution.Width, _ = flags.GetInt("width")
}
fmt.Println("Game config:", gameConfig)
return nil
},
}
func init() {
rootCmd.AddCommand(runCmd)
runCmd.Flags().StringP("directory", "d", "", "Game directory")
runCmd.Flags().StringP("executable", "x", "", "Game executable")
runCmd.Flags().Int("gpu", 0, "GPU number")
runCmd.Flags().StringP("vendor", "v", "", "GPU vendor")
runCmd.Flags().IntP("height", "H", 1080, "Screen height")
runCmd.Flags().IntP("width", "W", 1920, "Screen width")
// viper.BindPFlag("directory", runCmd.Flags().Lookup("directory"))
// viper.BindPFlag("executable", runCmd.Flags().Lookup("executable"))
// viper.BindPFlag("gpu", runCmd.Flags().Lookup("gpu"))
// viper.BindPFlag("vendor", runCmd.Flags().Lookup("vendor"))
// viper.BindPFlag("resolution.height", runCmd.Flags().Lookup("height"))
// viper.BindPFlag("resolution.width", runCmd.Flags().Lookup("width"))
viper.BindPFlag("games.*.directory", runCmd.Flags().Lookup("directory"))
viper.BindPFlag("games.*.executable", runCmd.Flags().Lookup("executable"))
viper.BindPFlag("games.*.gpu", runCmd.Flags().Lookup("gpu"))
viper.BindPFlag("games.*.vendor", runCmd.Flags().Lookup("vendor"))
viper.BindPFlag("games.*.resolution.height", runCmd.Flags().Lookup("height"))
viper.BindPFlag("games.*.resolution.width", runCmd.Flags().Lookup("width"))
}

30
go.mod
View File

@@ -2,17 +2,37 @@ module github.com/nestriness/cli
go 1.22.2
require (
github.com/charmbracelet/lipgloss v0.11.0
github.com/muesli/termenv v0.15.2
github.com/spf13/cobra v1.8.1
github.com/spf13/viper v1.19.0
)
require (
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
github.com/charmbracelet/lipgloss v0.11.0 // indirect
github.com/charmbracelet/x/ansi v0.1.1 // indirect
github.com/charmbracelet/x/ansi v0.1.2 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/muesli/termenv v0.15.2 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/spf13/cobra v1.8.0 // indirect
github.com/sagikazarmark/locafero v0.6.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
github.com/spf13/afero v1.11.0 // indirect
github.com/spf13/cast v1.6.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
golang.org/x/sys v0.19.0 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/exp v0.0.0-20240707233637-46b078467d37 // indirect
golang.org/x/sys v0.22.0 // indirect
golang.org/x/text v0.16.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

76
go.sum
View File

@@ -2,29 +2,91 @@ github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiE
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
github.com/charmbracelet/lipgloss v0.11.0 h1:UoAcbQ6Qml8hDwSWs0Y1cB5TEQuZkDPH/ZqwWWYTG4g=
github.com/charmbracelet/lipgloss v0.11.0/go.mod h1:1UdRTH9gYgpcdNN5oBtjbu/IzNKtzVtb7sqN1t9LNn8=
github.com/charmbracelet/x/ansi v0.1.1 h1:CGAduulr6egay/YVbGc8Hsu8deMg1xZ/bkaXTPi1JDk=
github.com/charmbracelet/x/ansi v0.1.1/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw=
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/charmbracelet/x/ansi v0.1.2 h1:6+LR39uG8DE6zAmbu023YlqjJHkYXDF1z36ZwzO4xZY=
github.com/charmbracelet/x/ansi v0.1.2/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw=
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo=
github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8=
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
github.com/sagikazarmark/locafero v0.6.0 h1:ON7AQg37yzcRPU69mt7gwhFEBwxI6P9T4Qu3N51bwOk=
github.com/sagikazarmark/locafero v0.6.0/go.mod h1:77OmuIc6VTraTXKXIs/uvUxKGUXjE1GbemJYHqdNjX0=
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI=
github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
golang.org/x/exp v0.0.0-20240707233637-46b078467d37 h1:uLDX+AfeFCct3a2C7uIWBKMJIR3CJMhcgfrUAqjRK6w=
golang.org/x/exp v0.0.0-20240707233637-46b078467d37/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@@ -1,6 +1,5 @@
/*
Copyright © 2024 NAME HERE <EMAIL ADDRESS>
*/
package main

302
root.go.txt Normal file
View File

@@ -0,0 +1,302 @@
// /*
// Copyright © 2024 Nestri <>
// */
// package main
// import (
// _ "embed"
// "fmt"
// "os"
// "os/exec"
// "path/filepath"
// "runtime"
// "strings"
// "time"
// "github.com/charmbracelet/lipgloss"
// "github.com/charmbracelet/lipgloss/table"
// "github.com/muesli/termenv"
// "github.com/spf13/cobra"
// "github.com/spf13/viper"
// )
// //go:embed nestri.ascii
// var art string
// var (
// gpu int
// hdr bool
// )
// // rootCmd represents the base command when called without any subcommands
// // For a good reference point, start here: https://github.com/charmbracelet/taskcli/blob/main/cmds.go
// var rootCmd = &cobra.Command{
// Use: "nestri",
// Short: "A CLI tool to manage your cloud gaming service",
// Args: cobra.NoArgs,
// RunE: func(cmd *cobra.Command, args []string) error {
// return cmd.Help()
// },
// }
// // this is for the "nestri neofetch" subcommand, has no arguments
// var neoFetchCmd = &cobra.Command{
// Use: "neofetch",
// Short: "Show important system information",
// Args: cobra.NoArgs,
// RunE: func(cmd *cobra.Command, args []string) error {
// lipgloss.SetColorProfile(termenv.TrueColor)
// baseStyle := lipgloss.NewStyle().
// PaddingTop(1).
// PaddingRight(4).
// PaddingBottom(1).
// PaddingLeft(4)
// var (
// b strings.Builder
// lines = strings.Split(art, "\n")
// colors = []string{"#F8481C", "#F74127", "#F53B30", "#F23538", "#F02E40"}
// step = len(lines) / len(colors)
// )
// for i, l := range lines {
// n := clamp(0, len(colors)-1, i/step)
// b.WriteString(colorize(colors[n], l))
// b.WriteRune('\n')
// }
// t := table.New().
// Border(lipgloss.HiddenBorder())
// t.Row(baseStyle.Render(b.String()), baseStyle.Render("System Info goes here"))
// fmt.Print(t)
// return nil
// },
// }
// // this is the "nestri run" subcommand, takes no arguments for now
// var runCmd = &cobra.Command{
// Use: "run",
// Short: "Run a game using nestri",
// Args: cobra.MaximumNArgs(1),
// RunE: func(cmd *cobra.Command, args []string) error {
// if runtime.GOOS != "linux" {
// //make sure os is linux
// fmt.Println("This command is only supported on Linux.")
// return nil
// }
// var game string
// if len(args) > 0 {
// game = args[0]
// viper.Set("game", game)
// viper.WriteConfig()
// } else {
// game = viper.GetString("game")
// if filepath.Ext(game) != ".exe" {
// return fmt.Errorf("Make sure the game is a .exe")
// }
// if game == "" {
// return fmt.Errorf("no game specified and no previous game selected")
// }
// }
// fmt.Printf("Running game: %s\n\n", game)
// if gpu > 0 {
// fmt.Print("Using gpu %s\n", gpu)
// }
// if hdr {
// fmt.Println("Enabling HDR mode")
// }
// //get linux version
// versionCmd := exec.Command("grep", "VERSION", "/etc/os-release")
// versionOutput, err := versionCmd.CombinedOutput()
// if err != nil {
// return fmt.Errorf("error getting linux version:")
// }
// fmt.Printf("Linux version:\n%s\n", string(versionOutput))
// //Step 1: change to games dir
// fmt.Println("changing to game dir.") //this is a temp command for debug as well as leads to a hardcoded dir
// HomeDir, err := os.UserHomeDir()
// if err != nil {
// return fmt.Errorf("error getting home directory %v\n", err)
// }
// err = os.Chdir(fmt.Sprintf("%s/game", HomeDir))
// if err != nil {
// return fmt.Errorf("error changing directory: %v\n", err)
// }
// //verify we are in game dir
// dir, err := os.Getwd()
// if err != nil {
// return fmt.Errorf("error getting current directory: %v\n", err)
// }
// fmt.Printf("Current directory: %s\n\n", dir)
// //list games dir
// listDir := exec.Command("ls", "-la", ".")
// listDirOutput, err := listDir.CombinedOutput()
// if err != nil {
// fmt.Errorf("error listing games: %v\n")
// }
// fmt.Printf("List of Games: \n%s\n", listDirOutput)
// //step 2: Generate a Session ID
// //generate id
// SID := exec.Command("bash", "-c", "head /dev/urandom | LC_ALL=C tr -dc 'a-zA-Z0-9' | head -c 16")
// //save output to variable
// output, err := SID.Output()
// if err != nil {
// fmt.Errorf("Error generating Session ID: %v\n", err)
// }
// sessionID := strings.TrimSpace(string(output))
// fmt.Printf("Your Session ID is: %s\n\n", sessionID)
// //step 3: Launch netris server
// fmt.Println("Installing Netris/Launching Netris Server\n")
// checkRunning := exec.Command("sudo", "docker", "ps", "-q", "-f", "name=netris")
// containerId, err := checkRunning.Output()
// if err != nil {
// return fmt.Errorf("error checking running Docker container: %v", err)
// }
// if len(containerId) == 0 {
// checkExisting := exec.Command("sudo", "docker", "ps", "-aq", "-f", "name=netris")
// containerId, err = checkExisting.Output()
// if err != nil {
// return fmt.Errorf("error checking for existing docker container: %v", err)
// }
// if len(containerId) == 0 {
// installCmd := exec.Command(
// "sudo", "docker", "run", "-d", "--gpus", "all", "--device=/dev/dri",
// "--name", "netris", "-it", "--entrypoint", "/bin/bash",
// "-e", fmt.Sprintf("SESSION_ID=%s", sessionID),
// "-v", fmt.Sprintf("%s:/game", dir), "-p", "8080:8080/udp",
// "--cap-add=SYS_NICE", "--cap-add=SYS_ADMIN", "ghcr.io/netrisdotme/netris/server:nightly",
// )
// installCmd.Stdout = os.Stdout
// installCmd.Stderr = os.Stderr
// if err := installCmd.Run(); err != nil {
// return fmt.Errorf("error running docker command: %v", err)
// }
// } else {
// startContainer := exec.Command("sudo", "docker", "start", "netris")
// startContainer.Stdout = os.Stdout
// startContainer.Stderr = os.Stderr
// if err := startContainer.Run(); err != nil {
// return fmt.Errorf("error starting existing Docker container: %v", err)
// }
// }
// }
// //main part of step 4:
// //start netris server
// fmt.Println("starting netris server\n\n")
// checkFileCmd := exec.Command("sudo", "docker", "exec", "netris", "ls", "-la", "/tmp")
// output, err = checkFileCmd.Output()
// if err != nil {
// return fmt.Errorf("error checking /tmp dir in docker container: %v\n", err)
// }
// if !strings.Contains(string(output), ".X11-unix") {
// startupCmd := exec.Command("sudo", "docker", "exec", "netris", "/etc/startup.sh", ">", "/dev/null", "&")
// startupCmd.Stdout = os.Stdout
// startupCmd.Stderr = os.Stderr
// if err := startupCmd.Run(); err != nil {
// return fmt.Errorf("error running startup command: %v\n", err)
// }
// for {
// time.Sleep(7 * time.Minute)
// output, err := checkFileCmd.Output()
// if err != nil {
// return fmt.Errorf("error checking /tmp directory in container: %v\n", err)
// }
// if strings.Contains(string(output), ".X11-unix") {
// break
// }
// }
// }
// gameCmd := fmt.Sprintf("netris-proton -pr %s", game)
// execCmd := exec.Command("sudo", "docker", "exec", "netris", gameCmd)
// execCmd.Stdout = os.Stdout
// execCmd.Stderr = os.Stderr
// if err := execCmd.Run(); err != nil {
// return fmt.Errorf("error executing game command in docker container: %v\n", err)
// }
// return nil
// },
// }
// // Execute adds all child commands to the root command and sets flags appropriately.
// // This is called by main.main(). It only needs to happen once to the rootCmd.
// func Execute() {
// err := rootCmd.Execute()
// if err != nil {
// os.Exit(1)
// }
// }
// func init() {
// rootCmd.AddCommand(neoFetchCmd)
// rootCmd.AddCommand(runCmd)
// runCmd.Flags().IntVar(&gpu, "gpu", 0, "Specify GPU index")
// runCmd.Flags().BoolVar(&hdr, "hdr", false, "Enable HDR mode")
// viper.SetConfigName("config")
// viper.SetConfigType("yaml")
// viper.AddConfigPath(".")
// if err := viper.ReadInConfig(); err != nil {
// if _, ok := err.(viper.ConfigFileNotFoundError); ok {
// } else {
// fmt.Println("error reading config file: %v(you should be able to ignore this)", err)
// }
// }
// //If you want to add subcommands to run for example "netri run -fsr" do it like this
// // runCmd.Flags().BoolP("fsr", "f", false, "Run the Game with FSR enabled or not")
// }
// func colorize(c, s string) string {
// return lipgloss.NewStyle().Foreground(lipgloss.Color(c)).Render(s)
// }
// func clamp(v, low, high int) int {
// if high < low {
// low, high = high, low
// }
// return min(high, max(low, v))
// }
// func min(a, b int) int {
// if a < b {
// return a
// }
// return b
// }
// func max(a, b int) int {
// if a > b {
// return a
// }
// return b
// }