import re from pathlib import Path import django.forms as forms from django.http import HttpResponseRedirect from django.shortcuts import redirect, render import troggle.settings as settings #from troggle.core.models.caves import Entrance, Cave from troggle.core.utils import ( WriteAndCommitError, current_expo, get_cookie, git_string, write_and_commit, ) from troggle.core.models.caves import Cave, Entrance from troggle.core.views.caves import get_cave_from_slug """Forms to handle renaming files and editing contents when a cave is 'katastered', ie.e moves from an informal number, such as 1623-2024-BL-10 to 1623-999 """ def fix(request, areacode="1626"): """Fix bad stuff: 2023 misplaced i/l/t files for caves in both 1623 (65 files x3) and 1626 (29 filex x 3) """ triple = ["i", "l", "t"] ents_html = settings.ENTRANCEDESCRIPTIONS caves_html = settings.CAVEDESCRIPTIONS to_move = [] caves_in_area = list(Cave.objects.filter(areacode=areacode, kataster_number="")) caves_nodir=[] ents = [] print(f"\n---------- {areacode}") # hack because some caves in 1623 have already been katastered. Bugger. That screws things up. for i in range(303,316): more = Cave.objects.filter(areacode=areacode, kataster_number=f"{i}") # print(more) caves_in_area.append(more[0]) for c in caves_in_area: cave_id = f"{c.areacode}-{c.unofficial_number}" c_html = caves_html / f"{cave_id}.html" if not c_html.is_file(): cave_id = f"{c.areacode}-{c.kataster_number}" c_html = caves_html / f"{cave_id}.html" if not c_html.is_file(): raise ents.append(c.entrances()) with open(c_html, 'r') as f: for line in f: search_term = f"{areacode}" + "/(l|t|i)/([^'\"]*)" if match := re.findall(search_term, line): # print(c, search_term, match, line) for m in match: dir, filename = m to_move.append(("c", dir, cave_id[5:], c_html.name, filename)) # for item in to_move: # print(item) for ce in ents: cc = ce[0].cave # print(cc) original_number = cc.unofficial_number for e in ce: # print(" ",e.entrance.slug, e.entrance.filename) e_html = ents_html / e.entrance.filename print(range(303,316), cc.kataster_number) if cc.kataster_number and int(cc.kataster_number) in range(303,316): original_number = cc.kataster_number u = cc.unofficial_number k = cc.kataster_number print(u,k) e_html = ents_html / e_html.name.replace(f"{cc.unofficial_number}",f"{cc.kataster_number}") if not e_html.is_file(): e_html = ents_html / e_html.name.replace(f"{original_number}",f"{cc.kataster_number}") original_number = cc.kataster_number if not e_html.is_file(): raise with open(e_html, 'r') as f: for line in f: search_term = f"{areacode}" + "/(l|t|i)/([^'\"]*)" if match := re.findall(search_term, line): print(c, search_term, match, line) for m in match: dir, filename = m to_move.append(("e", dir, original_number, e.entrance.filename, filename)) to_move = list(set(to_move)) to_move.sort(key=lambda tup: tup[2]) # for c in caves_in_area: # cave_dir = settings.EXPOWEB / areacode / c.unofficial_number # if cave_dir.is_dir(): # print(f"YES {c.unofficial_number}") # for subfile in cave_dir.iterdir(): # if subfile.name not in triple: # print(f" ---- {subfile.name}") # else: # print(f" ++++ {subfile.name}") # else: # # print(f"NO {c.unofficial_number}") # caves_nodir.append(c.unofficial_number) for key, dir, cave_id, filename, target in to_move: if key == "c": print((key, dir, cave_id, filename, target)) print("") for key, dir, cave_id, filename, target in to_move: if key == "e": print((key, dir, cave_id, filename, target)) newdirs = set() for key, dir, cave_id, filename, target in to_move: newdirs.add(cave_id) x_script = f"cd {settings.EXPOWEB / areacode}\n" for id in newdirs: # PATH.mkdir(parents=True, exist_ok=True) for d in triple: x_script += f"mkdir -p {id}/{d}\n" # This duplicates things horribly: every individual /l/ means a whole set of duplicate sed lines # simplify with a set somehow.. # don't trigger this on seeing a /l/, just do it at the end on all the cave_data and entrance_data files we have seen. x_script += f"cd {settings.EXPOWEB / areacode}\n" for key, dir, cave_id, filename, target in to_move: x_script += f"mv {dir}/\"{target}\" {cave_id}/{dir}\n" if dir =="t": x_script += f"mv i/\"{target}\" {cave_id}/i\n" if dir =="l": x_script += f"sed -i 's|\/{areacode}\/i\/|/{areacode}/{cave_id}/i/|g' {cave_id}/l/*.html\n" x_script += f"sed -i \"s|\/{areacode}\/i\/|/{areacode}/{cave_id}/i/|g\" {cave_id}/l/*.html\n" for q in triple: if key =="e": x_script += f"sed -i 's|\/{areacode}\/{q}\/|/{areacode}/{cave_id}/{q}/|g' ../entrance_data/'{filename}'\n" x_script += f"sed -i \"s|\/{areacode}\/{q}\/|/{areacode}/{cave_id}/{q}/|g\" ../entrance_data/'{filename}'\n" if key == "c": x_script += f"sed -i 's|\/{areacode}\/{q}\/|/{areacode}/{cave_id}/{q}/|g' ../cave_data/'{filename}'\n" x_script += f"sed -i \"s|\/{areacode}\/{q}\/|/{areacode}/{cave_id}/{q}/|g\" ../cave_data/'{filename}'\n" script_rows = str(max(35,3+x_script.count('\n'))) return render( request, "cave_fix.html", {"areacode": areacode, "caves_nodir": caves_nodir, "x_script": x_script, "rows": script_rows, }, ) def misplaced_html_files(cave): filelist = "" bad_place = settings.EXPOWEB / cave.areacode /"l" if bad_place.is_dir(): for subfile in bad_place.iterdir(): if subfile.name.lower().startswith(cave.unofficial_number.lower()): filelist += "   " + subfile.name + "
\n" return filelist def get_loser_dir(cave): """ Copes with capitalisation mismatch between declared loser diretory and actual. Two places to look: 1. in caves-1623//*.svx 2. in parent of survex file specified in the cave_data html page. return loser_dir, loser_name e.g. /home/philip/expo/loser/caves-1623/2024-jc-01 , caves-1623/2024-jc-01 """ loser_name = str(cave.unofficial_number) parent = settings.SURVEX_DATA / f"caves-{str(cave.areacode)}" for dn in [loser_name, loser_name.lower(), loser_name.upper()]: if ( parent / dn).is_dir(): return parent / dn, Path(f"caves-{str(cave.areacode)}") / dn if (settings.SURVEX_DATA / cave.survex_file).is_file(): loser_dir = (settings.SURVEX_DATA / cave.survex_file).parent return loser_dir, Path(cave.survex_file).parent raise FileNotFoundError("This cave has no directory for survex files in the loser repo") def get_cd(path): return f"$BASE_DIR/{path.relative_to(settings.REPOS_ROOT_PATH)}" def entrances_list(cave): entrances = [] for e in cave.entrances(): # horrid CaveAndEntrance indirection we need to refactor out in due course if e.entrance.best_station(): entrances.append(e.entrance) return entrances def entrances_stations(cave): entrance_stations = [] for e in cave.entrances(): # horrid CaveAndEntrance indirection we need to refactor out in due course if e.entrance.tag_station: entrance_stations.append((e.entrance, e.entrance.tag_station[4:])) if e.entrance.other_station: entrance_stations.append((e.entrance, e.entrance.other_station[4:])) return entrance_stations def kataster(request, slug=None): """Create the page which analyses how to rename a cave and all the files from the unofficial_number identifier, e.g. 1623-2023-mg-03 to the kataster number e.g. 1623-999 """ def do_file_finding(knum): global cavefilename, cave_data, entrance_data, loser_name, loser_data mvscript = f"BASE_DIR={settings.REPOS_ROOT_PATH}\n\n" ent_dir = settings.ENTRANCEDESCRIPTIONS # settings.EXPOWEB / "entrance_data" mvscript += f"cd {get_cd(settings.ENTRANCEDESCRIPTIONS)}\n" if cave.areacode == "1623": pt_target = "$BASE_DIR/loser/fixedpts/gps/gps*.svx" elif cave.areacode == "1626": pt_target = "$BASE_DIR/loser/fixedpts/*.svx" else: # 1627, 1624 pt_target = "nowt.svx" for ent, station in entrances_stations(cave): new = station.replace(cave.unofficial_number,str(knum)) sed_cmd = f"s/{station}/{new}/g".replace(".","\.") mvscript += f'sed -i {sed_cmd} {ent}.html\n' mvscript += f'sed -i {sed_cmd} {pt_target}\n' # 2024-DM-01 has no tag_ or other_station, but does have a *fix, cited in the survex file, catch this case: fix = (cave.unofficial_number) new = fix.replace(cave.unofficial_number,str(knum)) sed_cmd = f"s/{fix}/{new}/g".replace(".","\.") mvscript += f'sed -i "{sed_cmd}" {pt_target}\n' entrance_data = [] for ent in ent_dir.iterdir(): if str(ent.name).startswith(str(cave)): print(ent.name) entrance_data.append("entrance_data/"+ent.name) mvscript += f'sed -i "/{str(cave)}/d" {ent.name}\n' mvscript += f'sed -i "/href=\|src=/s/\/{cave.areacode}\/{cave.unofficial_number}\//\/{cave.areacode}\/{knum}\//g" {ent.name}\n' mvscript += f"mv {ent.name} {ent.name.replace(str(cave.unofficial_number),str(knum))}\n" mvscript += f"\ncd {get_cd(settings.CAVEDESCRIPTIONS)}\n" cavefilename = str(cave) + ".html" target= f"{cave.areacode}-{str(knum)}" cave_data = Path( "cave_data", cavefilename ) if not (settings.CAVEDESCRIPTIONS / cavefilename).is_file: # settings.EXPOWEB / cave_data cave_data = "does not exist" mvscript += f'sed -i "//s//{knum}/" {cavefilename}\n' mvscript += f'sed -i "//s/[^<]*/caves-{cave.areacode}\/{knum}\/{knum}.svx/" {cavefilename}\n' mvscript += f'sed -i "//s/{str(cave)}/{cave.areacode}-{knum}/" {cavefilename}\n' mvscript += f'sed -i "/href=\|src=/s/\/{cave.areacode}\/{cave.unofficial_number}\//\/{cave.areacode}\/{knum}\//g" {cavefilename}\n' mvscript += f"mv {cavefilename} {target}.html\n\n" mvscript += f"cd {get_cd(settings.EXPOWEB / cave.areacode / cave.unofficial_number)}\n" mvscript += f'sed -i "/href=\|src=/s/\/{cave.areacode}\/{cave.unofficial_number}\//\/{cave.areacode}\/{knum}\//g" *.html\n' mvscript += f'sed -i "/href=\|src=/s/\/{cave.areacode}\/{cave.unofficial_number}\//\/{cave.areacode}\/{knum}\//g" */*.html\n\n' mvscript += f"cd {get_cd(settings.EXPOWEB / cave.areacode)}\n" mvscript += f"mv {cave.unofficial_number} {knum}\n\n" loser_data = [] try: loser_dir, loser_name = get_loser_dir(cave) except: return mvscript if (loser_dir).is_dir(): print(loser_dir) for svx in loser_dir.iterdir(): print(svx) loser_data.append(Path(loser_dir , svx).name) return mvscript def script_loser(knum): global cavefilename, cave_data, entrance_data, loser_name, loser_data try: loser_dir, loser_name = get_loser_dir(cave) #/home/philip/expo/loser/caves-1623/2024-jc-01 , caves-1623/2024-jc-01 target = loser_name.parent / str(knum) survex_name = str(loser_name.name) l_script = f"\ncd {get_cd(settings.SURVEX_DATA)}\n" l_script += f'sed -i "/^*include/s/{survex_name}/{knum}/g" {loser_name.parent}/caves.svx\n' l_script += f'sed -i "/^*equate/s/{survex_name}/{knum}/g" {loser_name}/{survex_name}.svx\n' l_script += f'sed -i "/^*entrance/s/{survex_name}/{knum}/g" {loser_name}/{survex_name}.svx\n' l_script += f'sed -i "/^*begin/s/{survex_name}/{knum}/" {loser_name}/{survex_name}.svx\n' l_script += f'sed -i "/^*end/s/{survex_name}/{knum}/" {loser_name}/{survex_name}.svx\n' l_script +=f"# These 'sed' edits will not do everything in all cases, but they do the basics\n\n" except FileNotFoundError as e: print(e) loser_name = "" l_script = f"\n# {e}\n\n" area_dir = get_cd(settings.SURVEX_DATA / f"caves-{cave.areacode}") l_script +=f"cd {area_dir}\n" l_script +=f"mv {cave.unofficial_number} {knum}\n" l_script +=f"cd {knum}\n" for filename in loser_data: if survex_name in filename: l_script +=f"mv {filename} {filename.replace(survex_name,str(knum))}\n" l_script +=f"# But note that git ignores .log and .3d files\n\n" error = "" for dir in [(settings.SURVEX_DATA / f"caves-{cave.areacode}" / str(knum)), (settings.EXPOWEB / cave.areacode / str(knum))]: if dir.is_dir(): error += f"STOP: a target directory exists. REMOVE or RENAME it first: {dir}
\n" # 1623 : fixedpts/gps/gps23.svx:26:*fix p2023-mg-03 reference 13.81514 47.69169 1767 # 1626: fixedpts/1626-no-schoenberg-hs-not-tied-to-caves.svx return l_script, error knum = 9999 if not slug: slug = "1623-2013-BL-01" if cave := get_cave_from_slug(slug.lower()): pass elif cave := get_cave_from_slug(slug.upper()): pass else: return HttpResponseRedirect("/caves") entrances = entrances_list(cave) # for e in cave.entrances(): # horrid CaveAndEntrance indirection we need to refactor out in due course # if e.entrance.best_station(): # entrances.append(e.entrance) _ = do_file_finding(knum) try: # this is a python generator idiom. # see https://realpython.com/introduction-to-python-generators/ # THIS IS VERY SILLY. We have this in the databse fom when this file was parsed. Don't read it again ! # However we will need to parse the href= and src= strings in the cave description text, notes etc. with open(settings.CAVEDESCRIPTIONS / cavefilename, 'r') as f: for line in f: if match := re.search(r'(.*?)', line): entrance = match.group(1) print(entrance) except PermissionError as e: msg=f"CANNOT save this file.\nPERMISSIONS incorrectly set on server for this file {cavefilename}. Ask a nerd to fix this: {e}" print(msg) raise except Exception as e: msg=f"CANNOT write this file {cavefilename}. Ask a nerd to fix this: {e}" print(msg) # Restart script with POST data script = "# Conversion script - nearly complete\n# When doing it by hand, it is less error-prone to do the file re-namings last,\n" script += "# after the edits, but in a script it does not matter so much\n" script += "# so long as everything is consistent and tested.\n" script += "# Except that reversing changes using git does not always restore directories exactly\n# (because of .gitignore).\n\n" script += "# Be careful with the BASE_DIR directory: usually NOT the same on your PC as on the server\n\n" warning ="" if request.method == "POST": # If the form has been submitted... form = KatasterForm(request.POST) # A form bound to the POST data if form.is_valid(): clean = form.cleaned_data knum = clean['kataster_number'] print(f" # kataster_number {clean['kataster_number']}") if test := get_cave_from_slug(f"{cave.areacode}-{knum}"): warning = "

DANGER DANGER You will overwrite an existing katastered cave !!!
" warning += "resetting proposed new kataster number to 666.

" knum = 666 else: # GET and fall-through if POST is not valid form = KatasterForm() script += do_file_finding(knum) scr, error = script_loser(knum) script += scr alias = f'(\\"{cave.slug()}\\", \\"{cave.areacode}-{knum}\\"),' aliasfile = settings.CAVEDESCRIPTIONS / "cavealiases.txt" script += f'\necho "{alias}" >> {get_cd(aliasfile)}\n\n' script += f"# grep to see what we have missed, though should still be records of the old name in expoweb.\n" script += f"# (and gps_essentials will need refreshing)\n" script += f'grep -nirI --exclude-dir=.git --exclude-dir=gpx --exclude="*.gpx" --exclude="*.log" --exclude="*.kml" --exclude="*.pos" "{cave.unofficial_number}" $BASE_DIR/loser\n' script += f'grep -nirI --exclude-dir=.git --exclude="*.gpx" "{cave.unofficial_number}" $BASE_DIR/expoweb\n' misplaced = misplaced_html_files(cave) script_rows = str(max(35,3+script.count('\n'))) return render( request, "cave_kataster.html", { "form": form, "warning": warning, "error": error, "cave": cave, "entrances": entrances, "misplaced": misplaced, "cave_data": cave_data, "entrance_data": entrance_data, "loser_name": loser_name, "loser_data": loser_data, "knum": knum, "script": script, "rows": script_rows, }, ) class KatasterForm(forms.Form): kataster_number= forms.IntegerField(label="New kataster no.", widget=forms.TextInput(attrs={'tabindex': 1, 'size':1, 'placeholder': '9999'})) """ SURVEX_DATA = REPOS_ROOT_PATH / "loser" EXPOWEB = REPOS_ROOT_PATH / "expoweb" CAVEDESCRIPTIONS = EXPOWEB / "cave_data" ENTRANCEDESCRIPTIONS = EXPOWEB / "entrance_data" """