2022-10-03 05:52:50 +00:00
|
|
|
#!/usr/bin/python3
|
|
|
|
|
|
|
|
|
|
|
|
# Python imports
|
2022-11-29 04:34:13 +00:00
|
|
|
import os
|
|
|
|
import traceback
|
|
|
|
import argparse
|
2022-11-30 04:34:25 +00:00
|
|
|
import subprocess
|
2022-11-29 04:34:13 +00:00
|
|
|
import json
|
|
|
|
import base64
|
|
|
|
import time
|
2022-11-30 04:34:25 +00:00
|
|
|
from datetime import datetime
|
2022-10-03 05:52:50 +00:00
|
|
|
from setproctitle import setproctitle
|
2022-10-04 01:50:38 +00:00
|
|
|
from multiprocessing.connection import Client
|
2022-10-03 05:52:50 +00:00
|
|
|
|
|
|
|
# Lib imports
|
|
|
|
|
|
|
|
# Application imports
|
|
|
|
|
|
|
|
|
|
|
|
|
2022-10-04 01:50:38 +00:00
|
|
|
|
|
|
|
_ipc_address = f'/tmp/solarfm-search_grep-ipc.sock'
|
|
|
|
_ipc_authkey = b'' + bytes(f'solarfm-search_grep-ipc', 'utf-8')
|
2022-10-03 05:52:50 +00:00
|
|
|
|
2022-10-21 03:23:14 +00:00
|
|
|
filter = (".cpp", ".css", ".c", ".go", ".html", ".htm", ".java", ".js", ".json", ".lua", ".md", ".py", ".rs", ".toml", ".xml", ".pom") + \
|
|
|
|
(".txt", ".text", ".sh", ".cfg", ".conf", ".log")
|
|
|
|
|
2022-11-30 04:34:25 +00:00
|
|
|
# NOTE: Create timestamp of when this launched. Is used in IPC to see if
|
|
|
|
# we are stale and that new call didn't fully kill this or older processes.
|
|
|
|
dt = datetime.now()
|
|
|
|
ts = datetime.timestamp(dt)
|
2022-10-03 05:52:50 +00:00
|
|
|
|
|
|
|
|
2023-09-16 06:18:36 +00:00
|
|
|
def _log(message: str = "No message passed in...") -> None:
|
|
|
|
print(message)
|
|
|
|
|
|
|
|
|
2022-10-04 01:50:38 +00:00
|
|
|
def send_ipc_message(message) -> None:
|
2023-09-16 06:18:36 +00:00
|
|
|
conn = Client(address = _ipc_address, family = "AF_UNIX", authkey = _ipc_authkey)
|
2022-10-10 01:59:44 +00:00
|
|
|
conn.send(message)
|
|
|
|
conn.close()
|
2022-10-05 03:58:27 +00:00
|
|
|
|
2022-10-07 01:48:44 +00:00
|
|
|
# NOTE: Kinda important as this prevents overloading the UI thread
|
2022-10-10 01:59:44 +00:00
|
|
|
time.sleep(0.05)
|
2022-10-04 01:50:38 +00:00
|
|
|
|
|
|
|
|
2023-09-16 06:18:36 +00:00
|
|
|
def file_search(path: str = None, query: str = None) -> None:
|
|
|
|
if not path or not query: return
|
|
|
|
|
2022-10-03 05:52:50 +00:00
|
|
|
try:
|
2023-09-16 06:18:36 +00:00
|
|
|
for _path, _dir, _files in os.walk(path, topdown = True, onerror = _log, followlinks = True):
|
2022-10-07 01:48:44 +00:00
|
|
|
for file in _files:
|
|
|
|
if query in file.lower():
|
|
|
|
target = os.path.join(_path, file)
|
2022-11-30 04:34:25 +00:00
|
|
|
data = f"SEARCH|{ts}|{json.dumps([target, file])}"
|
2022-10-07 01:48:44 +00:00
|
|
|
send_ipc_message(data)
|
2022-10-03 05:52:50 +00:00
|
|
|
except Exception as e:
|
|
|
|
print("Couldn't traverse to path. Might be permissions related...")
|
|
|
|
traceback.print_exc()
|
|
|
|
|
2022-10-04 07:30:46 +00:00
|
|
|
|
2023-09-16 06:18:36 +00:00
|
|
|
def grep_search(target: str = None, query: str = None):
|
|
|
|
if not target or not query: return
|
2022-11-30 04:34:25 +00:00
|
|
|
|
|
|
|
# NOTE: -n = provide line numbers, -R = Search recursive in given target
|
|
|
|
# -i = insensitive, -F = don't do regex parsing. (Treat as raw string)
|
|
|
|
command = ["grep", "-n", "-R", "-i", "-F", query, target]
|
2023-09-16 06:18:36 +00:00
|
|
|
proc = subprocess.Popen(command, stdout = subprocess.PIPE, encoding = "utf-8")
|
2022-11-30 04:34:25 +00:00
|
|
|
raw_data = proc.communicate()[0].strip()
|
|
|
|
proc_data = raw_data.split("\n") # NOTE: Will return data AFTER completion (if any)
|
|
|
|
collection = {}
|
|
|
|
|
|
|
|
for line in proc_data:
|
2023-02-21 20:23:39 +00:00
|
|
|
try:
|
|
|
|
parts = line.split(":", 2)
|
|
|
|
if not len(parts) == 3:
|
|
|
|
continue
|
|
|
|
|
|
|
|
file, line_no, data = parts
|
|
|
|
b64_file = base64.urlsafe_b64encode(file.encode('utf-8')).decode('utf-8')
|
|
|
|
b64_data = base64.urlsafe_b64encode(data.encode('utf-8')).decode('utf-8')
|
|
|
|
|
|
|
|
if b64_file in collection.keys():
|
|
|
|
collection[f"{b64_file}"][f"{line_no}"] = b64_data
|
|
|
|
else:
|
|
|
|
collection[f"{b64_file}"] = {}
|
|
|
|
collection[f"{b64_file}"] = { f"{line_no}": b64_data}
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
traceback.print_exc()
|
2022-11-30 04:34:25 +00:00
|
|
|
|
2023-09-16 06:18:36 +00:00
|
|
|
proc.terminate()
|
2023-03-05 03:45:29 +00:00
|
|
|
data = f"GREP|{ts}|{json.dumps(collection, separators=(',', ':'), indent=4)}"
|
|
|
|
send_ipc_message(data)
|
2022-11-30 04:34:25 +00:00
|
|
|
collection = {}
|
|
|
|
|
2022-10-03 05:52:50 +00:00
|
|
|
|
|
|
|
def search(args):
|
2023-09-16 06:18:36 +00:00
|
|
|
path = args.dir
|
|
|
|
if (path[0] == "'" and path[-1] == "'") or \
|
|
|
|
path[0] == '"' and path[-1] == '"':
|
|
|
|
path = path[1:-1]
|
|
|
|
|
2022-10-03 05:52:50 +00:00
|
|
|
if args.type == "file_search":
|
2023-09-16 06:18:36 +00:00
|
|
|
file_search(path, args.query.lower())
|
2022-10-03 05:52:50 +00:00
|
|
|
|
|
|
|
if args.type == "grep_search":
|
2023-09-16 06:18:36 +00:00
|
|
|
grep_search(path, args.query.encode("utf-8"))
|
2022-10-03 05:52:50 +00:00
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
try:
|
|
|
|
setproctitle('SolarFM: File Search - Grepy')
|
|
|
|
|
|
|
|
parser = argparse.ArgumentParser()
|
|
|
|
# Add long and short arguments
|
|
|
|
parser.add_argument("--type", "-t", default=None, help="Type of search to do.")
|
|
|
|
parser.add_argument("--dir", "-d", default=None, help="Directory root for search type.")
|
|
|
|
parser.add_argument("--query", "-q", default=None, help="Query search is working against.")
|
|
|
|
|
|
|
|
# Read arguments (If any...)
|
|
|
|
args = parser.parse_args()
|
|
|
|
search(args)
|
2023-03-05 03:45:29 +00:00
|
|
|
|
|
|
|
data = f"SEARCH_DONE|{ts}|0"
|
|
|
|
send_ipc_message(data)
|
2022-10-03 05:52:50 +00:00
|
|
|
except Exception as e:
|
|
|
|
traceback.print_exc()
|
2023-03-05 03:45:29 +00:00
|
|
|
|
|
|
|
data = f"SEARCH_DONE|{ts}|1"
|
|
|
|
send_ipc_message(data)
|