summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/postrunner.rb11
-rw-r--r--lib/postrunner/ActivitiesDB.rb123
-rw-r--r--lib/postrunner/Activity.rb17
-rw-r--r--lib/postrunner/Main.rb116
-rw-r--r--lib/postrunner/version.rb3
5 files changed, 270 insertions, 0 deletions
diff --git a/lib/postrunner.rb b/lib/postrunner.rb
new file mode 100644
index 0000000..681c583
--- /dev/null
+++ b/lib/postrunner.rb
@@ -0,0 +1,11 @@
+$:.unshift(File.join(File.dirname(__FILE__), '..', '..', 'fit4ruby', 'lib'))
+$:.unshift(File.dirname(__FILE__))
+
+require 'postrunner/version'
+require 'postrunner/Main'
+
+module PostRunner
+
+ Main.new(ARGV)
+
+end
diff --git a/lib/postrunner/ActivitiesDB.rb b/lib/postrunner/ActivitiesDB.rb
new file mode 100644
index 0000000..df0c105
--- /dev/null
+++ b/lib/postrunner/ActivitiesDB.rb
@@ -0,0 +1,123 @@
+require 'fileutils'
+require 'yaml'
+
+require 'fit4ruby'
+require 'postrunner/Activity'
+
+module PostRunner
+
+ class ActivitiesDB
+
+ def initialize(db_dir)
+ @db_dir = db_dir
+ @fit_dir = File.join(@db_dir, 'fit')
+ @archive_file = File.join(@db_dir, 'archive.yml')
+
+ if Dir.exists?(@db_dir)
+ begin
+ if File.exists?(@archive_file)
+ @activities = YAML.load_file(@archive_file)
+ else
+ @activities = []
+ end
+ rescue
+ Log.fatal "Cannot load archive file #{@archive_file}: #{$!}"
+ end
+ else
+ create_directories
+ @activities = []
+ end
+ end
+
+ def add(fit_file)
+ base_fit_file = File.basename(fit_file)
+ if @activities.find { |a| a.fit_file == base_fit_file }
+ Log.warn "Activity #{fit_file} is already included in the archive"
+ return false
+ end
+
+ begin
+ fit_activity = Fit4Ruby.read(fit_file)
+ rescue
+ Log.error "Cannot read #{fit_file}: #{$!}"
+ return false
+ end
+
+ begin
+ FileUtils.cp(fit_file, @fit_dir)
+ rescue
+ Log.fatal "Cannot copy #{fit_file} into #{@fit_dir}: #{$!}"
+ end
+
+ @activities << Activity.new(base_fit_file, fit_activity)
+ sync
+ Log.info "#{fit_file} successfully added to archive"
+
+ true
+ end
+
+ def map_to_files(query)
+ case query
+ when /\A-?\d+$\z/
+ index = query.to_i
+ # The UI counts the activities from 1 to N. Ruby counts from 0 -
+ # (N-1).
+ index -= 1 if index > 0
+ if (a = @activities[index])
+ return [ File.join(@fit_dir, a.fit_file) ]
+ end
+ when /\A-?\d+--?\d+\z/
+ idxs = query.match(/(?<sidx>-?\d+)-(?<eidx>-?[0-9]+)/)
+ sidx = idxs['sidx'].to_i
+ eidx = idxs['eidx'].to_i
+ # The UI counts the activities from 1 to N. Ruby counts from 0 -
+ # (N-1).
+ sidx -= 1 if sidx > 0
+ eidx -= 1 if eidx > 0
+ puts "iv: #{sidx} - #{eidx}"
+ unless (as = @activities[sidx..eidx]).empty?
+ files = []
+ as.each do |a|
+ files << File.join(@fit_dir, a.fit_file)
+ end
+ return files
+ end
+ else
+ Log.error "Invalid activity query: #{query}"
+ end
+
+ []
+ end
+
+ def list
+ i = 0
+ @activities.each do |a|
+ i += 1
+ puts "#{"%4d" % i} #{"%12s" % a.fit_file} #{a.start_time}"
+ end
+ end
+
+ private
+
+ def sync
+ File.open(@archive_file, 'w') { |f| f.write(@activities.to_yaml) }
+ end
+
+ def create_directories
+ Log.info "Creating data directory #{@db_dir}"
+ begin
+ Dir.mkdir(@db_dir)
+ rescue
+ Log.fatal "Cannot create data directory #{@db_dir}: #{$!}"
+ end
+ begin
+ Dir.mkdir(@fit_dir)
+ rescue
+ Log.fatal "Cannot create fit directory #{@fit_dir}: #{$!}"
+ end
+ end
+
+ end
+
+end
+
diff --git a/lib/postrunner/Activity.rb b/lib/postrunner/Activity.rb
new file mode 100644
index 0000000..96c9887
--- /dev/null
+++ b/lib/postrunner/Activity.rb
@@ -0,0 +1,17 @@
+require 'fit4ruby'
+
+module PostRunner
+
+ class Activity
+
+ attr_reader :fit_file, :start_time
+
+ def initialize(fit_file, fit_activity)
+ @fit_file = fit_file
+ @start_time = fit_activity.start_time
+ end
+
+ end
+
+end
+
diff --git a/lib/postrunner/Main.rb b/lib/postrunner/Main.rb
new file mode 100644
index 0000000..26e1005
--- /dev/null
+++ b/lib/postrunner/Main.rb
@@ -0,0 +1,116 @@
+require 'optparse'
+require 'logger'
+require 'fit4ruby'
+require 'postrunner/ActivitiesDB'
+
+module PostRunner
+
+ Log = Fit4Ruby::ILogger.new(STDOUT)
+
+ class Main
+
+ def initialize(args)
+ @filter = nil
+ @activities = ActivitiesDB.new(File.join(ENV['HOME'], '.postrunner'))
+
+ execute_command(parse_options(args))
+ end
+
+ private
+
+ def parse_options(args)
+ parser = OptionParser.new do |opts|
+ opts.banner = "Usage postrunner <command> [options]"
+ opts.separator ""
+ opts.separator "Options for the 'dump' command:"
+
+ opts.on('--filter-msg N', Integer,
+ 'Only dump messages of type number N') do |n|
+ @filter = Fit4Ruby::FitFilter.new unless @filter
+ @filter.record_numbers = [] unless @filter.record_numbers
+ @filter.record_numbers << n.to_i
+ end
+ opts.on('--filter-msg-idx N', Integer,
+ 'Only dump the N-th message of the specified types') do |n|
+ @filter = Fit4Ruby::FitFilter.new unless @filter
+ @filter.record_indexes = [] unless @filter.record_indexes
+ @filter.record_indexes << n.to_i
+ end
+ opts.on('--filter-field name', String,
+ 'Only dump the field \'name\' of the selected messages') do |n|
+ @filter = Fit4Ruby::FitFilter.new unless @filter
+ @filter.field_names = [] unless @filter.field_names
+ @filter.field_names << n
+ end
+ end
+
+ parser.parse!(args)
+ end
+
+ def execute_command(args)
+ case args.shift
+ when 'check'
+ process_files(args, :check)
+ when 'dump'
+ @filter = Fit4Ruby::FitFilter.new unless @filter
+ process_files_or_activities(args, :dump)
+ when 'import'
+ process_files(args, :import)
+ when 'list'
+ @activities.list
+ when 'summary'
+ process_files(args, :summary)
+ else
+ Log.fatal("No command provided")
+ end
+ end
+
+ def process_files_or_activities(files_or_activities, command)
+ files_or_activities.each do |foa|
+ if foa[0] == ':'
+ files = @activities.map_to_files(foa[1..-1])
+ if files.empty?
+ Log.warn "No matching activities found for '#{foa}'"
+ return
+ end
+
+ process_files(files, command)
+ else
+ process_files(foa, command)
+ end
+ end
+ end
+
+ def process_files(files_or_dirs, command)
+ if files_or_dirs.empty?
+ Log.fatal("You must provide at least one .FIT file name")
+ end
+
+ files_or_dirs.each do |fod|
+ if File.directory?(fod)
+ Dir.glob(File.join(fod, '*.FIT')).each do |file|
+ process_file(file, command)
+ end
+ else
+ process_file(fod, command)
+ end
+ end
+ end
+
+ def process_file(file, command)
+ if command == :import
+ @activities.add(file)
+ else
+ begin
+ activity = Fit4Ruby::read(file, @filter)
+ #rescue
+ # Log.error("File '#{file}' is corrupted!: #{$!}")
+ end
+ puts activity.to_s if command == :summary
+ end
+ end
+
+ end
+
+end
+
diff --git a/lib/postrunner/version.rb b/lib/postrunner/version.rb
new file mode 100644
index 0000000..3861ec6
--- /dev/null
+++ b/lib/postrunner/version.rb
@@ -0,0 +1,3 @@
+module PostRunner
+ VERSION = "0.0.1"
+end