parent
368dd54d39
commit
2757bc6f16
@ -0,0 +1,56 @@ |
||||
[Unit] |
||||
Description=borgmatic backup |
||||
Wants=network-online.target |
||||
After=network-online.target |
||||
ConditionACPower=true |
||||
|
||||
[Service] |
||||
Type=simple |
||||
|
||||
# Security settings for systemd running as root |
||||
# For more details about this settings check the systemd manuals |
||||
# https://www.freedesktop.org/software/systemd/man/systemd.exec.html |
||||
LockPersonality=true |
||||
# Certain borgmatic features like Healthchecks integration need MemoryDenyWriteExecute to be off. |
||||
# But you can try setting it to "yes" for improved security if you don't use those features. |
||||
MemoryDenyWriteExecute=no |
||||
NoNewPrivileges=yes |
||||
PrivateDevices=yes |
||||
PrivateTmp=yes |
||||
ProtectClock=yes |
||||
ProtectControlGroups=yes |
||||
ProtectHostname=yes |
||||
ProtectKernelLogs=yes |
||||
ProtectKernelModules=yes |
||||
ProtectKernelTunables=yes |
||||
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 AF_NETLINK |
||||
RestrictNamespaces=yes |
||||
RestrictRealtime=yes |
||||
RestrictSUIDSGID=yes |
||||
SystemCallArchitectures=native |
||||
SystemCallFilter=@system-service |
||||
# Restrict write access |
||||
# Change to 'ProtectSystem=strict' and uncomment 'ProtectHome' to make the whole file |
||||
# system read-only be default and uncomment 'ReadWritePaths' for the required write access. |
||||
# Add local repositroy paths to the list of 'ReadWritePaths' like '-/mnt/my_backup_drive'. |
||||
ProtectSystem=strict |
||||
ProtectHome=read-only |
||||
ReadWritePaths=-/root/.config/borg -/root/.cache/borg -/root/.borgmatic /var/backups/postgres -/mnt/backup-1/borg/gubal.borg -/mnt/backup-2/borg/gubal.borg -/mnt/backup-1/borg/goldsaucer.borg -/mnt/backup-2/borg/goldsaucer.borg |
||||
|
||||
CapabilityBoundingSet=CAP_DAC_READ_SEARCH CAP_NET_RAW CAP_SETUID CAP_SETGID CAP_AUDIT_WRITE |
||||
|
||||
# Lower CPU and I/O priority. |
||||
Nice=19 |
||||
CPUSchedulingPolicy=batch |
||||
IOSchedulingClass=best-effort |
||||
IOSchedulingPriority=7 |
||||
IOWeight=100 |
||||
|
||||
Restart=no |
||||
# Prevent rate limiting of borgmatic log events. If you are using an older version of systemd that |
||||
# doesn't support this (pre-240 or so), you may have to remove this option. |
||||
LogRateLimitIntervalSec=0 |
||||
|
||||
# Delay start to prevent backups running during boot. Note that systemd-inhibit requires dbus and |
||||
# dbus-user-session to be installed. |
||||
ExecStart=systemd-inhibit --who="borgmatic" --why="Prevent interrupting scheduled backup" /usr/bin/borgmatic -c /etc/borgmatic/configs-nightly /etc/borgmatic/configs-enabled --syslog-verbosity 1 prune create check --only repository --only archives |
@ -0,0 +1,9 @@ |
||||
[Unit] |
||||
Description=Run borgmatic backup |
||||
|
||||
[Timer] |
||||
OnCalendar=Mon..Sat *-*-2..31 11:00:00 UTC |
||||
Persistent=true |
||||
|
||||
[Install] |
||||
WantedBy=timers.target |
@ -0,0 +1,56 @@ |
||||
[Unit] |
||||
Description=borgmatic backup |
||||
Wants=network-online.target |
||||
After=network-online.target |
||||
ConditionACPower=true |
||||
|
||||
[Service] |
||||
Type=simple |
||||
|
||||
# Security settings for systemd running as root |
||||
# For more details about this settings check the systemd manuals |
||||
# https://www.freedesktop.org/software/systemd/man/systemd.exec.html |
||||
LockPersonality=true |
||||
# Certain borgmatic features like Healthchecks integration need MemoryDenyWriteExecute to be off. |
||||
# But you can try setting it to "yes" for improved security if you don't use those features. |
||||
MemoryDenyWriteExecute=no |
||||
NoNewPrivileges=yes |
||||
PrivateDevices=yes |
||||
PrivateTmp=yes |
||||
ProtectClock=yes |
||||
ProtectControlGroups=yes |
||||
ProtectHostname=yes |
||||
ProtectKernelLogs=yes |
||||
ProtectKernelModules=yes |
||||
ProtectKernelTunables=yes |
||||
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 AF_NETLINK |
||||
RestrictNamespaces=yes |
||||
RestrictRealtime=yes |
||||
RestrictSUIDSGID=yes |
||||
SystemCallArchitectures=native |
||||
SystemCallFilter=@system-service |
||||
# Restrict write access |
||||
# Change to 'ProtectSystem=strict' and uncomment 'ProtectHome' to make the whole file |
||||
# system read-only be default and uncomment 'ReadWritePaths' for the required write access. |
||||
# Add local repositroy paths to the list of 'ReadWritePaths' like '-/mnt/my_backup_drive'. |
||||
ProtectSystem=strict |
||||
ProtectHome=read-only |
||||
ReadWritePaths=-/root/.config/borg -/root/.cache/borg -/root/.borgmatic /var/backups/postgres -/mnt/backup-1/borg/gubal.borg -/mnt/backup-2/borg/gubal.borg -/mnt/backup-1/borg/goldsaucer.borg -/mnt/backup-2/borg/goldsaucer.borg |
||||
|
||||
CapabilityBoundingSet=CAP_DAC_READ_SEARCH CAP_NET_RAW CAP_SETUID CAP_SETGID CAP_AUDIT_WRITE |
||||
|
||||
# Lower CPU and I/O priority. |
||||
Nice=19 |
||||
CPUSchedulingPolicy=batch |
||||
IOSchedulingClass=best-effort |
||||
IOSchedulingPriority=7 |
||||
IOWeight=100 |
||||
|
||||
Restart=no |
||||
# Prevent rate limiting of borgmatic log events. If you are using an older version of systemd that |
||||
# doesn't support this (pre-240 or so), you may have to remove this option. |
||||
LogRateLimitIntervalSec=0 |
||||
|
||||
# Delay start to prevent backups running during boot. Note that systemd-inhibit requires dbus and |
||||
# dbus-user-session to be installed. |
||||
ExecStart=systemd-inhibit --who="borgmatic" --why="Prevent interrupting scheduled backup" /usr/bin/borgmatic -c /etc/borgmatic/configs-enabled --syslog-verbosity 1 create |
@ -0,0 +1,9 @@ |
||||
[Unit] |
||||
Description=Run borgmatic backup |
||||
|
||||
[Timer] |
||||
OnCalendar=*-*-* 0..10,16..23:00:00 UTC |
||||
Persistent=true |
||||
|
||||
[Install] |
||||
WantedBy=timers.target |
@ -0,0 +1,56 @@ |
||||
[Unit] |
||||
Description=borgmatic backup |
||||
Wants=network-online.target |
||||
After=network-online.target |
||||
ConditionACPower=true |
||||
|
||||
[Service] |
||||
Type=simple |
||||
|
||||
# Security settings for systemd running as root |
||||
# For more details about this settings check the systemd manuals |
||||
# https://www.freedesktop.org/software/systemd/man/systemd.exec.html |
||||
LockPersonality=true |
||||
# Certain borgmatic features like Healthchecks integration need MemoryDenyWriteExecute to be off. |
||||
# But you can try setting it to "yes" for improved security if you don't use those features. |
||||
MemoryDenyWriteExecute=no |
||||
NoNewPrivileges=yes |
||||
PrivateDevices=yes |
||||
PrivateTmp=yes |
||||
ProtectClock=yes |
||||
ProtectControlGroups=yes |
||||
ProtectHostname=yes |
||||
ProtectKernelLogs=yes |
||||
ProtectKernelModules=yes |
||||
ProtectKernelTunables=yes |
||||
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 AF_NETLINK |
||||
RestrictNamespaces=yes |
||||
RestrictRealtime=yes |
||||
RestrictSUIDSGID=yes |
||||
SystemCallArchitectures=native |
||||
SystemCallFilter=@system-service |
||||
# Restrict write access |
||||
# Change to 'ProtectSystem=strict' and uncomment 'ProtectHome' to make the whole file |
||||
# system read-only be default and uncomment 'ReadWritePaths' for the required write access. |
||||
# Add local repositroy paths to the list of 'ReadWritePaths' like '-/mnt/my_backup_drive'. |
||||
ProtectSystem=strict |
||||
ProtectHome=read-only |
||||
ReadWritePaths=-/root/.config/borg -/root/.cache/borg -/root/.borgmatic /var/backups/postgres -/mnt/backup-1/borg/gubal.borg -/mnt/backup-2/borg/gubal.borg -/mnt/backup-1/borg/goldsaucer.borg -/mnt/backup-2/borg/goldsaucer.borg |
||||
|
||||
CapabilityBoundingSet=CAP_DAC_READ_SEARCH CAP_NET_RAW CAP_SETUID CAP_SETGID CAP_AUDIT_WRITE |
||||
|
||||
# Lower CPU and I/O priority. |
||||
Nice=19 |
||||
CPUSchedulingPolicy=batch |
||||
IOSchedulingClass=best-effort |
||||
IOSchedulingPriority=7 |
||||
IOWeight=100 |
||||
|
||||
Restart=no |
||||
# Prevent rate limiting of borgmatic log events. If you are using an older version of systemd that |
||||
# doesn't support this (pre-240 or so), you may have to remove this option. |
||||
LogRateLimitIntervalSec=0 |
||||
|
||||
# Delay start to prevent backups running during boot. Note that systemd-inhibit requires dbus and |
||||
# dbus-user-session to be installed. |
||||
ExecStart=systemd-inhibit --who="borgmatic" --why="Prevent interrupting scheduled backup" /usr/bin/borgmatic -c /etc/borgmatic/configs-nightly /etc/borgmatic/configs-enabled --syslog-verbosity 1 prune create check --only repository --only archives --only extract --only data |
@ -0,0 +1,9 @@ |
||||
[Unit] |
||||
Description=Run borgmatic backup |
||||
|
||||
[Timer] |
||||
OnCalendar=*-*-1 11:00:00 UTC |
||||
Persistent=true |
||||
|
||||
[Install] |
||||
WantedBy=timers.target |
@ -0,0 +1,56 @@ |
||||
[Unit] |
||||
Description=borgmatic backup |
||||
Wants=network-online.target |
||||
After=network-online.target |
||||
ConditionACPower=true |
||||
|
||||
[Service] |
||||
Type=simple |
||||
|
||||
# Security settings for systemd running as root |
||||
# For more details about this settings check the systemd manuals |
||||
# https://www.freedesktop.org/software/systemd/man/systemd.exec.html |
||||
LockPersonality=true |
||||
# Certain borgmatic features like Healthchecks integration need MemoryDenyWriteExecute to be off. |
||||
# But you can try setting it to "yes" for improved security if you don't use those features. |
||||
MemoryDenyWriteExecute=no |
||||
NoNewPrivileges=yes |
||||
PrivateDevices=yes |
||||
PrivateTmp=yes |
||||
ProtectClock=yes |
||||
ProtectControlGroups=yes |
||||
ProtectHostname=yes |
||||
ProtectKernelLogs=yes |
||||
ProtectKernelModules=yes |
||||
ProtectKernelTunables=yes |
||||
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 AF_NETLINK |
||||
RestrictNamespaces=yes |
||||
RestrictRealtime=yes |
||||
RestrictSUIDSGID=yes |
||||
SystemCallArchitectures=native |
||||
SystemCallFilter=@system-service |
||||
# Restrict write access |
||||
# Change to 'ProtectSystem=strict' and uncomment 'ProtectHome' to make the whole file |
||||
# system read-only be default and uncomment 'ReadWritePaths' for the required write access. |
||||
# Add local repositroy paths to the list of 'ReadWritePaths' like '-/mnt/my_backup_drive'. |
||||
ProtectSystem=strict |
||||
ProtectHome=read-only |
||||
ReadWritePaths=-/root/.config/borg -/root/.cache/borg -/root/.borgmatic /var/backups/postgres -/mnt/backup-1/borg/gubal.borg -/mnt/backup-2/borg/gubal.borg -/mnt/backup-1/borg/goldsaucer.borg -/mnt/backup-2/borg/goldsaucer.borg |
||||
|
||||
CapabilityBoundingSet=CAP_DAC_READ_SEARCH CAP_NET_RAW CAP_SETUID CAP_SETGID CAP_AUDIT_WRITE |
||||
|
||||
# Lower CPU and I/O priority. |
||||
Nice=19 |
||||
CPUSchedulingPolicy=batch |
||||
IOSchedulingClass=best-effort |
||||
IOSchedulingPriority=7 |
||||
IOWeight=100 |
||||
|
||||
Restart=no |
||||
# Prevent rate limiting of borgmatic log events. If you are using an older version of systemd that |
||||
# doesn't support this (pre-240 or so), you may have to remove this option. |
||||
LogRateLimitIntervalSec=0 |
||||
|
||||
# Delay start to prevent backups running during boot. Note that systemd-inhibit requires dbus and |
||||
# dbus-user-session to be installed. |
||||
ExecStart=systemd-inhibit --who="borgmatic" --why="Prevent interrupting scheduled backup" /usr/bin/borgmatic -c /etc/borgmatic/configs-nightly /etc/borgmatic/configs-enabled --syslog-verbosity 1 prune create check --only repository --only archives --only extract |
@ -0,0 +1,9 @@ |
||||
[Unit] |
||||
Description=Run borgmatic backup |
||||
|
||||
[Timer] |
||||
OnCalendar=Sun *-*-2..31 11:00:00 UTC |
||||
Persistent=true |
||||
|
||||
[Install] |
||||
WantedBy=timers.target |
@ -1 +0,0 @@ |
||||
barista-bar |
@ -0,0 +1,2 @@ |
||||
barista-bar |
||||
nerdfont-provider-data.go |
@ -0,0 +1,8 @@ |
||||
# Default ignored files |
||||
/shelf/ |
||||
/workspace.xml |
||||
# Datasource local storage ignored files |
||||
/dataSources/ |
||||
/dataSources.local.xml |
||||
# Editor-based HTTP Client requests |
||||
/httpRequests/ |
@ -0,0 +1,17 @@ |
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<module type="WEB_MODULE" version="4"> |
||||
<component name="Go" enabled="true"> |
||||
<buildTags> |
||||
<option name="customFlags"> |
||||
<array> |
||||
<option value="generation" /> |
||||
</array> |
||||
</option> |
||||
</buildTags> |
||||
</component> |
||||
<component name="NewModuleRootManager"> |
||||
<content url="file://$MODULE_DIR$" /> |
||||
<orderEntry type="inheritedJdk" /> |
||||
<orderEntry type="sourceFolder" forTests="false" /> |
||||
</component> |
||||
</module> |
@ -0,0 +1,8 @@ |
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<project version="4"> |
||||
<component name="ProjectModuleManager"> |
||||
<modules> |
||||
<module fileurl="file://$PROJECT_DIR$/.idea/barista.iml" filepath="$PROJECT_DIR$/.idea/barista.iml" /> |
||||
</modules> |
||||
</component> |
||||
</project> |
@ -0,0 +1,10 @@ |
||||
package main |
||||
|
||||
import ( |
||||
"barista.run/testing/httpcache" |
||||
"net/http" |
||||
) |
||||
|
||||
func init() { |
||||
http.DefaultTransport = httpcache.Wrap(http.DefaultTransport) |
||||
} |
@ -0,0 +1,23 @@ |
||||
package main |
||||
|
||||
import ( |
||||
"barista.run/colors" |
||||
"github.com/lucasb-eyer/go-colorful" |
||||
) |
||||
|
||||
func configureColors() { |
||||
colors.LoadBarConfig() |
||||
bg := colors.Scheme("background") |
||||
fg := colors.Scheme("statusline") |
||||
if fg != nil && bg != nil { |
||||
iconColor := fg.Colorful().BlendHcl(bg.Colorful(), 0.5).Clamped() |
||||
colors.Set("dim-icon", iconColor) |
||||
_, _, v := fg.Colorful().Hsv() |
||||
if v < 0.3 { |
||||
v = 0.3 |
||||
} |
||||
colors.Set("bad", colorful.Hcl(40, 1.0, v).Clamped()) |
||||
colors.Set("degraded", colorful.Hcl(90, 1.0, v).Clamped()) |
||||
colors.Set("good", colorful.Hcl(120, 1.0, v).Clamped()) |
||||
} |
||||
} |
@ -0,0 +1,31 @@ |
||||
package main |
||||
|
||||
import ( |
||||
"barista.run/pango" |
||||
"fmt" |
||||
"time" |
||||
) |
||||
|
||||
var spacer = pango.Text(" ").XXSmall() |
||||
|
||||
func truncate(in string, l int) string { |
||||
if len([]rune(in)) <= l { |
||||
return in |
||||
} |
||||
return string([]rune(in)[:l-1]) + "⋯" |
||||
} |
||||
|
||||
func hms(d time.Duration) (h int, m int, s int) { |
||||
h = int(d.Hours()) |
||||
m = int(d.Minutes()) % 60 |
||||
s = int(d.Seconds()) % 60 |
||||
return |
||||
} |
||||
|
||||
func formatMediaTime(d time.Duration) string { |
||||
h, m, s := hms(d) |
||||
if h > 0 { |
||||
return fmt.Sprintf("%d:%02d:%02d", h, m, s) |
||||
} |
||||
return fmt.Sprintf("%d:%02d", m, s) |
||||
} |
@ -0,0 +1,55 @@ |
||||
package main |
||||
|
||||
import ( |
||||
"barista.run/bar" |
||||
"barista.run/colors" |
||||
"barista.run/modules/media" |
||||
"barista.run/modules/volume" |
||||
"barista.run/modules/volume/alsa" |
||||
"barista.run/outputs" |
||||
"barista.run/pango" |
||||
) |
||||
|
||||
func mediaFormatFunc(m media.Info) bar.Output { |
||||
if m.PlaybackStatus == media.Stopped || m.PlaybackStatus == media.Disconnected { |
||||
return nil |
||||
} |
||||
artist := truncate(m.Artist, 20) |
||||
title := truncate(m.Title, 40-len(artist)) |
||||
if len(title) < 20 { |
||||
artist = truncate(m.Artist, 40-len(title)) |
||||
} |
||||
iconAndPosition := pango.Icon("nf-fa-music").Color(colors.Hex("#f70")) |
||||
if m.PlaybackStatus == media.Playing { |
||||
iconAndPosition.Append( |
||||
spacer, pango.Textf("%s/%s", |
||||
formatMediaTime(m.Position()), |
||||
formatMediaTime(m.Length)), |
||||
) |
||||
} |
||||
return outputs.Pango(iconAndPosition, spacer, title, " - ", artist) |
||||
} |
||||
|
||||
func volumeSegment() bar.Module { |
||||
return volume.New(alsa.DefaultMixer()).Output(func(v volume.Volume) bar.Output { |
||||
pct := v.Pct() |
||||
var indicatorText *pango.Node |
||||
var pctText *pango.Node |
||||
if pct > 99 { |
||||
pctText = pango.Text("MAX") |
||||
} else { |
||||
pctText = pango.Textf("%2d%%", pct) |
||||
} |
||||
if v.Mute { |
||||
indicatorText = pango.Text("MUT").Color(colors.Scheme("degraded")) |
||||
pctText = pctText.Color(colors.Scheme("degraded")).XSmall() |
||||
} else { |
||||
indicatorText = pango.Text("Vol").XSmall() |
||||
} |
||||
return outputs.Pango( |
||||
indicatorText, |
||||
spacer, |
||||
pctText, |
||||
) |
||||
}) |
||||
} |
@ -0,0 +1,157 @@ |
||||
// This file is run by go generate, and generates nerdfont-provider-data.go.
|
||||
// +build generation
|
||||
|
||||
package main |
||||
|
||||
import ( |
||||
"bufio" |
||||
"bytes" |
||||
"io" |
||||
"log" |
||||
"net/http" |
||||
"os" |
||||
"strconv" |
||||
"strings" |
||||
"text/template" |
||||
"time" |
||||
"unicode" |
||||
) |
||||
|
||||
var fileTemplate = template.Must(template.New("").Parse(`// Code generated by go generate; DO NOT EDIT.
|
||||
// This file was generated by robots at
|
||||
// {{ .Timestamp }}
|
||||
// using data from
|
||||
// {{ .URL }}
|
||||
package main |
||||
|
||||
var NerdFontGlyphs = []Glyph{ |
||||
{{- range $key, $rune := .Glyphs }} |
||||
{ |
||||
Key: {{ printf "%q" $key }}, |
||||
Rune: 0x{{ printf "%x" $rune }}, |
||||
}, |
||||
{{- end }} |
||||
} |
||||
`)) |
||||
|
||||
const TokenStartString = ".nf-" |
||||
const ClassStartString = ":before {\n content: \"\\" |
||||
const ClassEndString = "\";\n}\n" |
||||
// SplitCSS scans the reader looking for data of the form
|
||||
// .nf-(key):before {
|
||||
// content: "\(hex)";
|
||||
// }
|
||||
// and returns (key):(hex) when it finds this data.
|
||||
func SplitCSS(data []byte, atEOF bool) (advance int, token []byte, err error) { |
||||
if !bytes.HasPrefix(data, []byte(TokenStartString)) { |
||||
// This is not our goal. Skip this line.
|
||||
nextNewline := bytes.IndexRune(data, '\n'); |
||||
if nextNewline == -1 { |
||||
// Can't skip this line yet because we don't know where it ends!
|
||||
return 0, nil, nil |
||||
} else { |
||||
offset := nextNewline + 1 |
||||
// Skip this line in our own head and see if we get a result.
|
||||
advance, token, err = SplitCSS(data[offset:], atEOF) |
||||
if advance > 0 || token != nil || err != nil { |
||||
// If we do, return it adjusted by the offset.
|
||||
return advance + offset, token, err |
||||
} else { |
||||
// Otherwise, just tell the scanner to skip the line we found and keep going.
|
||||
return offset, nil, nil |
||||
} |
||||
} |
||||
} |
||||
keyEnd := bytes.Index(data, []byte(ClassStartString)) |
||||
if keyEnd == -1 { |
||||
// We don't know where the key ends!
|
||||
return 0, nil, nil |
||||
} |
||||
key := data[len(TokenStartString):keyEnd] |
||||
contentEnd := bytes.Index(data, []byte(ClassEndString)) |
||||
if contentEnd == -1 { |
||||
// We don't know where the content ends!
|
||||
return 0, nil, nil |
||||
} |
||||
content := data[keyEnd + len(ClassStartString):contentEnd] |
||||
token = make([]byte, len(key) + len(content) + 1) |
||||
copy(token[:len(key)], key) |
||||
token[len(key)] = ':' |
||||
copy(token[len(key) + 1:], content) |
||||
return contentEnd + len(ClassEndString), token, nil |
||||
} |
||||
|
||||
func SplitOnce(s string, sep string) (string, string) { |
||||
result := strings.SplitN(s, sep, 2) |
||||
if len(result) == 2 { |
||||
return result[0], result[1] |
||||
} else if len(result) == 1 { |
||||
return result[0], "" |
||||
} else { |
||||
panic("How did we get a different number of strings than 1 or 2 out of SplitN(2)?") |
||||
} |
||||
} |
||||
|
||||
func main() { |
||||
const url = "https://raw.githubusercontent.com/ryanoasis/nerd-fonts/master/css/nerd-fonts-generated.css" |
||||
|
||||
rsp, err := http.Get(url) |
||||
if err != nil { |
||||
log.Fatalf("failed to get css file: %s", err) |
||||
} |
||||
defer func(b io.ReadCloser) { |
||||
err := b.Close() |
||||
if err != nil { |
||||
log.Printf("failed closing the css file: %s", err) |
||||
} |
||||
}(rsp.Body) |
||||
|
||||
sc := bufio.NewScanner(rsp.Body) |
||||
sc.Split(SplitCSS) |
||||
|
||||
glyphs := make(map[string]rune) |
||||
|
||||
for sc.Scan() { |
||||
key, hex := SplitOnce(sc.Text(), ":") |
||||
val, err := strconv.ParseInt(hex, 16, 64) |
||||
if err != nil { |
||||
log.Printf("val %s for %s cannot be parsed as hex: %s", hex, key, err) |
||||
continue |
||||
} |
||||
if val > int64(unicode.MaxRune) { |
||||
log.Printf("val 0x%x for %s exceeds MaxRune", val, key) |
||||
continue |
||||
} |
||||
if old, ok := glyphs[key]; ok { |
||||
log.Printf("already stored %s as 0x%x but got 0x%x, replacing", key, old, val) |
||||
} |
||||
glyphs[key] = rune(val) |
||||
} |
||||
if sc.Err() != nil { |
||||
log.Fatalf("failed to scan: %s", sc.Err()) |
||||
} |
||||
|
||||
f, err := os.Create("nerdfont-provider-data.go") |
||||
if err != nil { |
||||
log.Fatalf("failed to open the data file: %s", err) |
||||
} |
||||
defer func(f *os.File) { |
||||
err := f.Close() |
||||
if err != nil { |
||||
log.Printf("failed closing the data file: %s", err) |
||||
} |
||||
}(f) |
||||
|
||||
err = fileTemplate.Execute(f, struct { |
||||
Timestamp time.Time |
||||
URL string |
||||
Glyphs map[string]rune |
||||
}{ |
||||
Timestamp: time.Now(), |
||||
URL: url, |
||||
Glyphs: glyphs, |
||||
}) |
||||
if err != nil { |
||||
log.Fatalf("failed writing template to the data file: %s", err) |
||||
} |
||||
} |
@ -0,0 +1,21 @@ |
||||
package main |
||||
|
||||
//go:generate go run nerdfont-process-css.go
|
||||
|
||||
import ( |
||||
"barista.run/pango/icons" |
||||
) |
||||
|
||||
type Glyph struct { |
||||
Key string |
||||
Rune rune |
||||
} |
||||
|
||||
func installNerdFontProvider(face string) *icons.Provider { |
||||
nf := icons.NewProvider("nf") |
||||
nf.Font(face) |
||||
for _, glyph := range NerdFontGlyphs { |
||||
nf.Symbol(glyph.Key, string(glyph.Rune)) |
||||
} |
||||
return nf |
||||
} |
@ -0,0 +1,46 @@ |
||||
package main |
||||
|
||||
import ( |
||||
"barista.run/oauth" |
||||
"crypto/rand" |
||||
"encoding/base64" |
||||
"fmt" |
||||
"github.com/zalando/go-keyring" |
||||
"os" |
||||
"os/user" |
||||
) |
||||
|
||||
func setupOauthEncryption() error { |
||||
const service = "reya.zone-barista-bar" |
||||
var username string |
||||
if u, err := user.Current(); err == nil { |
||||
username = u.Username |
||||
} else { |
||||
username = fmt.Sprintf("user-%d", os.Getuid()) |
||||
} |
||||
var secretBytes []byte |
||||
// IMPORTANT: The oauth tokens used by some modules are very sensitive, so
|
||||
// we encrypt them with a random key and store that random key using
|
||||
// libsecret (gnome-keyring or equivalent). If no secret provider is
|
||||
// available, there is no way to store tokens (since the version of
|
||||
// sample-bar used for setup-oauth will have a different key from the one
|
||||
// running in i3bar). See also https://github.com/zalando/go-keyring#linux.
|
||||
secret, err := keyring.Get(service, username) |
||||
if err == nil { |
||||
secretBytes, err = base64.RawURLEncoding.DecodeString(secret) |
||||
} |
||||
if err != nil { |
||||
secretBytes = make([]byte, 64) |
||||
_, err := rand.Read(secretBytes) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
secret = base64.RawURLEncoding.EncodeToString(secretBytes) |
||||
err = keyring.Set(service, username, secret) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
} |
||||
oauth.SetEncryptionKey(secretBytes) |
||||
return nil |
||||
} |
@ -0,0 +1,91 @@ |
||||
package main |
||||
|
||||
import ( |
||||
"barista.run/bar" |
||||
"barista.run/base/click" |
||||
"barista.run/colors" |
||||
"barista.run/modules/battery" |
||||
"barista.run/outputs" |
||||
"barista.run/pango" |
||||
) |
||||
|
||||
func buildBattOutput(i battery.Info, render func (i battery.Info) *pango.Node) *bar.Segment { |
||||
var indicator, display *pango.Node |
||||
display = render(i) |
||||
switch i.Status { |
||||
case battery.Disconnected: |
||||
indicator = pango.Text("---") |
||||
case battery.Full: |
||||
indicator = pango.Text("AC ") |
||||
case battery.Charging: |
||||
indicator = pango.Text("AC+") |
||||
case battery.Discharging: |
||||
indicator = pango.Text("Bat") |
||||
case battery.NotCharging: |
||||
indicator = pango.Text("AC?") |
||||
default: |
||||
indicator = pango.Text("???") |
||||
} |
||||
out := outputs.Pango(indicator.XSmall(), spacer, display) |
||||
switch { |
||||
case i.RemainingPct() <= 5: |
||||
out.Urgent(true) |
||||
case i.RemainingPct() <= 15: |
||||
out.Color(colors.Scheme("bad")) |
||||
case i.RemainingPct() <= 25: |
||||
out.Color(colors.Scheme("degraded")) |
||||
} |
||||
return out |
||||
} |
||||
|
||||
func batterySegment() bar.Module { |
||||
var showBattPct, showBattTime func(battery.Info) bar.Output |
||||
batt := battery.All() |
||||
showBattPct = func(i battery.Info) bar.Output { |
||||
out := buildBattOutput(i, func(i battery.Info) *pango.Node { |
||||
switch i.Status { |
||||
case battery.Full, battery.Charging, battery.Discharging, battery.NotCharging: |
||||
if i.RemainingPct() < 0 { |
||||
return pango.Text(" 0%") |
||||
} else if i.RemainingPct() > 99 { |
||||
return pango.Text("MAX") |
||||
} else { |
||||
return pango.Textf("%d%%", i.RemainingPct()) |
||||
} |
||||
case battery.Disconnected: |
||||
return pango.Text("---") |
||||
default: |
||||
return pango.Text("???") |
||||
} |
||||
}) |
||||
if out == nil { |
||||
return nil |
||||
} |
||||
return out.OnClick(click.Left(func() { |
||||
batt.Output(showBattTime) |
||||
})) |
||||
} |
||||
showBattTime = func(i battery.Info) bar.Output { |
||||
rem := i.RemainingTime() |
||||
out := buildBattOutput(i, func(i battery.Info) *pango.Node { |
||||
switch i.Status { |
||||
case battery.Full, battery.Charging, battery.Discharging, battery.NotCharging: |
||||
return pango.Textf("%d:%02d", int(rem.Hours()), int(rem.Minutes())%60) |
||||
case battery.Disconnected: |
||||
return pango.Text("-:--") |
||||
default: |
||||
return pango.Text("?:??") |
||||
} |
||||
}) |
||||
|
||||
if out == nil { |
||||
return nil |
||||
} |
||||
return out.OnClick(click.Left(func() { |
||||
batt.Output(showBattPct) |
||||
})) |
||||
} |
||||
batt.Output(showBattPct) |
||||
return batt |
||||
} |
||||
|
@ -0,0 +1,81 @@ |
||||
package main |
||||
|
||||
import ( |
||||
"barista.run/bar" |
||||
"barista.run/colors" |
||||
"barista.run/modules/cputemp" |
||||
"barista.run/modules/meminfo" |
||||
"barista.run/modules/sysinfo" |
||||
"barista.run/outputs" |
||||
"barista.run/pango" |
||||
"github.com/dustin/go-humanize" |
||||
"github.com/martinlindhe/unit" |
||||
"strings" |
||||
"time" |
||||
) |
||||
|
||||
func memorySegment() bar.Module { |
||||
return meminfo.New().Output(func(m meminfo.Info) bar.Output { |
||||
h := strings.SplitN(humanize.IBytes(uint64(m.Available().Bytes())), " ", 2) |
||||
freeText := pango.Text(h[0]) |
||||
if len(h) == 2 { |
||||
freeText = freeText.Append(spacer, pango.Text(h[1]).Small()) |
||||
} |
||||
out := outputs.Pango(pango.Text("Mem").XSmall(), spacer, freeText) |
||||
freeGigs := m.Available().Gigabytes() |
||||
switch { |
||||
case freeGigs < 0.5: |
||||
out.Urgent(true) |
||||
case freeGigs < 1: |
||||
out.Color(colors.Scheme("bad")) |
||||
case freeGigs < 2: |
||||
out.Color(colors.Scheme("degraded")) |
||||
case freeGigs > 12: |
||||
out.Color(colors.Scheme("good")) |
||||
} |
||||
out.OnClick(startTaskManager) |
||||
return out |
||||
}) |
||||
} |
||||
|
||||
func loadAverageSegment() bar.Module { |
||||
return sysinfo.New().Output(func(s sysinfo.Info) bar.Output { |
||||
out := outputs.Pango(pango.Text("Load 1m").XSmall(), spacer, pango.Textf("%0.2f", s.Loads[0]), spacer, pango.Text("15m").XSmall(), spacer, pango.Textf("%0.2f", s.Loads[2])) |
||||
// Load averages are unusually high for a few minutes after boot.
|
||||
if s.Uptime < 10*time.Minute { |
||||
// so don't add colours until 10 minutes after system start.
|
||||
return out |
||||
} |
||||
switch { |
||||
case s.Loads[0] > 128, s.Loads[2] > 64: |
||||
out.Urgent(true) |
||||
case s.Loads[0] > 64, s.Loads[2] > 32: |
||||
out.Color(colors.Scheme("bad")) |
||||
case s.Loads[0] > 32, s.Loads[2] > 16: |
||||
out.Color(colors.Scheme("degraded")) |
||||
} |
||||
out.OnClick(startTaskManager) |
||||
return out |
||||
}) |
||||
} |
||||
|
||||
func cputempSegment() bar.Module { |
||||
return cputemp.New(). |
||||
RefreshInterval(2 * time.Second). |
||||
Output(func(temp unit.Temperature) bar.Output { |
||||
out := outputs.Pango( |
||||
pango.Text("CPU").XSmall(), spacer, |
||||
pango.Textf("%2d", int(temp.Celsius())), |
||||
pango.Text("℃").XSmall(), |
||||
) |
||||
switch { |
||||
case temp.Celsius() > 90: |
||||
out.Urgent(true) |
||||
case temp.Celsius() > 70: |
||||
out.Color(colors.Scheme("bad")) |
||||
case temp.Celsius() > 60: |
||||
out.Color(colors.Scheme("degraded")) |
||||
} |
||||
return out |
||||
}) |
||||
} |
@ -0,0 +1,34 @@ |
||||
package main |
||||
|
||||
import ( |
||||
"encoding/json" |
||||
"net/http" |
||||
"os/user" |
||||
"path/filepath" |
||||
) |
||||
|
||||
func home(path string) string { |
||||
usr, err := user.Current() |
||||
if err != nil { |
||||
panic(err) |
||||
} |
||||
return filepath.Join(usr.HomeDir, path) |
||||
} |
||||
|
||||
type freegeoipResponse struct { |
||||
Lat float64 `json:"latitude"` |
||||
Lng float64 `json:"longitude"` |
||||
} |
||||
|
||||
func whereami() (lat float64, lng float64, err error) { |
||||
resp, err := http.Get("https://freegeoip.app/json/") |
||||
if err != nil { |
||||
return 0, 0, err |
||||
} |
||||
var res freegeoipResponse |
||||
err = json.NewDecoder(resp.Body).Decode(&res) |
||||
if err != nil { |
||||
return 0, 0, err |
||||
} |
||||
return res.Lat, res.Lng, nil |
||||
} |
@ -1 +1 @@ |
||||
Subproject commit 079e7bb5e0a79171f3356d55d3f6302a82645a39 |
||||
Subproject commit 5377cc37c0f71fe22484303a4c6f387aa339f3f5 |
Loading…
Reference in new issue