git-fit 0.6.1 → 0.7.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 75362a4faf88f3ca8497484ba835358eb06d82e36d81ad3e53d7dc4ec877f478
4
- data.tar.gz: 6cd85cd677977d84670daa160235ff65b5a7ebad55b8cd51ea59cd5661a6bd8a
3
+ metadata.gz: 726e06c730a1309c59072df3f52e3261f5bf0e9d3b931e7a7016a8756c3190fa
4
+ data.tar.gz: 314a50f4b64054fe984e022421e464f22ae0a5469c9e7d369c5ef775ccdc0f14
5
5
  SHA512:
6
- metadata.gz: 3aba69713ec7ba93ead186be8b58fbe577186b83a47ccded9c0f872abe492f15ee5337577e7c4aa36c07f7e6d33588d50231001e85e083156f79324bcf5daca1
7
- data.tar.gz: 0d8e9e012c911e5609d00be8324995acef30f3a3ff2ba44d9e15380881c1c7882226074d70c5723953b42a0535bf4ec21b329d26fc78d4a9b0f51ca45766a820
6
+ metadata.gz: 2e36dcd8e78e57bbec0a451f1ce8d98fe4a3ab83dbbce334c0b528f08b5a2cc3d050a3b5da1092dbbc808d3afb6fb48b4d8052030f7d3301ac557027c97072d4
7
+ data.tar.gz: '00767969c5771dac29763dad5a65f4d1fd0c348ea127cfa36165dc46497000eb0db93ccff83aa13f5fc2c051d35ea618163ba1046e0abbb4c7cac315aac9f386'
data/lib/git-fit.rb CHANGED
@@ -56,11 +56,18 @@ require_relative "git_fit/timezone/resolver"
56
56
  require_relative "git_fit/privacy/polyline_filter"
57
57
  require_relative "git_fit/import"
58
58
  require_relative "git_fit/sync/base"
59
- require_relative "git_fit/sync/strava"
60
59
  require_relative "git_fit/util"
61
- require_relative "git_fit/sync/base"
62
- require_relative "git_fit/sync/strava"
63
60
  require_relative "git_fit/sync/lorem"
61
+ require_relative "git_fit/sync/garmin_base"
62
+ require_relative "git_fit/sync/garmin_base_di"
63
+ require_relative "git_fit/sync/garmin"
64
+ require_relative "git_fit/sync/garmin_cn"
65
+ require_relative "git_fit/sync/strava"
66
+ require_relative "git_fit/sync/keep"
67
+ require_relative "git_fit/sync/igpsport"
68
+ require_relative "git_fit/sync/xoss"
69
+ require_relative "git_fit/sync/xingzhe"
70
+ require_relative "git_fit/sync/runner"
64
71
  require_relative "git_fit/cli/sync"
65
72
  require_relative "git_fit/db/rebuild"
66
73
  require_relative "git_fit/db/connection"
@@ -4,46 +4,35 @@ module GitFit
4
4
  def sync
5
5
  db = connect_db
6
6
  source = options[:source]
7
- unless source
8
- say_status :error, "Use --source to specify a source (e.g. lorem)", :red
9
- return
10
- end
11
-
12
7
  filter = options[:activity]&.flat_map { |v| v.split(",") }&.map(&:strip)&.map(&:downcase)
13
8
  privacy = GitFit::Privacy::PolylineFilter.new(config: git_fit_config.privacy_config)
14
- adapter = build_sync_adapter(source, db, filter, privacy: privacy)
15
- unless adapter
16
- say_status :error, "Unknown source: #{source}", :red
17
- return
18
- end
19
9
 
20
- say_status :syncing, source, :green
21
- count = adapter.call
22
- if count > 0
23
- say_status :done, "#{source}: #{count} activities synced", :green
10
+ sources = if source
11
+ [source]
24
12
  else
25
- say_status :warn, "#{source}: 0 activities", :yellow
13
+ configured = (git_fit_config["sync"] || {}).keys
14
+ builtin = GitFit::Sync::Base.adapters
15
+ .map { |c| c.config_key }
16
+ if ENV["GIT_FIT_ENVIRONMENT"] == "testing"
17
+ builtin += GitFit::Sync::Base.test_adapters
18
+ .map { |c| c.config_key }
19
+ end
20
+ (builtin + configured).uniq
26
21
  end
27
- rescue => e
28
- say_status :error, "#{source}: #{e.message}", :red
29
- end
30
-
31
- private
32
22
 
33
- def source_configured?(source)
34
- return true if GitFit::Sync.const_defined?(source.capitalize)
35
- config = git_fit_config
36
- cfg = config.sync_config(source)
37
- cfg && !cfg.empty?
38
- end
39
-
40
- def build_sync_adapter(source, db, filter, privacy: nil)
41
- case source
42
- when "lorem"
43
- GitFit::Sync::Lorem.new(config: git_fit_config.sync_config(source), db: db, activity_filter: filter, privacy: privacy)
44
- else
45
- nil
46
- end
23
+ runner = GitFit::Sync::Runner.new(
24
+ sources: sources,
25
+ db: db,
26
+ config: git_fit_config,
27
+ activity_filter: filter,
28
+ privacy: privacy,
29
+ num_workers: git_fit_config.dig("sync", "workers") || 3,
30
+ time_budget: git_fit_config.dig("sync", "time_budget"),
31
+ total_timeout: git_fit_config.dig("sync", "total_timeout")
32
+ )
33
+ runner.run
34
+ rescue => e
35
+ say_status :error, e.message, :red
47
36
  end
48
37
  end
49
38
  end
@@ -5,7 +5,11 @@ module GitFit
5
5
  class Config
6
6
  DEFAULTS = {
7
7
  "database" => { "path" => "db/fit.sqlite3" },
8
- "sync" => {},
8
+ "sync" => {
9
+ "workers" => 3,
10
+ "time_budget" => nil,
11
+ "total_timeout" => nil
12
+ },
9
13
  "export" => {
10
14
  "json" => { "path" => "site/activities.json" },
11
15
  "svg" => { "dir" => "site/svg" },
@@ -60,7 +64,10 @@ module GitFit
60
64
  private
61
65
 
62
66
  def load_env
63
- @data["database"]["path"] = ENV["GIT_FIT_DATABASE_PATH"] if ENV["GIT_FIT_DATABASE_PATH"]
67
+ @data["database"]["path"] = ENV["GIT_FIT_DATABASE_PATH"] if ENV["GIT_FIT_DATABASE_PATH"] && !ENV["GIT_FIT_DATABASE_PATH"].empty?
68
+ @data["sync"]["workers"] = ENV["GIT_FIT_SYNC_WORKERS"].to_i if ENV["GIT_FIT_SYNC_WORKERS"] && !ENV["GIT_FIT_SYNC_WORKERS"].empty?
69
+ @data["sync"]["time_budget"] = ENV["GIT_FIT_SYNC_TIME_BUDGET"].to_f if ENV["GIT_FIT_SYNC_TIME_BUDGET"] && !ENV["GIT_FIT_SYNC_TIME_BUDGET"].empty?
70
+ @data["sync"]["total_timeout"] = ENV["GIT_FIT_SYNC_TOTAL_TIMEOUT"].to_f if ENV["GIT_FIT_SYNC_TOTAL_TIMEOUT"] && !ENV["GIT_FIT_SYNC_TOTAL_TIMEOUT"].empty?
64
71
 
65
72
  GitFit.registered_configs.each do |reg|
66
73
  reg[:keys].each do |key|
@@ -7,6 +7,10 @@ module GitFit
7
7
  path: db/fit.sqlite3
8
8
 
9
9
  sync:
10
+ # workers: 3 # env: GIT_FIT_SYNC_WORKERS
11
+ # time_budget: 300 # env: GIT_FIT_SYNC_TIME_BUDGET (seconds)
12
+ # total_timeout: 600 # env: GIT_FIT_SYNC_TOTAL_TIMEOUT (seconds)
13
+
10
14
  # strava: # env: GIT_FIT_STRAVA_CLIENT_ID
11
15
  # client_id: "" # env: GIT_FIT_STRAVA_CLIENT_SECRET
12
16
  # refresh_token: "" # env: GIT_FIT_STRAVA_REFRESH_TOKEN
@@ -26,6 +30,14 @@ module GitFit
26
30
  # lorem: # env: GIT_FIT_LOREM_COUNT
27
31
  # count: 5
28
32
 
33
+ # xoss: # env: GIT_FIT_XOSS_PHONE
34
+ # phone: "" # env: GIT_FIT_XOSS_PASSWORD
35
+ # password: ""
36
+
37
+ # xingzhe: # env: GIT_FIT_XINGZHE_EMAIL
38
+ # email: "" # env: GIT_FIT_XINGZHE_PASSWORD
39
+ # password: ""
40
+
29
41
  export:
30
42
  json:
31
43
  path: site/activities.json
@@ -1,4 +1,5 @@
1
1
  require "fileutils"
2
+ require "json"
2
3
  require "time"
3
4
 
4
5
  module GitFit
@@ -81,6 +82,32 @@ module GitFit
81
82
  )
82
83
  end
83
84
 
85
+ class << self
86
+ def adapters
87
+ @adapters ||= []
88
+ end
89
+
90
+ def test_adapters
91
+ @test_adapters ||= []
92
+ end
93
+
94
+ def register_adapter
95
+ Base.adapters << self unless Base.adapters.include?(self)
96
+ end
97
+
98
+ def register_test_adapter
99
+ Base.test_adapters << self unless Base.test_adapters.include?(self)
100
+ end
101
+
102
+ def config_key(source = nil)
103
+ if source
104
+ @config_key = source
105
+ else
106
+ @config_key ||= name.split("::").last.downcase
107
+ end
108
+ end
109
+ end
110
+
84
111
  protected
85
112
 
86
113
  def raw_dir
@@ -144,7 +171,11 @@ module GitFit
144
171
  end
145
172
 
146
173
  def raw_file_exists?(platform_id)
147
- File.exist?(raw_path(platform_id))
174
+ return false unless respond_to?(:raw_path, true)
175
+ path = raw_path(platform_id)
176
+ File.exist?(path)
177
+ rescue NotImplementedError
178
+ false
148
179
  end
149
180
 
150
181
  def show_progress?(count, total)
@@ -158,6 +189,38 @@ module GitFit
158
189
  return 1 unless total && total > 0
159
190
  [1, (1.5 * (total ** 0.4)).to_i].max
160
191
  end
192
+
193
+ def raw_path(platform_id)
194
+ raise NotImplementedError, "#{self.class} must implement #raw_path"
195
+ end
196
+
197
+ def write_source_archive(data, platform_id, ext = "json")
198
+ dir = raw_dir
199
+ FileUtils.mkdir_p(dir)
200
+ tmp = File.join(dir, ".#{platform_id}.#{ext}.tmp")
201
+ dest = File.join(dir, "#{platform_id}.#{ext}")
202
+ case data
203
+ when String then File.write(tmp, data)
204
+ when Hash, Array then File.write(tmp, JSON.generate(data))
205
+ end
206
+ File.rename(tmp, dest)
207
+ end
208
+
209
+ def write_standardized_json(attrs, platform_id)
210
+ dir = std_dir
211
+ FileUtils.mkdir_p(dir)
212
+ tmp = File.join(dir, ".#{platform_id}.json.tmp")
213
+ dest = File.join(dir, "#{platform_id}.json")
214
+ File.write(tmp, JSON.generate(attrs.transform_keys(&:to_s)))
215
+ File.rename(tmp, dest)
216
+ end
217
+
218
+ def existing_run_ids
219
+ prefix = "#{self.class.config_key}_"
220
+ @db[:activities].where(Sequel.like(:run_id, "#{prefix}%"))
221
+ .select_map(:run_id)
222
+ .map { |rid| rid.sub(/\A#{Regexp.escape(prefix)}/, "") }
223
+ end
161
224
  end
162
225
  end
163
226
  end
@@ -0,0 +1,16 @@
1
+ require_relative "garmin_base_di"
2
+
3
+ module GitFit
4
+ module Sync
5
+ class Garmin < GarminBaseDI
6
+ register_adapter
7
+ register_config :email, :password, :secret, :auth_seed
8
+ config_key "garmin"
9
+
10
+ def initialize(config:, db:, activity_filter: nil, privacy: nil, time_budget: nil)
11
+ super
12
+ @domain = "garmin.com"
13
+ end
14
+ end
15
+ end
16
+ end