gitgud / app.py
stepenZEN's picture
Update app.py
729cec6 verified
from flask import Flask, send_file, request, render_template
import io
import zipfile
import os
app = Flask(__name__)
import subprocess
import re
from urllib.parse import urlparse, urlunparse
import shutil
def sanitize_git_url(url):
"""Sanitizes a Git repository URL."""
# Validate URL structure using urllib.parse
try:
parsed_url = urlparse(url)
if not all([parsed_url.scheme, parsed_url.netloc]):
print(f"Error: Invalid URL structure: {url}")
return None
if parsed_url.scheme not in ("https", "http", "git", "ssh"):
print(f"Error: Invalid URL scheme: {parsed_url.scheme}")
return None
except Exception:
print(f"Error: Could not parse url: {url}")
return None
# check input for suspicious characters
if re.search(r'[;&|]', url):
print(f"Error: Suspicious character in url {url}")
return None
# Normalize the url. Remove trailing slashes and .git suffix
normalized_url = url.rstrip("/").rstrip(".git")
return normalized_url
def git_clone(repo_url):
"""Clones a Git repository, using the repo name as the destination folder."""
sanitized_url = sanitize_git_url(repo_url)
if not sanitized_url:
return # If sanitize_git_url returned None, don't continue.
try:
# Extract the repository name from the URL
repo_name = extract_repo_name(sanitized_url)
if not repo_name:
print(f"Error: Unable to extract repository name from URL: {repo_url}")
return
destination_dir = repo_name # Use the extracted name for the destination folder
if os.path.isdir(destination_dir):
return repo_name
subprocess.run(
["git", "clone", sanitized_url, destination_dir],
check=True,
capture_output=True,
text=True
)
print(f"Successfully cloned {sanitized_url} to {destination_dir}")
return repo_name
except subprocess.CalledProcessError as e:
print(f"Error cloning {sanitized_url}:")
print(f" Return code: {e.returncode}")
print(f" Stdout:\n{e.stdout}")
print(f" Stderr:\n{e.stderr}")
def extract_repo_name(repo_url):
"""Extracts the repository name from a Git URL."""
# Example formats:
# https://github.com/user/repo.git
# [email protected]:user/repo.git
# https://gitlab.com/user/repo
match = re.search(r"([^/:]+)\/?$", repo_url.rstrip(".git/"))
if match:
return match.group(1)
else:
return None
def zip_folder_to_buffer(folder_path):
"""
Zips a folder and returns the zipped content in a BytesIO buffer.
Args:
folder_path: The path to the folder you want to zip.
Returns:
A io.BytesIO buffer containing the zipped folder data, or None if
there is an error.
"""
try:
buffer = io.BytesIO()
with zipfile.ZipFile(buffer, 'w', zipfile.ZIP_DEFLATED) as zf:
for root, _, files in os.walk(folder_path):
for file in files:
file_path = os.path.join(root, file)
arcname = os.path.relpath(file_path, folder_path)
zf.write(file_path, arcname=arcname)
buffer.seek(0) # Reset buffer position to the beginning for reading
return buffer
except Exception as e:
print(f"Error creating zip file: {e}")
return None
@app.route('/', methods=['GET', 'POST'])
def index():
if request.method == 'POST':
# folder_to_zip = "./my_folder" # Replace with the actual folder path
# deltemp = remove_all_files_and_directories("temp_folder") #clean temp folder
# # Create an example folder and files
# os.makedirs(folder_to_zip, exist_ok=True)
# with open(os.path.join(folder_to_zip, "file1.txt"), "w") as f:
# f.write("This is file1")
# with open(os.path.join(folder_to_zip, "file2.txt"), "w") as f:
# f.write("This is file2")
repo_url = request.form['giturl'] #"https://huggingface.co/spaces/stepenZEN/gitgud" # Example repo, can be very large
folder_to_zip = git_clone(repo_url)
# if not folder_to_zip:
# return
zipped_buffer = zip_folder_to_buffer(folder_to_zip)
if zipped_buffer:
# Send the zipped buffer as a file download
response = send_file(
zipped_buffer,
mimetype="application/zip", # Important: Set the correct MIME type
as_attachment=True,
download_name=f"{folder_to_zip}.zip" # Optional: Sets the suggested file name
)
# Clean up the example folder
# os.remove(os.path.join(folder_to_zip, "file1.txt"))
# os.remove(os.path.join(folder_to_zip, "file2.txt"))
# os.rmdir(folder_to_zip)
# shutil.rmtree(folder_to_zip)
return response
else:
return "Failed to create zip file", 500
return render_template('form.html') # Render form template
if __name__ == '__main__':
# app = create_app()
app.run(debug=True, port=5500)