146 lines
4.1 KiB
Python
146 lines
4.1 KiB
Python
#!/usr/bin/env python3
|
|
import os
|
|
import json
|
|
import ftplib
|
|
import sys
|
|
import hashlib
|
|
from pathlib import Path
|
|
|
|
SCRIPT_DIR = Path(__file__).resolve().parent
|
|
PROJECT_DIR = SCRIPT_DIR.parent
|
|
CONFIG_FILE = SCRIPT_DIR / 'deploy_config.json'
|
|
CACHE_FILE = SCRIPT_DIR / '.deploy_cache.json'
|
|
|
|
IGNORE_PATTERNS = {
|
|
'.git',
|
|
'.gitignore',
|
|
'scripts',
|
|
'.deploy_cache.json',
|
|
'Serverdaten.txt',
|
|
'Serverdaten.txt.bak',
|
|
'bin',
|
|
'obj'
|
|
}
|
|
|
|
def load_config():
|
|
if not CONFIG_FILE.exists():
|
|
print(f"Error: Config file {CONFIG_FILE} does not exist.")
|
|
sys.exit(1)
|
|
with open(CONFIG_FILE, 'r', encoding='utf-8') as f:
|
|
return json.load(f)
|
|
|
|
def load_cache():
|
|
if CACHE_FILE.exists():
|
|
try:
|
|
with open(CACHE_FILE, 'r', encoding='utf-8') as f:
|
|
return json.load(f)
|
|
except Exception:
|
|
return {}
|
|
return {}
|
|
|
|
def save_cache(cache):
|
|
with open(CACHE_FILE, 'w', encoding='utf-8') as f:
|
|
json.dump(cache, f, indent=2)
|
|
|
|
def compute_hash(filepath):
|
|
h = hashlib.md5()
|
|
with open(filepath, 'rb') as f:
|
|
while chunk := f.read(8192):
|
|
h.update(chunk)
|
|
return h.hexdigest()
|
|
|
|
def ensure_remote_dir(ftp, remote_path):
|
|
dirs = [d for d in remote_path.strip('/').split('/') if d]
|
|
current = ''
|
|
for d in dirs:
|
|
current += '/' + d
|
|
try:
|
|
ftp.cwd(current)
|
|
except ftplib.error_perm:
|
|
try:
|
|
ftp.mkd(current)
|
|
print(f"Created remote directory: {current}")
|
|
except Exception as e:
|
|
print(f"Warning: Could not create directory {current}: {e}")
|
|
|
|
def should_ignore(rel_path):
|
|
parts = Path(rel_path).parts
|
|
if not parts:
|
|
return False
|
|
for part in parts:
|
|
if part in IGNORE_PATTERNS:
|
|
return True
|
|
if part == '.htaccess':
|
|
continue
|
|
if part.startswith('.'):
|
|
return True
|
|
return False
|
|
|
|
def deploy():
|
|
config = load_config()
|
|
cache = load_cache()
|
|
new_cache = dict(cache)
|
|
|
|
print(f"Connecting to FTP {config['host']}...")
|
|
try:
|
|
if config.get('secure', False):
|
|
ftp = ftplib.FTP_TLS()
|
|
ftp.connect(config['host'], config.get('port', 21))
|
|
ftp.login(config['user'], config['pass'])
|
|
ftp.prot_p()
|
|
else:
|
|
ftp = ftplib.FTP()
|
|
ftp.connect(config['host'], config.get('port', 21))
|
|
ftp.login(config['user'], config['pass'])
|
|
print("Logged in successfully.")
|
|
except Exception as e:
|
|
print(f"FTP Connection failed: {e}")
|
|
sys.exit(1)
|
|
|
|
files_to_upload = []
|
|
for root, dirs, files in os.walk(PROJECT_DIR):
|
|
rel_dir = os.path.relpath(root, PROJECT_DIR)
|
|
if rel_dir == '.':
|
|
rel_dir = ''
|
|
|
|
dirs[:] = [d for d in dirs if not should_ignore(os.path.join(rel_dir, d))]
|
|
|
|
for f in files:
|
|
rel_file = os.path.normpath(os.path.join(rel_dir, f)).replace('\\', '/')
|
|
if should_ignore(rel_file):
|
|
continue
|
|
|
|
full_path = os.path.join(root, f)
|
|
file_hash = compute_hash(full_path)
|
|
|
|
if cache.get(rel_file) != file_hash:
|
|
files_to_upload.append((rel_file, full_path, file_hash))
|
|
|
|
if not files_to_upload:
|
|
print("No changed files to upload. Remote is up to date!")
|
|
ftp.quit()
|
|
return
|
|
|
|
print(f"Found {len(files_to_upload)} file(s) to upload:")
|
|
for rel_file, full_path, file_hash in files_to_upload:
|
|
print(f" -> {rel_file}")
|
|
|
|
for rel_file, full_path, file_hash in files_to_upload:
|
|
remote_file_path = f"/{rel_file}"
|
|
remote_dir = os.path.dirname(remote_file_path).replace('\\', '/')
|
|
if remote_dir and remote_dir != '/':
|
|
ensure_remote_dir(ftp, remote_dir)
|
|
|
|
ftp.cwd('/')
|
|
print(f"Uploading {rel_file} ...")
|
|
with open(full_path, 'rb') as f:
|
|
ftp.storbinary(f"STOR {remote_file_path}", f)
|
|
new_cache[rel_file] = file_hash
|
|
|
|
save_cache(new_cache)
|
|
ftp.quit()
|
|
print("Deployment completed successfully!")
|
|
|
|
if __name__ == '__main__':
|
|
deploy()
|