summaryrefslogtreecommitdiffstats
path: root/composer.json
blob: c1d7d2f41071e2f7daac4cd00b8544520c5689db (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
{
    "type": "project",
    "license": "AGPL-3.0",
    "description": "An RSS/Atom feed reader. Requires Nextcloud backgroundjobs or an updater script to be enabled to update your feeds. See the README.md in the apps top directory",
    "homepage": "https://github.com/nextcloud/news",
    "authors": [
        {
            "name": "Bernhard Posselt",
            "email": "dev@bernhard-posselt.com",
            "homepage": "https://bernhard-posselt.com",
            "role": "Developer"
        },
        {
            "name": "Alessandro Cosentino",
            "homepage": "http://algorithmsforthekitchen.com/",
            "email": "cosenal@gmail.com",
            "role": "Developer"
        },
        {
            "name": "Jan-Christoph Borchardt",
            "email": "hey@jancborchardt.net",
            "homepage": "http://jancborchardt.net/",
            "role": "Designer"
        }
    ],
    "support": {
        "irc": "irc://irc.freenode.org/nextcloud-news",
        "issues": "https://github.com/nextcloud/news/issues",
        "source": "https://github.com/nextcloud/news/"
    },
    "require": {
        "ezyang/htmlpurifier": "4.8",
        "fguillot/picofeed": "0.1.28",
        "pear/net_url2": "2.2.1",
        "riimu/kit-pathjoin": "1.1.2"
    }
}
/* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
package cmd

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"

	"strings"

	"github.com/Phantas0s/devdash/internal"
	"github.com/mitchellh/go-homedir"
	"github.com/spf13/viper"
)

const (
	// keys
	kQuit      = "C-c"
	kHotReload = "C-r"
)

type config struct {
	General  General   `mapstructure:"general"`
	Projects []Project `mapstructure:"projects"`
}

type General struct {
	Keys    map[string]string `mapstructure:"keys"`
	Refresh int64             `mapstructure:"refresh"`
}

// RefreshTime return the duration before refreshing the data of all widgets, in seconds.
func (c config) RefreshTime() int64 {
	if c.General.Refresh == 0 {
		return 60
	}

	return c.General.Refresh
}

type Project struct {
	Name        string                       `mapstructure:"name"`
	NameOptions map[string]string            `mapstructure:"name_options"`
	Services    Services                     `mapstructure:"services"`
	Themes      map[string]map[string]string `mapstructure:"themes"`
	Widgets     []Row                        `mapstructure:"widgets"`
}

// Row is constitued of columns
type Row struct {
	Row []Column `mapstructure:"row"`
}

// Col is constitued of widgets
type Column struct {
	Col []Widgets `mapstructure:"col"`
}

type Widgets struct {
	Size     string            `mapstructure:"size"`
	Elements []internal.Widget `mapstructure:"elements"`
}

type Services struct {
	GoogleAnalytics     GoogleAnalytics `mapstructure:"google_analytics"`
	GoogleSearchConsole SearchConsole   `mapstructure:"google_search_console"`
	Monitor             Monitor         `mapstructure:"monitor"`
	Github              Github          `mapstructure:"github"`
	TravisCI            TravisCI        `mapstructure:"travis"`
	Feedly              Feedly          `mapstructure:"feedly"`
	Git                 Git             `mapstructure:"git"`
	RemoteHost          RemoteHost      `mapstructure:"remote_host"`
}

type GoogleAnalytics struct {
	Keyfile string `mapstructure:"keyfile"`
	ViewID  string `mapstructure:"view_id"`
}

type SearchConsole struct {
	Keyfile string `mapstructure:"keyfile"`
	Address string `mapstructure:"address"`
}

type Monitor struct {
	Address string `mapstructure:"address"`
}

type Github struct {
	Token      string `mapstructure:"token"`
	Owner      string `mapstructure:"owner"`
	Repository string `mapstructure:"repository"`
}

type TravisCI struct {
	Token string `mapstructure:"token"`
}

type Feedly struct {
	Address string `mapstructure:"address"`
}

type RemoteHost struct {
	Username string `mapstructure:"username"`
	Address  string `mapstructure:"address"`
}

type Git struct {
	Path string `mapstructure:"path"`
}

func (g GoogleAnalytics) empty() bool {
	return g == GoogleAnalytics{}
}

func (m Monitor) empty() bool {
	return m == Monitor{}
}
func (s SearchConsole) empty() bool {
	return s == SearchConsole{}
}

func (g Github) empty() bool {
	return g == Github{}
}

func (t TravisCI) empty() bool {
	return t == TravisCI{}
}

func (f Feedly) empty() bool {
	return f == Feedly{}
}

func (g Git) empty() bool {
	return g == Git{}
}

func (g RemoteHost) empty() bool {
	return g == RemoteHost{}
}

// OrderWidgets add the widgets to a three dimensional slice.
// First dimension: index of the rows (ir or indexRows).
// Second dimension: index of the columns (ic or indexColumn).
// Third dimension: index of the widget.
func (p Project) OrderWidgets() ([][][]internal.Widget, [][]string) {
	rows := make([][][]internal.Widget, len(p.Widgets))
	sizes := make([][]string, len(p.Widgets))
	for ir, r := range p.Widgets {
		for ic, c := range r.Row {
			rows[ir] = append(rows[ir], []internal.Widget{}) // add columns to rows
			for _, ws := range c.Col {
				// keep sizes of columns and good order of widgets in a separate slice
				sizes[ir] = append(sizes[ir], ws.Size)

				// add widgets to columns
				rows[ir][ic] = append(rows[ir][ic], ws.Elements...)
			}
		}
	}

	return rows, sizes
}

func mapConfig(cfgFile string) config {
	home, err := homedir.Dir()
	if err != nil {
		fmt.Println(err)
	}

	if cfgFile == "" {
		defaultPath := home + "/.config/devdash/"
		cfgFile = defaultConfig(defaultPath, "default.yml")
	}

	// viper.AddConfigPath(home)
	viper.AddConfigPath(".")
	viper.AddConfigPath("$XDG_CONFIG_HOME/devdash/")
	viper.AddConfigPath(home + "/.config/devdash/")

	viper.SetConfigName(removeExt(cfgFile))
	err = viper.ReadInConfig()
	if err != nil {
		tryReadFile(cfgFile)
	}

	// viper.WatchConfig()
	var cfg config
	if err := viper.Unmarshal(&cfg); err != nil {
		panic(err)
	}

	return cfg
}

func removeExt(filepath string) string {
	ext := []string{".json", ".yml", ".yaml"}
	for _, v := range ext {
		filepath = strings.Replace(filepath, v, "", -1)
	}

	return filepath
}

func defaultConfig(path string, filename string) string {
	if _, err := os.Stat(path); os.IsNotExist(err) {
		os.MkdirAll(path, 0755)
	}

	f := path + filename
	if _, err := os.Stat(f); os.IsNotExist(err) {
		file, _ := os.Create(f)
		defer file.Close()

		// TODO kind of ugly, but not sure if I can use a template here: it will be runtimeee
		if file != nil {
			_, err := file.Write([]byte(
				`---
general:
  refresh: 600
  keys:
    quit: "C-c"

projects:
  - name: Default Configuration - You can modify at at $XDG_CONFIG_HOME/devdash/devdash.yml
    services:
      monitor:
        address: "https://thevaluable.dev"
    widgets:
      - row:
          - col:
              size: "M"
              elements:
                - name: mon.box_availability
                  options:
                    border_color: green`))
			if err != nil {
				panic(err)
			}
		}
	}

	return f
}

func tryReadFile(cfgFile string) {
	if _, err := os.Stat(cfgFile); os.IsNotExist(err) {
		panic(fmt.Errorf("config %s doesnt exists", cfgFile))
	}

	f, err := ioutil.ReadFile(cfgFile)
	if err != nil {
		panic(fmt.Errorf("could not read file %s data", cfgFile))
	}

	viper.SetConfigType(strings.Trim(filepath.Ext(cfgFile), "."))
	err = viper.ReadConfig(bytes.NewBuffer(f))
	if err != nil {
		panic(fmt.Errorf("could not read config %s data", string(f)))
	}
}

// Keyboard events
func (c config) KQuit() string {
	if ok := c.General.Keys["quit"]; ok != "" {
		return c.General.Keys["quit"]
	}

	return kQuit
}

func (c config) KHotReload() string {
	if ok := c.General.Keys["hot_reload"]; ok != "" {
		return c.General.Keys["hot_reload"]
	}

	return kHotReload
}