summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Schlaeger <chris@linux.com>2014-07-20 21:47:39 +0200
committerChris Schlaeger <chris@linux.com>2014-07-20 21:47:39 +0200
commit06fd275a92cee58de4fcb2ca5e8f255f655d4ba5 (patch)
tree8eff1d8252ff14e7367d8aa68781d01d9e267f57
parentcc72a9807699b95363d0ae58aa5237d982946470 (diff)
downloadpostrunner-06fd275a92cee58de4fcb2ca5e8f255f655d4ba5.zip
Lots of cleanup work
-rwxr-xr-xbin/postrunner5
-rw-r--r--lib/postrunner/ActivitiesDB.rb35
-rw-r--r--lib/postrunner/Activity.rb53
-rw-r--r--lib/postrunner/Main.rb43
-rw-r--r--lib/postrunner/RuntimeConfig.rb20
-rw-r--r--postrunner.gemspec8
6 files changed, 148 insertions, 16 deletions
diff --git a/bin/postrunner b/bin/postrunner
new file mode 100755
index 0000000..988c5c5
--- /dev/null
+++ b/bin/postrunner
@@ -0,0 +1,5 @@
+#!/usr/bin/env ruby
+
+$:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
+require File.basename(__FILE__)
+
diff --git a/lib/postrunner/ActivitiesDB.rb b/lib/postrunner/ActivitiesDB.rb
index df0c105..c8785fb 100644
--- a/lib/postrunner/ActivitiesDB.rb
+++ b/lib/postrunner/ActivitiesDB.rb
@@ -8,6 +8,8 @@ module PostRunner
class ActivitiesDB
+ include Fit4Ruby::Converters
+
def initialize(db_dir)
@db_dir = db_dir
@fit_dir = File.join(@db_dir, 'fit')
@@ -21,24 +23,28 @@ module PostRunner
@activities = []
end
rescue
- Log.fatal "Cannot load archive file #{@archive_file}: #{$!}"
+ Log.fatal "Cannot load archive file '#{@archive_file}': #{$!}"
end
else
create_directories
@activities = []
end
+
+ unless @activities.is_a?(Array)
+ Log.fatal "The archive file '#{@archive_file}' is corrupted"
+ 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"
+ Log.debug "Activity #{fit_file} is already included in the archive"
return false
end
begin
fit_activity = Fit4Ruby.read(fit_file)
- rescue
+ rescue Fit4Ruby::Error
Log.error "Cannot read #{fit_file}: #{$!}"
return false
end
@@ -50,12 +56,27 @@ module PostRunner
end
@activities << Activity.new(base_fit_file, fit_activity)
+ @activities.sort! do |a1, a2|
+ a2.start_time <=> a1.start_time
+ end
sync
Log.info "#{fit_file} successfully added to archive"
true
end
+
+ def rename(fit_file, name)
+ base_fit_file = File.basename(fit_file)
+ @activities.each do |a|
+ if a.fit_file == base_fit_file
+ a.name = name
+ sync
+ break
+ end
+ end
+ end
+
def map_to_files(query)
case query
when /\A-?\d+$\z/
@@ -74,7 +95,6 @@ module PostRunner
# (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|
@@ -93,7 +113,12 @@ module PostRunner
i = 0
@activities.each do |a|
i += 1
- puts "#{"%4d" % i} #{"%12s" % a.fit_file} #{a.start_time}"
+ puts "#{'%4d' % i} " +
+ "#{'%-20s' % a.name[0..19]} " +
+ "#{'%22s' % a.start_time.strftime("%a, %Y %b %d %H:%M")} " +
+ "#{'%7.2f' % (a.distance / 1000)} " +
+ "#{'%8s' % secsToHMS(a.duration)} " +
+ "#{'%5s' % speedToPace(a.avg_speed)} "
end
end
diff --git a/lib/postrunner/Activity.rb b/lib/postrunner/Activity.rb
index 96c9887..964a702 100644
--- a/lib/postrunner/Activity.rb
+++ b/lib/postrunner/Activity.rb
@@ -1,14 +1,61 @@
require 'fit4ruby'
+require 'postrunner/RuntimeConfig'
module PostRunner
class Activity
- attr_reader :fit_file, :start_time
+ attr_reader :fit_file
+ attr_accessor :name
- def initialize(fit_file, fit_activity)
+ # This is a list of variables that provide data from the fit file. To
+ # speed up access to it, we cache the data in the activity database.
+ @@CachedVariables = %w( start_time distance duration avg_speed )
+
+ def initialize(fit_file, fit_activity, name = nil)
@fit_file = fit_file
- @start_time = fit_activity.start_time
+ @fit_activity = fit_activity
+ @name = name || fit_file
+
+ @@CachedVariables.each do |v|
+ v_str = "@#{v}"
+ instance_variable_set(v_str, fit_activity.send(v))
+ self.class.send(:attr_reader, v.to_sym)
+ end
+ end
+
+ def yaml_initialize(tag, value)
+ # Create attr_readers for cached variables.
+ @@CachedVariables.each { |v| self.class.send(:attr_reader, v.to_sym) }
+
+ # Load all attributes and assign them to instance variables.
+ value.each do |a, v|
+ instance_variable_set("@" + a, v)
+ end
+ # Use the FIT file name as activity name if none has been set yet.
+ @name = @fit_file unless @name
+ end
+
+ def encode_with(coder)
+ attr_ignore = %w( @fit_activity )
+
+ instance_variables.each do |v|
+ v = v.to_s
+ next if attr_ignore.include?(v)
+
+ coder[v[1..-1]] = instance_variable_get(v)
+ end
+ end
+
+ def method_missing(method_name, *args, &block)
+ fit_file = File.join(Config['fit_dir'], @fit_file)
+ begin
+ @fit_activity = Fit4Ruby.read(fit_file) unless @fit_activity
+ rescue Fit4Ruby::Error
+ Log.error "Cannot read #{fit_file}: #{$!}"
+ return false
+ end
+ @fit_activity.send(method_name, *args, &block)
end
end
diff --git a/lib/postrunner/Main.rb b/lib/postrunner/Main.rb
index 26e1005..4e2f020 100644
--- a/lib/postrunner/Main.rb
+++ b/lib/postrunner/Main.rb
@@ -1,6 +1,7 @@
require 'optparse'
require 'logger'
require 'fit4ruby'
+require 'postrunner/RuntimeConfig'
require 'postrunner/ActivitiesDB'
module PostRunner
@@ -11,6 +12,7 @@ module PostRunner
def initialize(args)
@filter = nil
+ @name = nil
@activities = ActivitiesDB.new(File.join(ENV['HOME'], '.postrunner'))
execute_command(parse_options(args))
@@ -42,6 +44,18 @@ module PostRunner
@filter.field_names = [] unless @filter.field_names
@filter.field_names << n
end
+ opts.on('--filter-undef',
+ "Don't show fields with undefined values") do
+ @filter = Fit4Ruby::FitFilter.new unless @filter
+ @filter.ignore_undef = true
+ end
+
+ opts.separator "Options for the 'import' and 'rename' command:"
+
+ opts.on('--name name', String,
+ 'Name or rename the activity to the specified name') do |n|
+ @name = n
+ end
end
parser.parse!(args)
@@ -50,7 +64,7 @@ module PostRunner
def execute_command(args)
case args.shift
when 'check'
- process_files(args, :check)
+ process_files_or_activities(args, :check)
when 'dump'
@filter = Fit4Ruby::FitFilter.new unless @filter
process_files_or_activities(args, :dump)
@@ -58,8 +72,10 @@ module PostRunner
process_files(args, :import)
when 'list'
@activities.list
+ when 'rename'
+ process_activities(args, :rename)
when 'summary'
- process_files(args, :summary)
+ process_files_or_activities(args, :summary)
else
Log.fatal("No command provided")
end
@@ -76,11 +92,27 @@ module PostRunner
process_files(files, command)
else
- process_files(foa, command)
+ process_files([ foa ], command)
end
end
end
+ def process_activities(activity_files, command)
+ activity_files.each do |a|
+ if a[0] == ':'
+ files = @activities.map_to_files(a[1..-1])
+ if files.empty?
+ Log.warn "No matching activities found for '#{a}'"
+ return
+ end
+ process_files(files, command)
+ else
+ Log.fatal "Activity references must start with ':': #{a}"
+ 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")
@@ -98,8 +130,11 @@ module PostRunner
end
def process_file(file, command)
- if command == :import
+ case command
+ when :import
@activities.add(file)
+ when :rename
+ @activities.rename(file, @name)
else
begin
activity = Fit4Ruby::read(file, @filter)
diff --git a/lib/postrunner/RuntimeConfig.rb b/lib/postrunner/RuntimeConfig.rb
new file mode 100644
index 0000000..2d5dccb
--- /dev/null
+++ b/lib/postrunner/RuntimeConfig.rb
@@ -0,0 +1,20 @@
+module PostRunner
+
+ class RuntimeConfig
+
+ def initialize
+ @settings = {}
+ @settings['data_dir'] = File.join(ENV['HOME'], '.postrunner')
+ @settings['fit_dir'] = File.join(@settings['data_dir'], 'fit')
+ end
+
+ def [](key)
+ @settings[key]
+ end
+
+ end
+
+ Config = RuntimeConfig.new
+
+end
+
diff --git a/postrunner.gemspec b/postrunner.gemspec
index cc6c537..a63343e 100644
--- a/postrunner.gemspec
+++ b/postrunner.gemspec
@@ -5,20 +5,20 @@ require 'postrunner/version'
Gem::Specification.new do |spec|
spec.name = "postrunner"
- spec.version = Postrunner::VERSION
+ spec.version = PostRunner::VERSION
spec.authors = ["Chris Schlaeger"]
spec.email = ["chris@linux.com"]
spec.summary = %q{Application to manage and analyze Garmin FIT files.}
spec.description = %q{This application will allow you to manage and analyze .FIT files as generated by Garmin GPS devices. The application was developed for the Garmin Forerunner 620. Other devices may or may not work. Only devices that expose themselves as USB Mass Storage devices are supported.}
- spec.homepage = "TBD"
- spec.license = "MIT"
+ spec.homepage = 'https://github.com/scrapper/fit4ruby'
+ spec.license = "GNU GPL version 2"
spec.files = `git ls-files -z`.split("\x0")
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
spec.require_paths = ["lib"]
+ spec.required_ruby_version = '>=2.0'
spec.add_development_dependency "bundler", "~> 1.6"
spec.add_development_dependency "rake"
- spec.add_development_dependency "fit4ruby"
end