|
12 | 12 | import traceback |
13 | 13 | import uuid |
14 | 14 | import zipfile |
| 15 | +import pathlib |
15 | 16 |
|
| 17 | +import pathspec |
16 | 18 | import requests |
| 19 | + |
17 | 20 | from pydal.restapi import Policy, RestAPI |
18 | 21 | from pydal.validators import CRYPT |
19 | 22 |
|
|
43 | 46 | APP_FOLDER = os.path.dirname(__file__) |
44 | 47 | T_FOLDER = os.path.join(APP_FOLDER, "translations") |
45 | 48 | T = Translator(T_FOLDER) |
| 49 | +PY4WEB_IGNORE = ".py4web_ignore" |
46 | 50 |
|
47 | 51 | session = Session() |
48 | 52 |
|
@@ -322,31 +326,46 @@ def new_file(name, file_name): |
322 | 326 | def walk(path): |
323 | 327 | """Returns a nested folder structure as a tree""" |
324 | 328 | top = os.path.join(FOLDER, path) |
| 329 | + filter = None |
| 330 | + filter_file = os.path.join(top, PY4WEB_IGNORE) |
| 331 | + if os.path.exists(filter_file): |
| 332 | + with open(filter_file, "r") as stream: |
| 333 | + patterns = stream.readlines() |
| 334 | + try: |
| 335 | + filter = pathspec.PathSpec.from_lines("gitwildmatch", patterns) |
| 336 | + except Exception: |
| 337 | + print(traceback.format_exc()) |
| 338 | + |
| 339 | + def visible(root, name, filter=filter): |
| 340 | + if filter: |
| 341 | + return not filter.match_file(os.path.join(root, name)) |
| 342 | + return not ( |
| 343 | + name.startswith(".") |
| 344 | + or name.startswith("#") |
| 345 | + or name.endswith("~") |
| 346 | + or name[-4:] in (".pyc", "pyo") |
| 347 | + or name == "__pycache__" |
| 348 | + or root == "uploads" |
| 349 | + ) |
| 350 | + |
325 | 351 | if not os.path.exists(top) or not os.path.isdir(top): |
326 | 352 | return {"status": "error", "message": "folder does not exist"} |
327 | 353 | store = {} |
328 | 354 | for root, dirs, files in os.walk(top, topdown=False, followlinks=True): |
329 | | - store[root] = { |
330 | | - "dirs": list( |
331 | | - sorted( |
332 | | - [ |
333 | | - {"name": dir, "content": store[os.path.join(root, dir)]} |
334 | | - for dir in dirs |
335 | | - if dir[0] != "." and dir[:2] != "__" |
336 | | - ], |
337 | | - key=lambda item: item["name"], |
338 | | - ) |
339 | | - ), |
340 | | - "files": list( |
341 | | - sorted( |
342 | | - [ |
343 | | - f |
344 | | - for f in files |
345 | | - if f[0] != "." and f[-1] != "~" and f[-4:] != ".pyc" |
346 | | - ] |
347 | | - ) |
348 | | - ), |
349 | | - } |
| 355 | + if visible(*os.path.split(root)): |
| 356 | + store[root] = { |
| 357 | + "dirs": list( |
| 358 | + sorted( |
| 359 | + [ |
| 360 | + {"name": d, "content": store[os.path.join(root, d)]} |
| 361 | + for d in dirs |
| 362 | + if visible(root, d) |
| 363 | + ], |
| 364 | + key=lambda item: item["name"], |
| 365 | + ) |
| 366 | + ), |
| 367 | + "files": list(sorted([f for f in files if visible(root, f)])), |
| 368 | + } |
350 | 369 | return {"payload": store[top], "status": "success"} |
351 | 370 |
|
352 | 371 | @action("load/<path:path>") |
|
0 commit comments