Skip to content

Instantly share code, notes, and snippets.

@yymao
Last active April 5, 2026 17:13
Show Gist options
  • Select an option

  • Save yymao/6457f129b7fa54e5c154dcdd3f8f9785 to your computer and use it in GitHub Desktop.

Select an option

Save yymao/6457f129b7fa54e5c154dcdd3f8f9785 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python3
#
# move-website.py
# A script that backs up the existing public_html directory and points the website to a new URL.
# Author: Yao-Yuan Mao
#
# Usage:
# python move-website.py --to-url [new url]
# python move-website.py --to-elements [uNID]
# python move-website.py --backup-only
# Additional option: --skip-url-check to skip URL validation
import argparse
import html
import os
import re
import sys
import urllib.request
_ELEMENTS_URL = "https://profiles.faculty.utah.edu/{unid}/"
_HTML_TEMPLATE = """<!DOCTYPE html>
<html lang="en">
<head>
<script>location.href="$URL_JS$";</script>
<meta http-equiv="refresh" content="0;url=$URL$" />
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
</head>
<body>
<p>You are being redirected to <a href="$URL$">$URL$</a></p>
</body>
</html>
"""
def check_url(url):
req = urllib.request.Request(url, method='HEAD')
try:
with urllib.request.urlopen(req) as response:
code = response.getcode()
return (code >= 200) and (code < 400)
except Exception as e:
print(f"Error checking URL: {e}")
return False
def run():
parser = argparse.ArgumentParser(description="Back up public_html and point the website to a new URL.")
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument("--to-url", help="Redirect to the specified URL")
group.add_argument("--to-elements", metavar="uNID", help="Redirect to the Utah Elements profile for the given uNID")
group.add_argument("--backup-only", action="store_true", help="Only back up public_html without creating a redirect")
parser.add_argument("--skip-url-check", action="store_true", help="Skip URL validation")
args = parser.parse_args()
if args.to_elements:
if not re.match(r"^u\d{7}$", args.to_elements):
print(f"Invalid uNID format for {args.to_elements}. Please use the format u followed by 7 digits.")
return 10
url = _ELEMENTS_URL.format(unid=args.to_elements)
else:
if args.to_url and not re.match(r"^https?://[^/]+", args.to_url, re.IGNORECASE):
print(f"Invalid URL format for {args.to_url}. Please include http:// or https://.")
return 11
url = args.to_url
if not args.backup_only and not args.skip_url_check:
if not check_url(url):
print(f"URL check failed for {url}. Use --skip-url-check to skip this check.")
return 20
public_html = os.path.expanduser("~/public_html")
backup_path = public_html + ".bak"
if os.path.exists(public_html):
if os.path.exists(backup_path):
counter = 1
while os.path.exists(f"{backup_path}.{counter}"):
counter += 1
backup_path = f"{backup_path}.{counter}"
os.rename(public_html, backup_path)
print(f"Backed up public_html to {backup_path}")
else:
print("No existing public_html to back up.")
backup_path = None
if not args.backup_only:
os.makedirs(public_html, exist_ok=True)
if os.listdir(public_html):
print("New public_html is not empty. Something is wrong... aborting.")
return 30
url_for_html = html.escape(url)
url_for_js = url.replace("\\", "\\\\").replace('"', '\\"').replace("<", "\\x3c")
html_src = (
_HTML_TEMPLATE
.replace("$URL_JS$", url_for_js)
.replace("$URL$", url_for_html)
)
index_path = os.path.join(public_html, "index.html")
with open(index_path, "w") as f:
f.write(html_src)
print(f"public_html now redirects to {url}")
if backup_path:
print(f"Previous site backed up at {backup_path}")
return 0
if __name__ == "__main__":
sys.exit(run())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment