sysdo 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +37 -0
- data/README.md +35 -0
- data/exe/sysdo +22 -0
- data/lib/sysdo.rb +10 -0
- data/lib/sysdo/cli.rb +17 -0
- data/lib/sysdo/dsl.rb +14 -0
- data/lib/sysdo/event_source.rb +19 -0
- data/lib/sysdo/event_source/polled_change.rb +21 -0
- data/lib/sysdo/event_source/polled_collection_change.rb +32 -0
- data/lib/sysdo/event_source/polled_equal_change.rb +21 -0
- data/lib/sysdo/source_library/battery.rb +29 -0
- data/lib/sysdo/source_library/network.rb +27 -0
- data/lib/sysdo/source_library/usb.rb +24 -0
- data/lib/sysdo/version.rb +3 -0
- data/sysdo.gemspec +29 -0
- metadata +116 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 526340346fe535a7a51c3b275c3453d65fa5eb99339bce3ad66112a30621622b
|
4
|
+
data.tar.gz: 7e6a04616a5cbb990b8ab38557dea1ffabd6cc6db7905f110ddd7d30fbf9af27
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 826769e8392dcc22e31eb8d22f7a007a624c60142ed2b1e491f332f91b5ad926c58036cd7f90879ecbb20e17cca151b19adf92004426ac6890f37195093dbefa
|
7
|
+
data.tar.gz: 33159a9e470d42b229f92e3f5e886ebad3bb45a012297015849ab15e3c716d9cd3781d9ff018172d34794ce5d0e9ee7485bf1717f098e31db7752d52df85af14
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
sysdo (0.0.1)
|
5
|
+
daemons (~> 1.3)
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: https://rubygems.org/
|
9
|
+
specs:
|
10
|
+
daemons (1.3.1)
|
11
|
+
diff-lcs (1.4.4)
|
12
|
+
rake (13.0.3)
|
13
|
+
rspec (3.10.0)
|
14
|
+
rspec-core (~> 3.10.0)
|
15
|
+
rspec-expectations (~> 3.10.0)
|
16
|
+
rspec-mocks (~> 3.10.0)
|
17
|
+
rspec-core (3.10.0)
|
18
|
+
rspec-support (~> 3.10.0)
|
19
|
+
rspec-expectations (3.10.0)
|
20
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
21
|
+
rspec-support (~> 3.10.0)
|
22
|
+
rspec-mocks (3.10.0)
|
23
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
24
|
+
rspec-support (~> 3.10.0)
|
25
|
+
rspec-support (3.10.0)
|
26
|
+
|
27
|
+
PLATFORMS
|
28
|
+
ruby
|
29
|
+
|
30
|
+
DEPENDENCIES
|
31
|
+
bundler (~> 2.0)
|
32
|
+
rake (>= 12.3.3)
|
33
|
+
rspec (~> 3.0)
|
34
|
+
sysdo!
|
35
|
+
|
36
|
+
BUNDLED WITH
|
37
|
+
2.1.4
|
data/README.md
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# Sysdo
|
2
|
+
|
3
|
+
Sysdo is a tiny automation framework for gluing bits of your Linux system
|
4
|
+
together. Sysdo provides events, and you write Ruby to do things automatically
|
5
|
+
when the events fire.
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
# If we're on the go, automatically switch to power-saving CPU frequency
|
9
|
+
on Battery.charger_disconnected do
|
10
|
+
`cpupower frequency-set -g powersave`
|
11
|
+
end
|
12
|
+
|
13
|
+
# Don't let Steam eat all of your data allowance when tethering
|
14
|
+
on Network.changed do |network|
|
15
|
+
if network.ssid == "Aaron's Phone"
|
16
|
+
`pkill -9 steam`
|
17
|
+
end
|
18
|
+
end
|
19
|
+
```
|
20
|
+
|
21
|
+
If you've used Tasker on Android, or Shortcuts on iOS, or Automator on macOS,
|
22
|
+
this is somewhat similar in the things you can achieve (albeit a bit more
|
23
|
+
hands-on).
|
24
|
+
|
25
|
+
This isn't really ready for proper usage yet, but with a bit more polish and a
|
26
|
+
larger library of events, it's not far off!
|
27
|
+
|
28
|
+
## Usage
|
29
|
+
|
30
|
+
1. Install with `gem install sysdo`.
|
31
|
+
2. Create a `sysdo` directory under your user config directory (defaults to
|
32
|
+
`XDG_CONFIG_HOME`, or `~/.config` if that's unset).
|
33
|
+
3. Put some Ruby scripts in there. You can create as many as you like and
|
34
|
+
they'll all be loaded; the names don't matter as long as they end in `.rb`.
|
35
|
+
4. Run `sysdo start` to launch the Sysdo daemon.
|
data/exe/sysdo
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'sysdo'
|
3
|
+
require 'fileutils'
|
4
|
+
require 'thwait'
|
5
|
+
require 'daemons'
|
6
|
+
|
7
|
+
include Sysdo::SourceLibrary
|
8
|
+
|
9
|
+
dsl = Sysdo::Dsl.new
|
10
|
+
Sysdo::Cli.user_scripts.each do |file|
|
11
|
+
dsl.instance_eval(File.read(file))
|
12
|
+
end
|
13
|
+
|
14
|
+
Daemons.run_proc('sysdo') do
|
15
|
+
threads = dsl.event_sources.map do |src|
|
16
|
+
t = Thread.new { src.listen }
|
17
|
+
t.abort_on_exception = true
|
18
|
+
t
|
19
|
+
end
|
20
|
+
|
21
|
+
ThreadsWait.all_waits(*threads)
|
22
|
+
end
|
data/lib/sysdo.rb
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
require 'sysdo/source_library/usb'
|
2
|
+
require 'sysdo/source_library/network'
|
3
|
+
require 'sysdo/source_library/battery'
|
4
|
+
require 'sysdo/event_source'
|
5
|
+
require 'sysdo/event_source/polled_collection_change'
|
6
|
+
require 'sysdo/event_source/polled_equal_change'
|
7
|
+
require 'sysdo/event_source/polled_change'
|
8
|
+
require 'sysdo/dsl'
|
9
|
+
require 'sysdo/cli'
|
10
|
+
require 'sysdo/version'
|
data/lib/sysdo/cli.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
module Sysdo
|
2
|
+
module Cli
|
3
|
+
CONFIG_DIRECTORY = File.join(
|
4
|
+
ENV['XDG_CONFIG_HOME'] || File.expand_path('~/.config'),
|
5
|
+
'sysdo',
|
6
|
+
)
|
7
|
+
|
8
|
+
def self.user_scripts
|
9
|
+
create_config_directory
|
10
|
+
Dir[File.join(CONFIG_DIRECTORY, '*.rb')]
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.create_config_directory
|
14
|
+
FileUtils.mkdir_p(CONFIG_DIRECTORY)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/sysdo/dsl.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
module Sysdo
|
2
|
+
class EventSource
|
3
|
+
attr_accessor :on_fire
|
4
|
+
|
5
|
+
def initialize(&listener)
|
6
|
+
@listener = listener
|
7
|
+
@on_fire = ->{}
|
8
|
+
end
|
9
|
+
|
10
|
+
def fire(*args, **kwargs)
|
11
|
+
@on_fire.(*args, **kwargs)
|
12
|
+
end
|
13
|
+
|
14
|
+
def listen
|
15
|
+
@listener.(self)
|
16
|
+
# TODO: what if this dies?
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Sysdo
|
2
|
+
class EventSource
|
3
|
+
class PolledChange < EventSource
|
4
|
+
def initialize(poll_rate = 1, &value)
|
5
|
+
super() do |s|
|
6
|
+
last = value.()
|
7
|
+
|
8
|
+
loop do
|
9
|
+
now = value.()
|
10
|
+
if last != now
|
11
|
+
s.fire(now)
|
12
|
+
end
|
13
|
+
last = now
|
14
|
+
|
15
|
+
sleep poll_rate
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Sysdo
|
2
|
+
class EventSource
|
3
|
+
class PolledCollectionChange < EventSource
|
4
|
+
def initialize(change, poll_rate = 1, &collection)
|
5
|
+
raise "change parameter must be :add or :remove" \
|
6
|
+
unless change == :add || change == :remove
|
7
|
+
|
8
|
+
super() do |s|
|
9
|
+
last = collection.()
|
10
|
+
|
11
|
+
loop do
|
12
|
+
now = collection.()
|
13
|
+
if last != now
|
14
|
+
if change == :add
|
15
|
+
relevant_items = now - last
|
16
|
+
elsif change == :remove
|
17
|
+
relevant_items = last - now
|
18
|
+
end
|
19
|
+
|
20
|
+
relevant_items.each do |new_item|
|
21
|
+
s.fire(new_item)
|
22
|
+
end unless relevant_items.empty?
|
23
|
+
end
|
24
|
+
last = now
|
25
|
+
|
26
|
+
sleep poll_rate
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Sysdo
|
2
|
+
class EventSource
|
3
|
+
class PolledEqualChange < EventSource
|
4
|
+
def initialize(equal, poll_rate = 1, &value)
|
5
|
+
super() do |s|
|
6
|
+
last = value.()
|
7
|
+
|
8
|
+
loop do
|
9
|
+
now = value.()
|
10
|
+
if last != now && now == equal
|
11
|
+
s.fire(now)
|
12
|
+
end
|
13
|
+
last = now
|
14
|
+
|
15
|
+
sleep poll_rate
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Sysdo
|
2
|
+
module SourceLibrary
|
3
|
+
module Battery
|
4
|
+
def self.charger_connected
|
5
|
+
EventSource::PolledEqualChange.new(true) { charger_connected? }
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.charger_disconnected
|
9
|
+
EventSource::PolledEqualChange.new(false) { charger_connected? }
|
10
|
+
end
|
11
|
+
|
12
|
+
protected
|
13
|
+
|
14
|
+
BATTERY = '/org/freedesktop/UPower/devices/battery_BAT0'
|
15
|
+
|
16
|
+
def self.charger_connected?
|
17
|
+
# Can be "fully-charged" or "charging", so this is easier
|
18
|
+
battery_info['state'] != 'discharging'
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.battery_info
|
22
|
+
# World's most naive upower parser
|
23
|
+
`upower -i "#{BATTERY}"`.each_line.map do |line|
|
24
|
+
[$~['key'], $~['value']] if /^\s*(?<key>.+):\s*(?<value>.+)$/ === line
|
25
|
+
end.compact.to_h
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Sysdo
|
2
|
+
module SourceLibrary
|
3
|
+
# Only supports Wi-Fi
|
4
|
+
module Network
|
5
|
+
def self.changed
|
6
|
+
EventSource::PolledChange.new { network_status }
|
7
|
+
end
|
8
|
+
|
9
|
+
protected
|
10
|
+
|
11
|
+
NetworkStatus = Struct.new('NetworkStatus', :connected, :type, :ssid) do
|
12
|
+
def connected?
|
13
|
+
connected
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.network_status
|
18
|
+
ssid = `iwgetid -r`.chomp
|
19
|
+
if $?.success?
|
20
|
+
NetworkStatus.new(true, :wifi, ssid)
|
21
|
+
else
|
22
|
+
NetworkStatus.new(false, nil, nil)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Sysdo
|
2
|
+
module SourceLibrary
|
3
|
+
module Usb
|
4
|
+
def self.connected
|
5
|
+
EventSource::PolledCollectionChange.new(:add) { attached_devices }
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.disconnected
|
9
|
+
EventSource::PolledCollectionChange.new(:remove) { attached_devices }
|
10
|
+
end
|
11
|
+
|
12
|
+
protected
|
13
|
+
|
14
|
+
UsbDevice = Struct.new('UsbDevice', :name, :id, :bus, :device)
|
15
|
+
|
16
|
+
def self.attached_devices
|
17
|
+
`lsusb`.each_line.map do |line|
|
18
|
+
UsbDevice.new($~['name'], $~['id'], $~['bus'].to_i, $~['device'].to_i) \
|
19
|
+
if /^Bus (?<bus>\d+) Device (?<device>\d+): ID (?<id>.{4}:.{4}) (?<name>.+)$/ === line.strip
|
20
|
+
end.compact
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/sysdo.gemspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
lib = File.expand_path("../lib", __FILE__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require "sysdo"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "sysdo"
|
7
|
+
spec.version = Sysdo::VERSION
|
8
|
+
spec.authors = ["Aaron Christiansen"]
|
9
|
+
spec.email = ["hello@aaronc.cc"]
|
10
|
+
|
11
|
+
spec.summary = %q{Do things automatically}
|
12
|
+
spec.homepage = "https://github.com/AaronC81/sysdo"
|
13
|
+
spec.license = "MIT"
|
14
|
+
|
15
|
+
# Specify which files should be added to the gem when it is released.
|
16
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
17
|
+
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
18
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features|sorbet)/}) }
|
19
|
+
end
|
20
|
+
spec.bindir = "exe"
|
21
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
22
|
+
spec.require_paths = ["lib"]
|
23
|
+
|
24
|
+
spec.add_dependency "daemons", "~> 1.3"
|
25
|
+
|
26
|
+
spec.add_development_dependency "bundler", "~> 2.0"
|
27
|
+
spec.add_development_dependency "rake", ">= 12.3.3"
|
28
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
29
|
+
end
|
metadata
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sysdo
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Aaron Christiansen
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-12-28 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: daemons
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.3'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '2.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '2.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 12.3.3
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 12.3.3
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '3.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '3.0'
|
69
|
+
description:
|
70
|
+
email:
|
71
|
+
- hello@aaronc.cc
|
72
|
+
executables:
|
73
|
+
- sysdo
|
74
|
+
extensions: []
|
75
|
+
extra_rdoc_files: []
|
76
|
+
files:
|
77
|
+
- Gemfile
|
78
|
+
- Gemfile.lock
|
79
|
+
- README.md
|
80
|
+
- exe/sysdo
|
81
|
+
- lib/sysdo.rb
|
82
|
+
- lib/sysdo/cli.rb
|
83
|
+
- lib/sysdo/dsl.rb
|
84
|
+
- lib/sysdo/event_source.rb
|
85
|
+
- lib/sysdo/event_source/polled_change.rb
|
86
|
+
- lib/sysdo/event_source/polled_collection_change.rb
|
87
|
+
- lib/sysdo/event_source/polled_equal_change.rb
|
88
|
+
- lib/sysdo/source_library/battery.rb
|
89
|
+
- lib/sysdo/source_library/network.rb
|
90
|
+
- lib/sysdo/source_library/usb.rb
|
91
|
+
- lib/sysdo/version.rb
|
92
|
+
- sysdo.gemspec
|
93
|
+
homepage: https://github.com/AaronC81/sysdo
|
94
|
+
licenses:
|
95
|
+
- MIT
|
96
|
+
metadata: {}
|
97
|
+
post_install_message:
|
98
|
+
rdoc_options: []
|
99
|
+
require_paths:
|
100
|
+
- lib
|
101
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
102
|
+
requirements:
|
103
|
+
- - ">="
|
104
|
+
- !ruby/object:Gem::Version
|
105
|
+
version: '0'
|
106
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
requirements: []
|
112
|
+
rubygems_version: 3.0.3
|
113
|
+
signing_key:
|
114
|
+
specification_version: 4
|
115
|
+
summary: Do things automatically
|
116
|
+
test_files: []
|