git-fit 0.0.0 → 0.1.0
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 +4 -4
- data/exe/git-fit +5 -0
- data/lib/git-fit.rb +7 -0
- data/lib/git_fit/cli.rb +61 -0
- data/lib/git_fit/config.rb +101 -0
- data/lib/git_fit/config_template.rb +44 -0
- data/lib/git_fit/version.rb +1 -1
- metadata +22 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e868be2f4295bf56a1af4e653dcadb26bca9c67a3f4cf42e8c5822b55ae380e6
|
|
4
|
+
data.tar.gz: 49470e6b69e829a484e7347a44cb48241f9366a6cb2a345023da903e4045d00f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d5a45ab91987725f37a00dadf6e16f8c2c45a4258a9bde275bebc8203c12bd7376e9d4605dcd87c1f5432c735c50d9ac30e42deb18b4d92611b1a90418834b7f
|
|
7
|
+
data.tar.gz: 2ce6cd5123f4d55ff5f8316c5cdd6c912dc0be3721db63b5a844c149fa38743792a5d2e4c3d46feb3e2d4d23562a7f0c6f04f17d4f9c29728384eb2647f49e07
|
data/exe/git-fit
ADDED
data/lib/git-fit.rb
CHANGED
data/lib/git_fit/cli.rb
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
require "thor"
|
|
2
|
+
|
|
3
|
+
module GitFit
|
|
4
|
+
class CLI < Thor
|
|
5
|
+
package_name "git-fit"
|
|
6
|
+
|
|
7
|
+
class_option :config, type: :string, desc: "Config file path", aliases: "-c"
|
|
8
|
+
|
|
9
|
+
def self.exit_on_failure?
|
|
10
|
+
true
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
desc "version", "Show version"
|
|
14
|
+
def version
|
|
15
|
+
puts "git-fit v#{GitFit::VERSION}"
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
desc "init", "Generate config.yml"
|
|
19
|
+
option :output, type: :string, desc: "Output path", aliases: "-o"
|
|
20
|
+
def init
|
|
21
|
+
path = options[:output] || "config/config.yml"
|
|
22
|
+
FileUtils.mkdir_p(File.dirname(path))
|
|
23
|
+
|
|
24
|
+
if File.exist?(path)
|
|
25
|
+
existing = YAML.safe_load(File.read(path)) || {}
|
|
26
|
+
merged = deep_merge(ConfigTemplate.hash, existing)
|
|
27
|
+
File.write(path, YAML.dump(merged))
|
|
28
|
+
say_status :merged, path, :green
|
|
29
|
+
else
|
|
30
|
+
File.write(path, ConfigTemplate.generate)
|
|
31
|
+
say_status :created, path, :green
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
no_commands do
|
|
36
|
+
def git_fit_config
|
|
37
|
+
@git_fit_config ||= GitFit::Config.new(options[:config])
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def deep_merge(template, existing)
|
|
41
|
+
result = deep_dup(template)
|
|
42
|
+
existing.each do |key, val|
|
|
43
|
+
if val.is_a?(Hash) && result[key].is_a?(Hash)
|
|
44
|
+
result[key] = deep_merge(result[key], val)
|
|
45
|
+
else
|
|
46
|
+
result[key] = val
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
result
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def deep_dup(obj)
|
|
53
|
+
case obj
|
|
54
|
+
when Hash then obj.each_with_object({}) { |(k, v), h| h[k] = deep_dup(v) }
|
|
55
|
+
when Array then obj.map { |v| deep_dup(v) }
|
|
56
|
+
else obj
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
require "yaml"
|
|
2
|
+
|
|
3
|
+
module GitFit
|
|
4
|
+
# 三优先级: env var > YAML > DEFAULTS
|
|
5
|
+
class Config
|
|
6
|
+
DEFAULTS = {
|
|
7
|
+
"database" => { "path" => "db/fit.sqlite3" },
|
|
8
|
+
"sync" => {},
|
|
9
|
+
"export" => {
|
|
10
|
+
"json" => { "path" => "site/activities.json" },
|
|
11
|
+
"svg" => { "dir" => "site/svg" },
|
|
12
|
+
"csv" => { "path" => "site/workouts.csv" },
|
|
13
|
+
"gpx" => { "path" => "site/gpx_out" }
|
|
14
|
+
},
|
|
15
|
+
"privacy" => {
|
|
16
|
+
"start_end_range" => 200
|
|
17
|
+
},
|
|
18
|
+
"system" => {
|
|
19
|
+
"units" => "metric",
|
|
20
|
+
"log_level" => "info",
|
|
21
|
+
"timezone" => "Asia/Shanghai"
|
|
22
|
+
}
|
|
23
|
+
}.freeze
|
|
24
|
+
|
|
25
|
+
DEFAULT_PATH = "config/config.yml"
|
|
26
|
+
KNOWN_TOP_KEYS = %w[database sync export privacy system].freeze
|
|
27
|
+
|
|
28
|
+
def initialize(path = nil)
|
|
29
|
+
@data = deep_dup(DEFAULTS)
|
|
30
|
+
load_file(path) if path
|
|
31
|
+
load_file(DEFAULT_PATH) if !path && File.exist?(DEFAULT_PATH)
|
|
32
|
+
load_env
|
|
33
|
+
validate!
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def [](key)
|
|
37
|
+
@data[key]
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def dig(*keys)
|
|
41
|
+
@data.dig(*keys)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def sync_config(source)
|
|
45
|
+
@data.dig("sync", source) || {}
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def privacy_config
|
|
49
|
+
@data["privacy"] || {}
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def export_config
|
|
53
|
+
@data["export"] || {}
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def db_path
|
|
57
|
+
@data.dig("database", "path") || DEFAULTS["database"]["path"]
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
private
|
|
61
|
+
|
|
62
|
+
# v0.1.0: 仅支持 DATABASE_PATH 覆盖
|
|
63
|
+
# v0.1.1+: 引入 register_config 注册机制
|
|
64
|
+
def load_env
|
|
65
|
+
@data["database"]["path"] = ENV["GIT_FIT_DATABASE_PATH"] if ENV["GIT_FIT_DATABASE_PATH"]
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def validate!
|
|
69
|
+
@data.each_key do |k|
|
|
70
|
+
next if k.empty? || KNOWN_TOP_KEYS.include?(k)
|
|
71
|
+
warn "Config: unknown top-level key '#{k}'"
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def load_file(path)
|
|
76
|
+
yaml = YAML.safe_load(File.read(path)) || {}
|
|
77
|
+
deep_merge!(@data, yaml)
|
|
78
|
+
rescue => e
|
|
79
|
+
warn "Config: failed to load #{path}: #{e.message}"
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def deep_merge!(target, source)
|
|
83
|
+
source.each do |key, val|
|
|
84
|
+
if val.is_a?(Hash) && target[key].is_a?(Hash)
|
|
85
|
+
deep_merge!(target[key], val)
|
|
86
|
+
else
|
|
87
|
+
target[key] = deep_dup(val)
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
target
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def deep_dup(obj)
|
|
94
|
+
case obj
|
|
95
|
+
when Hash then obj.each_with_object({}) { |(k, v), h| h[k] = deep_dup(v) }
|
|
96
|
+
when Array then obj.map { |v| deep_dup(v) }
|
|
97
|
+
else obj
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
module GitFit
|
|
2
|
+
class ConfigTemplate
|
|
3
|
+
def self.generate
|
|
4
|
+
<<~YAML
|
|
5
|
+
---
|
|
6
|
+
database:
|
|
7
|
+
path: db/fit.sqlite3
|
|
8
|
+
|
|
9
|
+
sync:
|
|
10
|
+
# strava:
|
|
11
|
+
# client_id: ""
|
|
12
|
+
# refresh_token: ""
|
|
13
|
+
|
|
14
|
+
# garmin:
|
|
15
|
+
# email: ""
|
|
16
|
+
# password: ""
|
|
17
|
+
|
|
18
|
+
# keep:
|
|
19
|
+
# phone: ""
|
|
20
|
+
# password: ""
|
|
21
|
+
|
|
22
|
+
# igpsport:
|
|
23
|
+
# phone: ""
|
|
24
|
+
# password: ""
|
|
25
|
+
|
|
26
|
+
export:
|
|
27
|
+
json:
|
|
28
|
+
path: site/activities.json
|
|
29
|
+
|
|
30
|
+
privacy:
|
|
31
|
+
start_end_range: 200
|
|
32
|
+
|
|
33
|
+
system:
|
|
34
|
+
units: metric
|
|
35
|
+
log_level: info
|
|
36
|
+
timezone: Asia/Shanghai
|
|
37
|
+
YAML
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def self.hash
|
|
41
|
+
YAML.safe_load(generate) || {}
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
data/lib/git_fit/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,23 +1,42 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: git-fit
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Lax
|
|
8
8
|
bindir: exe
|
|
9
9
|
cert_chain: []
|
|
10
10
|
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
-
dependencies:
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: thor
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - "~>"
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '1.3'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - "~>"
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '1.3'
|
|
12
26
|
description: A git extension CLI for aggregating, managing, and exporting fitness
|
|
13
27
|
activity data from multiple sources (Garmin, Strava, Keep, etc.)
|
|
14
28
|
email:
|
|
15
29
|
- lax@liulantao.com
|
|
16
|
-
executables:
|
|
30
|
+
executables:
|
|
31
|
+
- git-fit
|
|
17
32
|
extensions: []
|
|
18
33
|
extra_rdoc_files: []
|
|
19
34
|
files:
|
|
35
|
+
- exe/git-fit
|
|
20
36
|
- lib/git-fit.rb
|
|
37
|
+
- lib/git_fit/cli.rb
|
|
38
|
+
- lib/git_fit/config.rb
|
|
39
|
+
- lib/git_fit/config_template.rb
|
|
21
40
|
- lib/git_fit/version.rb
|
|
22
41
|
homepage: https://github.com/Lax/git-fit
|
|
23
42
|
licenses:
|