aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKatharina Fey <kookie@spacekookie.de>2019-08-04 02:21:22 +0200
committerKatharina Fey <kookie@spacekookie.de>2019-08-04 02:21:22 +0200
commit7fd0a464821aa9ad9ef0d5a16d0bedecdf83c542 (patch)
tree709326434d2ec2f1cd1f872f04899852401b2dc8
parentc951ce7fa7aafc01997599e8ebd694c5a1178a09 (diff)
First functional version
Has a few problems: - Doesn't properly indent entries - Only processes _first_ open account - Doesn't catch enough errors - CLI parsing sucks
-rw-r--r--Gemfile3
-rwxr-xr-xcass.rb58
-rw-r--r--[-rwxr-xr-x]parser.rb53
-rw-r--r--start.rb25
-rw-r--r--stop.rb32
-rw-r--r--time_util.rb7
6 files changed, 149 insertions, 29 deletions
diff --git a/Gemfile b/Gemfile
new file mode 100644
index 0000000..f007eb2
--- /dev/null
+++ b/Gemfile
@@ -0,0 +1,3 @@
+source "https://rubygems.org"
+
+gem "parslet"
diff --git a/cass.rb b/cass.rb
new file mode 100755
index 0000000..7c8abbf
--- /dev/null
+++ b/cass.rb
@@ -0,0 +1,58 @@
+#!/usr/bin/env ruby
+
+require "optparse"
+require "pp"
+
+require_relative "parser"
+require_relative "time_util"
+
+op = OptionParser.new
+op.on("start ACCOUNT", String) do |acc|
+ puts acc
+end
+
+options = {}
+OptionParser.new do |opts|
+ opts.banner = "Usage: cassiopeia <command>"
+
+ opts.on("-f FILE", "--file=FILE", "Provide the working file") do |f|
+ options[:file] = f
+ end
+
+ opts.on("--start=ACCOUNT", "Start tracking time") do |acc|
+ options[:start] = acc
+ end
+
+ opts.on("--stop=ACCOUNT", "Stop working!") do |acc|
+ options[:stop] = acc
+ end
+
+ opts.on("-r", "--round", "Round to the next 15 minutes") do |r|
+ options[:round] = r
+ end
+
+ opts.on("-v", "--version", "Print program version") do |v|
+ puts "0.1.0"
+ end
+end.parse!
+
+path = options[:file]
+start = options[:start]
+stop = options[:stop]
+round = !!options[:round]
+
+file = File.open(path, "r") { |f| CassParser.new.parse(f.read) }
+
+if start
+ require_relative "start"
+ new = start(start, round, file)
+
+ File.open(path, "a") { |f| f.write(new) }
+elsif stop
+ require_relative "stop"
+ line, new = stop(stop, round, file)
+
+ lines = File.open(path, "r") { |f| f.readlines }
+ lines[line - 1] = new
+ File.open(path, "w") { |f| f.write(lines.join) }
+end
diff --git a/parser.rb b/parser.rb
index 4e261ba..08cc50c 100755..100644
--- a/parser.rb
+++ b/parser.rb
@@ -5,23 +5,23 @@ require "pp"
require "parslet"
include Parslet
-class EntryParser < Parslet::Parser
+class CassParser < Parslet::Parser
root :doc
### Type segments
- rule(:hour) { hour_.as(:hour) }
- rule(:minute) { minute_.as(:minute) }
- rule(:second) { second_.as(:second) }
+ # rule(:hour) { hour_.as(:hour) }
+ # rule(:minute) { minute_.as(:minute) }
+ # rule(:second) { second_.as(:second) }
- rule(:year) { year_.as(:year) }
- rule(:month) { month_.as(:month) }
- rule(:day) { day_.as(:day) }
+ # rule(:year) { year_.as(:year) }
+ # rule(:month) { month_.as(:month) }
+ # rule(:day) { day_.as(:day) }
- rule(:time) { time_.as(:time) }
- rule(:local) { local_.as(:local) }
- rule(:offset) { offset_.as(:offset) }
+ # rule(:time) { time_.as(:time) }
+ # rule(:local) { local_.as(:local) }
+ # rule(:offset) { offset_.as(:offset) }
- rule(:date) { date_.as(:date) }
+ # rule(:date) { date_.as(:date) }
rule(:datetime) { date >> str(" ") >> time }
rule(:daterange) { start >> str(" -") >> stop }
@@ -32,21 +32,21 @@ class EntryParser < Parslet::Parser
rule(:doc) { line_.repeat }
### Combinatory segments
- rule(:hour_) { digit.repeat(2, 2) }
- rule(:minute_) { digit.repeat(2, 2) }
- rule(:second_) { digit.repeat(2, 2) }
+ rule(:hour) { digit.repeat(2, 2) }
+ rule(:minute) { digit.repeat(2, 2) }
+ rule(:second) { digit.repeat(2, 2) }
- rule(:time_) { local >> offset }
- rule(:date_) { year >> str("-") >> month >> str("-") >> day }
+ rule(:time) { local >> offset }
+ rule(:date) { year >> str("-") >> month >> str("-") >> day }
- rule(:year_) { digit.repeat(4, 4) }
- rule(:month_) { digit.repeat(2, 2) }
- rule(:day_) { digit.repeat(2, 2) }
-
- rule(:local_) { hour >> str(":") >> minute >> str(":") >> second }
- rule(:offset_) { match("[zZ]") | tnoffset_ }
- rule(:poffset_) { str(" ") >> match("[+\-]") }
- rule(:tnoffset_) { poffset_ >> hour >> str(":").maybe >> minute }
+ rule(:year) { digit.repeat(4, 4) }
+ rule(:month) { digit.repeat(2, 2) }
+ rule(:day) { digit.repeat(2, 2) }
+
+ rule(:local) { hour >> str(":") >> minute >> str(":") >> second }
+ rule(:offset) { match("[zZ]") | tnoffset }
+ rule(:poffset) { str(" ") >> match("[+\-]") }
+ rule(:tnoffset) { poffset >> hour >> str(":").maybe >> minute }
rule(:title_) { text >> str(":") }
@@ -61,11 +61,6 @@ class EntryParser < Parslet::Parser
rule(:newline) { spaces.maybe >> str("\n") }
end
-PP.pp EntryParser.new.parse("
-# This is a comment
-Bobs Burger: 2019-07-21 21:00:00 +0200 -
-")
-
__END__
# Following is an example of what the `timebox` file format looks like
diff --git a/start.rb b/start.rb
new file mode 100644
index 0000000..3ec3c48
--- /dev/null
+++ b/start.rb
@@ -0,0 +1,25 @@
+"""
+This file is part of cassiopeia and licensed
+under the GNU Public License 3.0 (or later)
+
+cassiopeia-start - start working on an account
+
+This file is included and run from cass(1)
+"""
+
+require "time"
+require_relative "time_util"
+
+def start(account, round, file = [])
+ rel = file.select { |i| i[:title].to_s.include? account }
+
+ # This is a kind of fuzzy find
+ account = rel[0][:title].to_s[0..-2]
+
+ # Check if there's any ling jobs
+ jobs = rel.select { |i| i[:stop] == nil }.length
+ STDERR.puts \
+ "[Warn]: #{jobs} dangling jobs for account #{account}" if jobs > 0
+
+ "#{account}: #{round ? Time.now.round : Time.now} - "
+end
diff --git a/stop.rb b/stop.rb
new file mode 100644
index 0000000..fff5744
--- /dev/null
+++ b/stop.rb
@@ -0,0 +1,32 @@
+"""
+This file is part of cassiopeia and licensed
+under the GNU Public License 3.0 (or later)
+
+cassiopeia-stop - stop working on an account
+
+This file is included and run from cass(1)
+"""
+
+require "time"
+require_relative "time_util"
+
+def stop(account, round, file = [])
+ rel = file.select { |i| i[:title].to_s.include? account }
+
+ # This is a kind of fuzzy find
+ account = rel[0][:title].to_s[0..-2]
+
+ jobs = rel.select { |i| i[:stop] == nil }
+ if jobs.length == 0
+ STDERR.puts "No unfinished accounts for '#{account}'!"
+ exit 2
+ end
+
+ STDERR.puts "[Warn]: More than one dangling account!" unless jobs.length == 1
+ job = jobs[0]
+ line, _ = job[:title].line_and_column
+
+ # We return the line number too, so that we can inset correctly
+ return line, "#{account}:\
+ #{job[:start]} - #{round ? Time.now.round : Time.now}"
+end
diff --git a/time_util.rb b/time_util.rb
new file mode 100644
index 0000000..410b5cd
--- /dev/null
+++ b/time_util.rb
@@ -0,0 +1,7 @@
+class Time
+ def round(minutes = 15)
+ minutes *= 60
+ Time.at((self.to_f / minutes).round * minutes)
+ end
+end
+