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.
@@ -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
@@ -0,0 +1,4 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in parlour.gemspec
4
+ gemspec
@@ -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
@@ -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.
@@ -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
@@ -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'
@@ -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
@@ -0,0 +1,14 @@
1
+ module Sysdo
2
+ class Dsl
3
+ attr_reader :event_sources
4
+
5
+ def initialize
6
+ @event_sources = []
7
+ end
8
+
9
+ def on(event_source, &action)
10
+ event_source.on_fire = action
11
+ @event_sources << event_source
12
+ end
13
+ end
14
+ end
@@ -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
@@ -0,0 +1,3 @@
1
+ module Sysdo
2
+ VERSION = '0.0.1'
3
+ end
@@ -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: []