RoyAalekh commited on
Commit
babf125
·
1 Parent(s): 04315ad

chore(cache): add auto cache-bump hooks and script

Browse files
.githooks/pre-commit ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env sh
2
+ # Auto-bump cache on commit and stage updated files
3
+
4
+ REPO_ROOT="$(git rev-parse --show-toplevel)"
5
+ cd "$REPO_ROOT" || exit 1
6
+
7
+ # Run bump (timestamp only) so every commit invalidates browser cache
8
+ python scripts/bump_cache.py --now >/dev/null 2>&1 || {
9
+ echo "[pre-commit] bump_cache failed; ensure Python is installed and scripts/bump_cache.py exists" 1>&2
10
+ exit 1
11
+ }
12
+
13
+ # Stage changed files
14
+ git add static/sw.js static/index.html static/map.html version.json 2>/dev/null
15
+
16
+ echo "[pre-commit] Cache bust updated and staged."
17
+ exit 0
.githooks/pre-push ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env sh
2
+ # Safety: ensure cache bump ran; if not, run it here before push
3
+
4
+ REPO_ROOT="$(git rev-parse --show-toplevel)"
5
+ cd "$REPO_ROOT" || exit 1
6
+
7
+ # Run bump (timestamp only) to be safe
8
+ python scripts/bump_cache.py --now >/dev/null 2>&1 || {
9
+ echo "[pre-push] bump_cache failed; ensure Python is installed and scripts/bump_cache.py exists" 1>&2
10
+ exit 1
11
+ }
12
+
13
+ # If files changed, create an auto-commit so pushed code matches cache version
14
+ if ! git diff --quiet -- static/sw.js static/index.html static/map.html version.json 2>/dev/null; then
15
+ git add static/sw.js static/index.html static/map.html version.json
16
+ git commit -m "chore(cache): auto-bump cache version before push" || true
17
+ echo "[pre-push] Auto-committed cache bump."
18
+ fi
19
+
20
+ exit 0
README.md CHANGED
@@ -92,3 +92,22 @@ A **secure, robust, and high-performance** web application for mapping, tracking
92
  ---
93
 
94
  Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
  ---
93
 
94
  Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
95
+
96
+ ## Developer workflow notes
97
+
98
+ ### Automatic cache busting on commit/push
99
+
100
+ This repo includes a small utility and Git hooks to ensure browsers always fetch the latest static assets:
101
+ - scripts/bump_cache.py updates service worker, HTML inline version/timestamp, and script tag query params.
102
+ - .githooks/pre-commit runs the bump (timestamp-only) and stages changed files.
103
+ - .githooks/pre-push runs a final bump and, if necessary, auto-commits the change before pushing.
104
+
105
+ Setup (one-time):
106
+ - git config core.hooksPath .githooks
107
+
108
+ Usage:
109
+ - Just commit and push normally. The hooks will bump the timestamp each time.
110
+ - To bump semantic version too: python scripts/bump_cache.py --bump patch (or minor/major). The hooks will stage the changes for your next commit.
111
+
112
+ Note for Windows developers:
113
+ - Git for Windows ships with a POSIX shell that executes hooks. Ensure Python is available on PATH.
scripts/bump_cache.py ADDED
@@ -0,0 +1,188 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ Automated cache-busting version bump utility for TreeTrack.
4
+
5
+ Updates:
6
+ - static/sw.js: const VERSION = <timestamp>
7
+ - static/index.html and static/map.html:
8
+ * inline currentVersion = '<version>'
9
+ * inline timestamp = '<timestamp>'
10
+ * script tag query params (?v=<version>&t=<timestamp>) for tree-track-app.js and map.js
11
+
12
+ Usage examples:
13
+ python scripts/bump_cache.py --now # bump timestamp only
14
+ python scripts/bump_cache.py --bump patch # bump version 1.2.3 -> 1.2.4 and timestamp
15
+ python scripts/bump_cache.py --set-version 5.1.2 # set specific version and bump timestamp
16
+
17
+ This script maintains state in version.json at repository root.
18
+ """
19
+
20
+ import argparse
21
+ import json
22
+ import os
23
+ import re
24
+ import sys
25
+ import time
26
+ from pathlib import Path
27
+
28
+ ROOT = Path(__file__).resolve().parents[1]
29
+ VERSION_FILE = ROOT / 'version.json'
30
+ FILES = {
31
+ 'sw': ROOT / 'static' / 'sw.js',
32
+ 'index': ROOT / 'static' / 'index.html',
33
+ 'map': ROOT / 'static' / 'map.html',
34
+ }
35
+
36
+ SEMVER_RE = re.compile(r"^(\d+)\.(\d+)\.(\d+)$")
37
+
38
+
39
+ def read_text(p: Path) -> str:
40
+ try:
41
+ return p.read_text(encoding='utf-8')
42
+ except FileNotFoundError:
43
+ print(f"Error: file not found: {p}", file=sys.stderr)
44
+ sys.exit(1)
45
+
46
+
47
+ def write_text(p: Path, content: str) -> None:
48
+ p.write_text(content, encoding='utf-8', newline='\n')
49
+
50
+
51
+ def bump_semver(version: str, which: str) -> str:
52
+ m = SEMVER_RE.match(version)
53
+ if not m:
54
+ raise ValueError(f"Invalid semver: {version}")
55
+ major, minor, patch = map(int, m.groups())
56
+ if which == 'major':
57
+ major += 1
58
+ minor = 0
59
+ patch = 0
60
+ elif which == 'minor':
61
+ minor += 1
62
+ patch = 0
63
+ elif which == 'patch':
64
+ patch += 1
65
+ else:
66
+ raise ValueError(f"Unknown bump type: {which}")
67
+ return f"{major}.{minor}.{patch}"
68
+
69
+
70
+ def load_version() -> dict:
71
+ if VERSION_FILE.exists():
72
+ with VERSION_FILE.open('r', encoding='utf-8') as f:
73
+ data = json.load(f)
74
+ # minimal validation
75
+ if 'version' not in data or 'timestamp' not in data:
76
+ raise ValueError('version.json missing required fields')
77
+ return data
78
+ # default if not present
79
+ return {
80
+ 'version': '0.1.0',
81
+ 'timestamp': int(time.time()),
82
+ }
83
+
84
+
85
+ def save_version(version: str, timestamp: int) -> None:
86
+ with VERSION_FILE.open('w', encoding='utf-8') as f:
87
+ json.dump({'version': version, 'timestamp': timestamp}, f, indent=2)
88
+ f.write('\n')
89
+
90
+
91
+ def update_sw_js(content: str, timestamp: int) -> str:
92
+ # Replace: const VERSION = 1234567890;
93
+ new_content, n = re.subn(r"(const\s+VERSION\s*=\s*)(\d+)(\s*;)",
94
+ rf"\g<1>{timestamp}\g<3>", content)
95
+ if n == 0:
96
+ print('Warning: VERSION not updated in sw.js (pattern not found)')
97
+ return new_content
98
+
99
+
100
+ def update_html(content: str, version: str, timestamp: int, is_index: bool) -> str:
101
+ updated = content
102
+
103
+ # Update inline currentVersion = '<version>'
104
+ updated, n_ver = re.subn(r"(currentVersion\s*=\s*')[^']*(')", rf"\g<1>{version}\g<2>", updated)
105
+ if n_ver == 0:
106
+ print('Warning: currentVersion not updated (pattern not found)')
107
+
108
+ # Update inline timestamp = '<timestamp>'
109
+ updated, n_ts = re.subn(r"(timestamp\s*=\s*')[^']*(')", rf"\g<1>{timestamp}\g<2>", updated)
110
+ if n_ts == 0:
111
+ print('Warning: timestamp not updated (pattern not found)')
112
+
113
+ # Update script tag query params
114
+ # For index.html: tree-track-app.js?v=X&t=Y
115
+ # For map.html: /static/map.js?v=X&t=Y (we use same version for simplicity)
116
+ if is_index:
117
+ updated, n_tag = re.subn(r"(tree-track-app\.js\?v=)[^&']+(\&t=)[^'\"]+",
118
+ rf"\g<1>{version}\g<2>{timestamp}", updated)
119
+ if n_tag == 0:
120
+ print('Warning: tree-track-app.js cache params not updated (pattern not found)')
121
+ else:
122
+ updated, n_tag = re.subn(r"(/static/map\.js\?v=)[^&']+(\&t=)[^'\"]+",
123
+ rf"\g<1>{version}\g<2>{timestamp}", updated)
124
+ if n_tag == 0:
125
+ print('Warning: map.js cache params not updated (pattern not found)')
126
+
127
+ return updated
128
+
129
+
130
+ def main():
131
+ parser = argparse.ArgumentParser(description='Bump cache-busting version/timestamp across files')
132
+ group = parser.add_mutually_exclusive_group()
133
+ group.add_argument('--bump', choices=['major', 'minor', 'patch'], help='Semver bump type')
134
+ group.add_argument('--set-version', help='Set explicit version (x.y.z)')
135
+ parser.add_argument('--timestamp', type=int, help='Set explicit timestamp (epoch seconds)')
136
+ parser.add_argument('--now', action='store_true', help='Use current time as timestamp')
137
+ args = parser.parse_args()
138
+
139
+ state = load_version()
140
+ version = state['version']
141
+ timestamp = state['timestamp']
142
+
143
+ # Determine new version
144
+ if args.set_version:
145
+ if not SEMVER_RE.match(args.set_version):
146
+ print('Error: --set-version must be in x.y.z format', file=sys.stderr)
147
+ sys.exit(2)
148
+ version = args.set_version
149
+ elif args.bump:
150
+ version = bump_semver(version, args.bump)
151
+
152
+ # Determine new timestamp
153
+ if args.timestamp is not None:
154
+ timestamp = int(args.timestamp)
155
+ elif args.now or args.set_version or args.bump:
156
+ timestamp = int(time.time())
157
+
158
+ # Save version state
159
+ save_version(version, timestamp)
160
+
161
+ # Update files
162
+ sw_path = FILES['sw']
163
+ index_path = FILES['index']
164
+ map_path = FILES['map']
165
+
166
+ sw_content = read_text(sw_path)
167
+ index_content = read_text(index_path)
168
+ map_content = read_text(map_path)
169
+
170
+ sw_new = update_sw_js(sw_content, timestamp)
171
+ index_new = update_html(index_content, version, timestamp, is_index=True)
172
+ map_new = update_html(map_content, version, timestamp, is_index=False)
173
+
174
+ if sw_new != sw_content:
175
+ write_text(sw_path, sw_new)
176
+ print(f"Updated {sw_path}")
177
+ if index_new != index_content:
178
+ write_text(index_path, index_new)
179
+ print(f"Updated {index_path}")
180
+ if map_new != map_content:
181
+ write_text(map_path, map_new)
182
+ print(f"Updated {map_path}")
183
+
184
+ print(f"Done. version={version} timestamp={timestamp}")
185
+
186
+
187
+ if __name__ == '__main__':
188
+ main()
static/index.html CHANGED
@@ -916,8 +916,8 @@
916
  <script>
917
  // Force refresh if we detect cached version
918
  (function() {
919
- const currentVersion = '5.1.0';
920
- const timestamp = '1754659000'; // Cache-busting bump
921
  const lastVersion = sessionStorage.getItem('treetrack_version');
922
  const lastTimestamp = sessionStorage.getItem('treetrack_timestamp');
923
 
@@ -1162,7 +1162,7 @@
1162
  </div>
1163
  </div>
1164
 
1165
- <script type="module" src="/static/js/tree-track-app.js?v=5.0.0"></script>
1166
 
1167
  <script>
1168
  // Initialize Granim background animation on page load
 
916
  <script>
917
  // Force refresh if we detect cached version
918
  (function() {
919
+ const currentVersion = '5.1.1';
920
+ const timestamp = '1755112750'; // Cache-busting bump
921
  const lastVersion = sessionStorage.getItem('treetrack_version');
922
  const lastTimestamp = sessionStorage.getItem('treetrack_timestamp');
923
 
 
1162
  </div>
1163
  </div>
1164
 
1165
+ <script type="module" src="/static/js/tree-track-app.js?v=5.1.1&t=1755112750"></script>
1166
 
1167
  <script>
1168
  // Initialize Granim background animation on page load
static/map.html CHANGED
@@ -812,8 +812,8 @@
812
  <script>
813
  // Force refresh if we detect cached version
814
  (function() {
815
- const currentVersion = '5.1.0';
816
- const timestamp = '1754659000'; // Current timestamp for cache busting
817
  const lastVersion = sessionStorage.getItem('treetrack_version');
818
  const lastTimestamp = sessionStorage.getItem('treetrack_timestamp');
819
 
@@ -939,7 +939,7 @@ const timestamp = '1754659000'; // Current timestamp for cache busting
939
 
940
  <!-- Leaflet JS -->
941
  <script src="https://unpkg.com/[email protected]/dist/leaflet.js"></script>
942
- <script src="/static/map.js?v=4.0.1&t=1754659000">
943
 
944
  "default-state": {
945
  gradients: [
 
812
  <script>
813
  // Force refresh if we detect cached version
814
  (function() {
815
+ const currentVersion = '5.1.1';
816
+ const timestamp = '1755112750'; // Current timestamp for cache busting
817
  const lastVersion = sessionStorage.getItem('treetrack_version');
818
  const lastTimestamp = sessionStorage.getItem('treetrack_timestamp');
819
 
 
939
 
940
  <!-- Leaflet JS -->
941
  <script src="https://unpkg.com/[email protected]/dist/leaflet.js"></script>
942
+ <script src="/static/map.js?v=5.1.1&t=1755112750">
943
 
944
  "default-state": {
945
  gradients: [
static/sw.js CHANGED
@@ -1,5 +1,5 @@
1
  // TreeTrack Service Worker - PWA and Offline Support
2
- const VERSION = 1754662800; // Cache busting bump - force clients to fetch new static assets and header image change
3
  const CACHE_NAME = `treetrack-v${VERSION}`;
4
  const STATIC_CACHE = `static-v${VERSION}`;
5
  const API_CACHE = `api-v${VERSION}`;
 
1
  // TreeTrack Service Worker - PWA and Offline Support
2
+ const VERSION = 1755112750; // Cache busting bump - force clients to fetch new static assets and header image change
3
  const CACHE_NAME = `treetrack-v${VERSION}`;
4
  const STATIC_CACHE = `static-v${VERSION}`;
5
  const API_CACHE = `api-v${VERSION}`;
version.json ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ {
2
+ "version": "5.1.1",
3
+ "timestamp": 1755112750
4
+ }