mmrelay 1.0.4__tar.gz → 1.0.5__tar.gz
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.
Potentially problematic release.
This version of mmrelay might be problematic. Click here for more details.
- {mmrelay-1.0.4/src/mmrelay.egg-info → mmrelay-1.0.5}/PKG-INFO +1 -1
- {mmrelay-1.0.4 → mmrelay-1.0.5}/setup.cfg +1 -1
- {mmrelay-1.0.4 → mmrelay-1.0.5}/src/mmrelay/plugin_loader.py +260 -62
- {mmrelay-1.0.4 → mmrelay-1.0.5/src/mmrelay.egg-info}/PKG-INFO +1 -1
- {mmrelay-1.0.4 → mmrelay-1.0.5}/LICENSE +0 -0
- {mmrelay-1.0.4 → mmrelay-1.0.5}/MANIFEST.in +0 -0
- {mmrelay-1.0.4 → mmrelay-1.0.5}/README.md +0 -0
- {mmrelay-1.0.4 → mmrelay-1.0.5}/pyproject.toml +0 -0
- {mmrelay-1.0.4 → mmrelay-1.0.5}/requirements.txt +0 -0
- {mmrelay-1.0.4 → mmrelay-1.0.5}/sample_config.yaml +0 -0
- {mmrelay-1.0.4 → mmrelay-1.0.5}/src/mmrelay/__init__.py +0 -0
- {mmrelay-1.0.4 → mmrelay-1.0.5}/src/mmrelay/cli.py +0 -0
- {mmrelay-1.0.4 → mmrelay-1.0.5}/src/mmrelay/config.py +0 -0
- {mmrelay-1.0.4 → mmrelay-1.0.5}/src/mmrelay/config_checker.py +0 -0
- {mmrelay-1.0.4 → mmrelay-1.0.5}/src/mmrelay/db_utils.py +0 -0
- {mmrelay-1.0.4 → mmrelay-1.0.5}/src/mmrelay/log_utils.py +0 -0
- {mmrelay-1.0.4 → mmrelay-1.0.5}/src/mmrelay/main.py +0 -0
- {mmrelay-1.0.4 → mmrelay-1.0.5}/src/mmrelay/matrix_utils.py +0 -0
- {mmrelay-1.0.4 → mmrelay-1.0.5}/src/mmrelay/meshtastic_utils.py +0 -0
- {mmrelay-1.0.4 → mmrelay-1.0.5}/src/mmrelay/plugins/__init__.py +0 -0
- {mmrelay-1.0.4 → mmrelay-1.0.5}/src/mmrelay/plugins/base_plugin.py +0 -0
- {mmrelay-1.0.4 → mmrelay-1.0.5}/src/mmrelay/plugins/debug_plugin.py +0 -0
- {mmrelay-1.0.4 → mmrelay-1.0.5}/src/mmrelay/plugins/drop_plugin.py +0 -0
- {mmrelay-1.0.4 → mmrelay-1.0.5}/src/mmrelay/plugins/health_plugin.py +0 -0
- {mmrelay-1.0.4 → mmrelay-1.0.5}/src/mmrelay/plugins/help_plugin.py +0 -0
- {mmrelay-1.0.4 → mmrelay-1.0.5}/src/mmrelay/plugins/map_plugin.py +0 -0
- {mmrelay-1.0.4 → mmrelay-1.0.5}/src/mmrelay/plugins/mesh_relay_plugin.py +0 -0
- {mmrelay-1.0.4 → mmrelay-1.0.5}/src/mmrelay/plugins/nodes_plugin.py +0 -0
- {mmrelay-1.0.4 → mmrelay-1.0.5}/src/mmrelay/plugins/ping_plugin.py +0 -0
- {mmrelay-1.0.4 → mmrelay-1.0.5}/src/mmrelay/plugins/telemetry_plugin.py +0 -0
- {mmrelay-1.0.4 → mmrelay-1.0.5}/src/mmrelay/plugins/weather_plugin.py +0 -0
- {mmrelay-1.0.4 → mmrelay-1.0.5}/src/mmrelay/setup_utils.py +0 -0
- {mmrelay-1.0.4 → mmrelay-1.0.5}/src/mmrelay.egg-info/SOURCES.txt +0 -0
- {mmrelay-1.0.4 → mmrelay-1.0.5}/src/mmrelay.egg-info/dependency_links.txt +0 -0
- {mmrelay-1.0.4 → mmrelay-1.0.5}/src/mmrelay.egg-info/entry_points.txt +0 -0
- {mmrelay-1.0.4 → mmrelay-1.0.5}/src/mmrelay.egg-info/requires.txt +0 -0
- {mmrelay-1.0.4 → mmrelay-1.0.5}/src/mmrelay.egg-info/top_level.txt +0 -0
- {mmrelay-1.0.4 → mmrelay-1.0.5}/tools/mmrelay.service +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mmrelay
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.5
|
|
4
4
|
Summary: Bridge between Meshtastic mesh networks and Matrix chat rooms
|
|
5
5
|
Home-page: https://github.com/geoffwhittington/meshtastic-matrix-relay
|
|
6
6
|
Author: Geoff Whittington, Jeremiah K., and contributors
|
|
@@ -56,16 +56,23 @@ def get_community_plugin_dirs():
|
|
|
56
56
|
return dirs
|
|
57
57
|
|
|
58
58
|
|
|
59
|
-
def clone_or_update_repo(repo_url,
|
|
59
|
+
def clone_or_update_repo(repo_url, ref, plugins_dir):
|
|
60
60
|
# Extract the repository name from the URL
|
|
61
61
|
repo_name = os.path.splitext(os.path.basename(repo_url.rstrip("/")))[0]
|
|
62
62
|
repo_path = os.path.join(plugins_dir, repo_name)
|
|
63
63
|
|
|
64
|
-
# Default branch names to try if
|
|
64
|
+
# Default branch names to try if ref is not specified
|
|
65
65
|
default_branches = ["main", "master"]
|
|
66
66
|
|
|
67
|
-
#
|
|
68
|
-
|
|
67
|
+
# Get the ref type and value
|
|
68
|
+
ref_type = ref["type"] # "tag" or "branch"
|
|
69
|
+
ref_value = ref["value"]
|
|
70
|
+
|
|
71
|
+
# Log what we're trying to do
|
|
72
|
+
logger.info(f"Using {ref_type} '{ref_value}' for repository {repo_name}")
|
|
73
|
+
|
|
74
|
+
# If it's a branch and one of the default branches, we'll handle it specially
|
|
75
|
+
is_default_branch = ref_type == "branch" and ref_value in default_branches
|
|
69
76
|
|
|
70
77
|
if os.path.isdir(repo_path):
|
|
71
78
|
try:
|
|
@@ -85,32 +92,39 @@ def clone_or_update_repo(repo_url, tag, plugins_dir):
|
|
|
85
92
|
universal_newlines=True,
|
|
86
93
|
).strip()
|
|
87
94
|
|
|
88
|
-
if current_branch ==
|
|
95
|
+
if current_branch == ref_value:
|
|
89
96
|
# We're on the right branch, just pull
|
|
90
97
|
try:
|
|
91
98
|
subprocess.check_call(
|
|
92
|
-
["git", "-C", repo_path, "pull", "origin",
|
|
99
|
+
["git", "-C", repo_path, "pull", "origin", ref_value]
|
|
100
|
+
)
|
|
101
|
+
logger.info(
|
|
102
|
+
f"Updated repository {repo_name} branch {ref_value}"
|
|
93
103
|
)
|
|
94
|
-
logger.info(f"Updated repository {repo_name} branch {tag}")
|
|
95
104
|
return True
|
|
96
105
|
except subprocess.CalledProcessError as e:
|
|
97
|
-
logger.warning(f"Error pulling branch {
|
|
106
|
+
logger.warning(f"Error pulling branch {ref_value}: {e}")
|
|
98
107
|
# Continue anyway, we'll use what we have
|
|
99
108
|
return True
|
|
100
109
|
else:
|
|
101
110
|
# Switch to the right branch
|
|
102
|
-
subprocess.check_call(["git", "-C", repo_path, "checkout", tag])
|
|
103
111
|
subprocess.check_call(
|
|
104
|
-
["git", "-C", repo_path, "
|
|
112
|
+
["git", "-C", repo_path, "checkout", ref_value]
|
|
113
|
+
)
|
|
114
|
+
subprocess.check_call(
|
|
115
|
+
["git", "-C", repo_path, "pull", "origin", ref_value]
|
|
105
116
|
)
|
|
106
|
-
|
|
117
|
+
if ref_type == "branch":
|
|
118
|
+
logger.info(f"Switched to and updated branch {ref_value}")
|
|
119
|
+
else:
|
|
120
|
+
logger.info(f"Switched to and updated tag {ref_value}")
|
|
107
121
|
return True
|
|
108
122
|
except subprocess.CalledProcessError:
|
|
109
123
|
# If we can't checkout the specified branch, try the other default branch
|
|
110
|
-
other_default = "main" if
|
|
124
|
+
other_default = "main" if ref_value == "master" else "master"
|
|
111
125
|
try:
|
|
112
126
|
logger.warning(
|
|
113
|
-
f"Branch {
|
|
127
|
+
f"Branch {ref_value} not found, trying {other_default}"
|
|
114
128
|
)
|
|
115
129
|
subprocess.check_call(
|
|
116
130
|
["git", "-C", repo_path, "checkout", other_default]
|
|
@@ -118,7 +132,9 @@ def clone_or_update_repo(repo_url, tag, plugins_dir):
|
|
|
118
132
|
subprocess.check_call(
|
|
119
133
|
["git", "-C", repo_path, "pull", "origin", other_default]
|
|
120
134
|
)
|
|
121
|
-
logger.info(
|
|
135
|
+
logger.info(
|
|
136
|
+
f"Using {other_default} branch instead of {ref_value}"
|
|
137
|
+
)
|
|
122
138
|
return True
|
|
123
139
|
except subprocess.CalledProcessError:
|
|
124
140
|
# If that fails too, just use whatever branch we're on
|
|
@@ -140,7 +156,7 @@ def clone_or_update_repo(repo_url, tag, plugins_dir):
|
|
|
140
156
|
tag_commit = None
|
|
141
157
|
try:
|
|
142
158
|
tag_commit = subprocess.check_output(
|
|
143
|
-
["git", "-C", repo_path, "rev-parse",
|
|
159
|
+
["git", "-C", repo_path, "rev-parse", ref_value],
|
|
144
160
|
universal_newlines=True,
|
|
145
161
|
).strip()
|
|
146
162
|
except subprocess.CalledProcessError:
|
|
@@ -149,24 +165,35 @@ def clone_or_update_repo(repo_url, tag, plugins_dir):
|
|
|
149
165
|
|
|
150
166
|
# If we're already at the tag's commit, we're done
|
|
151
167
|
if tag_commit and current_commit == tag_commit:
|
|
152
|
-
logger.info(
|
|
168
|
+
logger.info(
|
|
169
|
+
f"Repository {repo_name} is already at tag {ref_value}"
|
|
170
|
+
)
|
|
153
171
|
return True
|
|
154
172
|
|
|
155
173
|
# Otherwise, try to checkout the tag
|
|
156
|
-
subprocess.check_call(
|
|
157
|
-
|
|
174
|
+
subprocess.check_call(
|
|
175
|
+
["git", "-C", repo_path, "checkout", ref_value]
|
|
176
|
+
)
|
|
177
|
+
if ref_type == "branch":
|
|
178
|
+
logger.info(
|
|
179
|
+
f"Updated repository {repo_name} to branch {ref_value}"
|
|
180
|
+
)
|
|
181
|
+
else:
|
|
182
|
+
logger.info(
|
|
183
|
+
f"Updated repository {repo_name} to tag {ref_value}"
|
|
184
|
+
)
|
|
158
185
|
return True
|
|
159
186
|
except subprocess.CalledProcessError:
|
|
160
187
|
# If tag checkout fails, try to fetch it specifically
|
|
161
188
|
logger.warning(
|
|
162
|
-
f"Tag {
|
|
189
|
+
f"Tag {ref_value} not found locally, trying to fetch it specifically"
|
|
163
190
|
)
|
|
164
191
|
try:
|
|
165
192
|
# Try to fetch the specific tag, but first remove any existing tag with the same name
|
|
166
193
|
try:
|
|
167
194
|
# Delete the local tag if it exists to avoid conflicts
|
|
168
195
|
subprocess.check_call(
|
|
169
|
-
["git", "-C", repo_path, "tag", "-d",
|
|
196
|
+
["git", "-C", repo_path, "tag", "-d", ref_value]
|
|
170
197
|
)
|
|
171
198
|
except subprocess.CalledProcessError:
|
|
172
199
|
# Tag doesn't exist locally, which is fine
|
|
@@ -182,7 +209,7 @@ def clone_or_update_repo(repo_url, tag, plugins_dir):
|
|
|
182
209
|
repo_path,
|
|
183
210
|
"fetch",
|
|
184
211
|
"origin",
|
|
185
|
-
f"refs/tags/{
|
|
212
|
+
f"refs/tags/{ref_value}",
|
|
186
213
|
]
|
|
187
214
|
)
|
|
188
215
|
except subprocess.CalledProcessError:
|
|
@@ -194,34 +221,45 @@ def clone_or_update_repo(repo_url, tag, plugins_dir):
|
|
|
194
221
|
repo_path,
|
|
195
222
|
"fetch",
|
|
196
223
|
"origin",
|
|
197
|
-
f"refs/tags/{
|
|
224
|
+
f"refs/tags/{ref_value}:refs/tags/{ref_value}",
|
|
198
225
|
]
|
|
199
226
|
)
|
|
200
227
|
|
|
201
|
-
subprocess.check_call(
|
|
202
|
-
|
|
228
|
+
subprocess.check_call(
|
|
229
|
+
["git", "-C", repo_path, "checkout", ref_value]
|
|
230
|
+
)
|
|
231
|
+
if ref_type == "branch":
|
|
232
|
+
logger.info(
|
|
233
|
+
f"Successfully fetched and checked out branch {ref_value}"
|
|
234
|
+
)
|
|
235
|
+
else:
|
|
236
|
+
logger.info(
|
|
237
|
+
f"Successfully fetched and checked out tag {ref_value}"
|
|
238
|
+
)
|
|
203
239
|
return True
|
|
204
240
|
except subprocess.CalledProcessError:
|
|
205
241
|
# If that fails too, try as a branch
|
|
206
|
-
logger.warning(
|
|
242
|
+
logger.warning(
|
|
243
|
+
f"Could not fetch tag {ref_value}, trying as a branch"
|
|
244
|
+
)
|
|
207
245
|
try:
|
|
208
246
|
subprocess.check_call(
|
|
209
|
-
["git", "-C", repo_path, "fetch", "origin",
|
|
247
|
+
["git", "-C", repo_path, "fetch", "origin", ref_value]
|
|
210
248
|
)
|
|
211
249
|
subprocess.check_call(
|
|
212
|
-
["git", "-C", repo_path, "checkout",
|
|
250
|
+
["git", "-C", repo_path, "checkout", ref_value]
|
|
213
251
|
)
|
|
214
252
|
subprocess.check_call(
|
|
215
|
-
["git", "-C", repo_path, "pull", "origin",
|
|
253
|
+
["git", "-C", repo_path, "pull", "origin", ref_value]
|
|
216
254
|
)
|
|
217
255
|
logger.info(
|
|
218
|
-
f"Updated repository {repo_name} to branch {
|
|
256
|
+
f"Updated repository {repo_name} to branch {ref_value}"
|
|
219
257
|
)
|
|
220
258
|
return True
|
|
221
259
|
except subprocess.CalledProcessError:
|
|
222
260
|
# If all else fails, just use a default branch
|
|
223
261
|
logger.warning(
|
|
224
|
-
f"Could not checkout {
|
|
262
|
+
f"Could not checkout {ref_value} as tag or branch, trying default branches"
|
|
225
263
|
)
|
|
226
264
|
for default_branch in default_branches:
|
|
227
265
|
try:
|
|
@@ -245,7 +283,7 @@ def clone_or_update_repo(repo_url, tag, plugins_dir):
|
|
|
245
283
|
]
|
|
246
284
|
)
|
|
247
285
|
logger.info(
|
|
248
|
-
f"Using {default_branch} instead of {
|
|
286
|
+
f"Using {default_branch} instead of {ref_value}"
|
|
249
287
|
)
|
|
250
288
|
return True
|
|
251
289
|
except subprocess.CalledProcessError:
|
|
@@ -272,18 +310,24 @@ def clone_or_update_repo(repo_url, tag, plugins_dir):
|
|
|
272
310
|
try:
|
|
273
311
|
# Try to clone with the specified branch
|
|
274
312
|
subprocess.check_call(
|
|
275
|
-
["git", "clone", "--branch",
|
|
276
|
-
|
|
277
|
-
logger.info(
|
|
278
|
-
f"Cloned repository {repo_name} from {repo_url} at branch {tag}"
|
|
313
|
+
["git", "clone", "--branch", ref_value, repo_url],
|
|
314
|
+
cwd=plugins_dir,
|
|
279
315
|
)
|
|
316
|
+
if ref_type == "branch":
|
|
317
|
+
logger.info(
|
|
318
|
+
f"Cloned repository {repo_name} from {repo_url} at branch {ref_value}"
|
|
319
|
+
)
|
|
320
|
+
else:
|
|
321
|
+
logger.info(
|
|
322
|
+
f"Cloned repository {repo_name} from {repo_url} at tag {ref_value}"
|
|
323
|
+
)
|
|
280
324
|
return True
|
|
281
325
|
except subprocess.CalledProcessError:
|
|
282
326
|
# If that fails, try the other default branch
|
|
283
|
-
other_default = "main" if
|
|
327
|
+
other_default = "main" if ref_value == "master" else "master"
|
|
284
328
|
try:
|
|
285
329
|
logger.warning(
|
|
286
|
-
f"Could not clone with branch {
|
|
330
|
+
f"Could not clone with branch {ref_value}, trying {other_default}"
|
|
287
331
|
)
|
|
288
332
|
subprocess.check_call(
|
|
289
333
|
["git", "clone", "--branch", other_default, repo_url],
|
|
@@ -310,16 +354,22 @@ def clone_or_update_repo(repo_url, tag, plugins_dir):
|
|
|
310
354
|
try:
|
|
311
355
|
# Try to clone with the specified tag
|
|
312
356
|
subprocess.check_call(
|
|
313
|
-
["git", "clone", "--branch",
|
|
314
|
-
|
|
315
|
-
logger.info(
|
|
316
|
-
f"Cloned repository {repo_name} from {repo_url} at tag {tag}"
|
|
357
|
+
["git", "clone", "--branch", ref_value, repo_url],
|
|
358
|
+
cwd=plugins_dir,
|
|
317
359
|
)
|
|
360
|
+
if ref_type == "branch":
|
|
361
|
+
logger.info(
|
|
362
|
+
f"Cloned repository {repo_name} from {repo_url} at branch {ref_value}"
|
|
363
|
+
)
|
|
364
|
+
else:
|
|
365
|
+
logger.info(
|
|
366
|
+
f"Cloned repository {repo_name} from {repo_url} at tag {ref_value}"
|
|
367
|
+
)
|
|
318
368
|
return True
|
|
319
369
|
except subprocess.CalledProcessError:
|
|
320
370
|
# If that fails, clone without specifying a tag
|
|
321
371
|
logger.warning(
|
|
322
|
-
f"Could not clone with tag {
|
|
372
|
+
f"Could not clone with tag {ref_value}, cloning default branch"
|
|
323
373
|
)
|
|
324
374
|
subprocess.check_call(["git", "clone", repo_url], cwd=plugins_dir)
|
|
325
375
|
|
|
@@ -334,7 +384,7 @@ def clone_or_update_repo(repo_url, tag, plugins_dir):
|
|
|
334
384
|
repo_path,
|
|
335
385
|
"fetch",
|
|
336
386
|
"origin",
|
|
337
|
-
f"refs/tags/{
|
|
387
|
+
f"refs/tags/{ref_value}",
|
|
338
388
|
]
|
|
339
389
|
)
|
|
340
390
|
except subprocess.CalledProcessError:
|
|
@@ -346,35 +396,42 @@ def clone_or_update_repo(repo_url, tag, plugins_dir):
|
|
|
346
396
|
repo_path,
|
|
347
397
|
"fetch",
|
|
348
398
|
"origin",
|
|
349
|
-
f"refs/tags/{
|
|
399
|
+
f"refs/tags/{ref_value}:refs/tags/{ref_value}",
|
|
350
400
|
]
|
|
351
401
|
)
|
|
352
402
|
|
|
353
403
|
# Now checkout the tag
|
|
354
|
-
subprocess.check_call(
|
|
355
|
-
|
|
356
|
-
f"Cloned repository {repo_name} and checked out tag {tag}"
|
|
404
|
+
subprocess.check_call(
|
|
405
|
+
["git", "-C", repo_path, "checkout", ref_value]
|
|
357
406
|
)
|
|
407
|
+
if ref_type == "branch":
|
|
408
|
+
logger.info(
|
|
409
|
+
f"Cloned repository {repo_name} and checked out branch {ref_value}"
|
|
410
|
+
)
|
|
411
|
+
else:
|
|
412
|
+
logger.info(
|
|
413
|
+
f"Cloned repository {repo_name} and checked out tag {ref_value}"
|
|
414
|
+
)
|
|
358
415
|
return True
|
|
359
416
|
except subprocess.CalledProcessError:
|
|
360
417
|
# If that fails, try as a branch
|
|
361
418
|
try:
|
|
362
419
|
logger.warning(
|
|
363
|
-
f"Could not checkout {
|
|
420
|
+
f"Could not checkout {ref_value} as a tag, trying as a branch"
|
|
364
421
|
)
|
|
365
422
|
subprocess.check_call(
|
|
366
|
-
["git", "-C", repo_path, "fetch", "origin",
|
|
423
|
+
["git", "-C", repo_path, "fetch", "origin", ref_value]
|
|
367
424
|
)
|
|
368
425
|
subprocess.check_call(
|
|
369
|
-
["git", "-C", repo_path, "checkout",
|
|
426
|
+
["git", "-C", repo_path, "checkout", ref_value]
|
|
370
427
|
)
|
|
371
428
|
logger.info(
|
|
372
|
-
f"Cloned repository {repo_name} and checked out branch {
|
|
429
|
+
f"Cloned repository {repo_name} and checked out branch {ref_value}"
|
|
373
430
|
)
|
|
374
431
|
return True
|
|
375
432
|
except subprocess.CalledProcessError:
|
|
376
433
|
logger.warning(
|
|
377
|
-
f"Could not checkout {
|
|
434
|
+
f"Could not checkout {ref_value}, using default branch"
|
|
378
435
|
)
|
|
379
436
|
logger.info(
|
|
380
437
|
f"Cloned repository {repo_name} from {repo_url} (default branch)"
|
|
@@ -390,17 +447,53 @@ def clone_or_update_repo(repo_url, tag, plugins_dir):
|
|
|
390
447
|
requirements_path = os.path.join(repo_path, "requirements.txt")
|
|
391
448
|
if os.path.isfile(requirements_path):
|
|
392
449
|
try:
|
|
393
|
-
#
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
450
|
+
# Check if we're running in a pipx environment
|
|
451
|
+
in_pipx = "PIPX_HOME" in os.environ or "PIPX_LOCAL_VENVS" in os.environ
|
|
452
|
+
|
|
453
|
+
# Read requirements from file
|
|
454
|
+
with open(requirements_path, "r") as f:
|
|
455
|
+
requirements = [
|
|
456
|
+
line.strip()
|
|
457
|
+
for line in f
|
|
458
|
+
if line.strip() and not line.startswith("#")
|
|
459
|
+
]
|
|
460
|
+
|
|
461
|
+
if requirements:
|
|
462
|
+
if in_pipx:
|
|
463
|
+
# Use pipx inject for each requirement
|
|
464
|
+
logger.info(
|
|
465
|
+
f"Installing requirements for plugin {repo_name} with pipx inject"
|
|
466
|
+
)
|
|
467
|
+
for req in requirements:
|
|
468
|
+
logger.info(f"Installing {req}")
|
|
469
|
+
subprocess.check_call(["pipx", "inject", "mmrelay", req])
|
|
470
|
+
else:
|
|
471
|
+
# Use pip to install the requirements.txt
|
|
472
|
+
logger.info(
|
|
473
|
+
f"Installing requirements for plugin {repo_name} with pip"
|
|
474
|
+
)
|
|
475
|
+
subprocess.check_call(
|
|
476
|
+
[
|
|
477
|
+
sys.executable,
|
|
478
|
+
"-m",
|
|
479
|
+
"pip",
|
|
480
|
+
"install",
|
|
481
|
+
"-r",
|
|
482
|
+
requirements_path,
|
|
483
|
+
]
|
|
484
|
+
)
|
|
485
|
+
logger.info(
|
|
486
|
+
f"Successfully installed requirements for plugin {repo_name}"
|
|
487
|
+
)
|
|
398
488
|
except subprocess.CalledProcessError as e:
|
|
399
489
|
logger.error(f"Error installing requirements for plugin {repo_name}: {e}")
|
|
400
490
|
logger.error(
|
|
401
491
|
f"Please manually install the requirements from {requirements_path}"
|
|
402
492
|
)
|
|
403
|
-
|
|
493
|
+
# Don't exit, just continue with a warning
|
|
494
|
+
logger.warning(
|
|
495
|
+
f"Plugin {repo_name} may not work correctly without its dependencies"
|
|
496
|
+
)
|
|
404
497
|
|
|
405
498
|
|
|
406
499
|
def load_plugins_from_directory(directory, recursive=False):
|
|
@@ -418,14 +511,101 @@ def load_plugins_from_directory(directory, recursive=False):
|
|
|
418
511
|
module_name, plugin_path
|
|
419
512
|
)
|
|
420
513
|
plugin_module = importlib.util.module_from_spec(spec)
|
|
514
|
+
|
|
515
|
+
# Create a compatibility layer for plugins
|
|
516
|
+
# This allows plugins to import from 'plugins' or 'mmrelay.plugins'
|
|
517
|
+
if "mmrelay.plugins" not in sys.modules:
|
|
518
|
+
import mmrelay.plugins
|
|
519
|
+
|
|
520
|
+
sys.modules["mmrelay.plugins"] = mmrelay.plugins
|
|
521
|
+
|
|
522
|
+
# For backward compatibility with older plugins
|
|
523
|
+
if "plugins" not in sys.modules:
|
|
524
|
+
import mmrelay.plugins
|
|
525
|
+
|
|
526
|
+
sys.modules["plugins"] = mmrelay.plugins
|
|
527
|
+
|
|
421
528
|
try:
|
|
529
|
+
# Add the plugin's directory to sys.path temporarily
|
|
530
|
+
plugin_dir = os.path.dirname(plugin_path)
|
|
531
|
+
sys.path.insert(0, plugin_dir)
|
|
532
|
+
|
|
533
|
+
# Execute the module
|
|
422
534
|
spec.loader.exec_module(plugin_module)
|
|
535
|
+
|
|
536
|
+
# Remove the plugin directory from sys.path
|
|
537
|
+
if plugin_dir in sys.path:
|
|
538
|
+
sys.path.remove(plugin_dir)
|
|
539
|
+
|
|
423
540
|
if hasattr(plugin_module, "Plugin"):
|
|
424
541
|
plugins.append(plugin_module.Plugin())
|
|
425
542
|
else:
|
|
426
543
|
logger.warning(
|
|
427
544
|
f"{plugin_path} does not define a Plugin class."
|
|
428
545
|
)
|
|
546
|
+
except ModuleNotFoundError as e:
|
|
547
|
+
missing_module = str(e).split()[-1].strip("'")
|
|
548
|
+
logger.warning(
|
|
549
|
+
f"Missing dependency for plugin {plugin_path}: {missing_module}"
|
|
550
|
+
)
|
|
551
|
+
|
|
552
|
+
# Try to automatically install the missing dependency
|
|
553
|
+
try:
|
|
554
|
+
# Check if we're running in a pipx environment
|
|
555
|
+
in_pipx = (
|
|
556
|
+
"PIPX_HOME" in os.environ
|
|
557
|
+
or "PIPX_LOCAL_VENVS" in os.environ
|
|
558
|
+
)
|
|
559
|
+
|
|
560
|
+
if in_pipx:
|
|
561
|
+
logger.info(
|
|
562
|
+
f"Attempting to install missing dependency with pipx inject: {missing_module}"
|
|
563
|
+
)
|
|
564
|
+
subprocess.check_call(
|
|
565
|
+
["pipx", "inject", "mmrelay", missing_module]
|
|
566
|
+
)
|
|
567
|
+
else:
|
|
568
|
+
logger.info(
|
|
569
|
+
f"Attempting to install missing dependency with pip: {missing_module}"
|
|
570
|
+
)
|
|
571
|
+
subprocess.check_call(
|
|
572
|
+
[
|
|
573
|
+
sys.executable,
|
|
574
|
+
"-m",
|
|
575
|
+
"pip",
|
|
576
|
+
"install",
|
|
577
|
+
missing_module,
|
|
578
|
+
]
|
|
579
|
+
)
|
|
580
|
+
|
|
581
|
+
logger.info(
|
|
582
|
+
f"Successfully installed {missing_module}, retrying plugin load"
|
|
583
|
+
)
|
|
584
|
+
|
|
585
|
+
# Try to load the module again
|
|
586
|
+
spec.loader.exec_module(plugin_module)
|
|
587
|
+
|
|
588
|
+
if hasattr(plugin_module, "Plugin"):
|
|
589
|
+
plugins.append(plugin_module.Plugin())
|
|
590
|
+
else:
|
|
591
|
+
logger.warning(
|
|
592
|
+
f"{plugin_path} does not define a Plugin class."
|
|
593
|
+
)
|
|
594
|
+
|
|
595
|
+
except subprocess.CalledProcessError:
|
|
596
|
+
logger.error(
|
|
597
|
+
f"Failed to automatically install {missing_module}"
|
|
598
|
+
)
|
|
599
|
+
logger.error("Please install it manually:")
|
|
600
|
+
logger.error(
|
|
601
|
+
f"pipx inject mmrelay {missing_module} # if using pipx"
|
|
602
|
+
)
|
|
603
|
+
logger.error(
|
|
604
|
+
f"pip install {missing_module} # if using pip"
|
|
605
|
+
)
|
|
606
|
+
logger.error(
|
|
607
|
+
f"Plugin directory: {os.path.dirname(plugin_path)}"
|
|
608
|
+
)
|
|
429
609
|
except Exception as e:
|
|
430
610
|
logger.error(f"Error loading plugin {plugin_path}: {e}")
|
|
431
611
|
if not recursive:
|
|
@@ -524,7 +704,7 @@ def load_plugins(passed_config=None):
|
|
|
524
704
|
|
|
525
705
|
# Get the first directory for cloning (prefer user directory)
|
|
526
706
|
community_plugins_dir = community_plugin_dirs[
|
|
527
|
-
|
|
707
|
+
0
|
|
528
708
|
] # Use the user directory for new clones
|
|
529
709
|
|
|
530
710
|
# Create community plugins directory if needed
|
|
@@ -553,10 +733,28 @@ def load_plugins(passed_config=None):
|
|
|
553
733
|
continue
|
|
554
734
|
|
|
555
735
|
repo_url = plugin_info.get("repository")
|
|
556
|
-
|
|
736
|
+
|
|
737
|
+
# Support both tag and branch parameters
|
|
738
|
+
tag = plugin_info.get("tag")
|
|
739
|
+
branch = plugin_info.get("branch")
|
|
740
|
+
|
|
741
|
+
# Determine what to use (tag, branch, or default)
|
|
742
|
+
if tag and branch:
|
|
743
|
+
logger.warning(
|
|
744
|
+
f"Both tag and branch specified for plugin {plugin_name}, using tag"
|
|
745
|
+
)
|
|
746
|
+
ref = {"type": "tag", "value": tag}
|
|
747
|
+
elif tag:
|
|
748
|
+
ref = {"type": "tag", "value": tag}
|
|
749
|
+
elif branch:
|
|
750
|
+
ref = {"type": "branch", "value": branch}
|
|
751
|
+
else:
|
|
752
|
+
# Default to main branch if neither is specified
|
|
753
|
+
ref = {"type": "branch", "value": "main"}
|
|
754
|
+
|
|
557
755
|
if repo_url:
|
|
558
756
|
# Clone to the user directory by default
|
|
559
|
-
success = clone_or_update_repo(repo_url,
|
|
757
|
+
success = clone_or_update_repo(repo_url, ref, community_plugins_dir)
|
|
560
758
|
if not success:
|
|
561
759
|
logger.warning(
|
|
562
760
|
f"Failed to clone/update plugin {plugin_name}, skipping"
|
|
@@ -580,7 +778,7 @@ def load_plugins(passed_config=None):
|
|
|
580
778
|
for dir_path in community_plugin_dirs:
|
|
581
779
|
plugin_path = os.path.join(dir_path, repo_name)
|
|
582
780
|
if os.path.exists(plugin_path):
|
|
583
|
-
logger.
|
|
781
|
+
logger.info(f"Loading community plugin from: {plugin_path}")
|
|
584
782
|
plugins.extend(
|
|
585
783
|
load_plugins_from_directory(plugin_path, recursive=True)
|
|
586
784
|
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mmrelay
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.5
|
|
4
4
|
Summary: Bridge between Meshtastic mesh networks and Matrix chat rooms
|
|
5
5
|
Home-page: https://github.com/geoffwhittington/meshtastic-matrix-relay
|
|
6
6
|
Author: Geoff Whittington, Jeremiah K., and contributors
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|