119 lines
4.6 KiB
Python
119 lines
4.6 KiB
Python
import os
|
|
import zipfile
|
|
import shutil
|
|
import re
|
|
|
|
# Source and Destination
|
|
SOURCE_DIR = 'sql_tools_zip'
|
|
DEST_DIR = 'sql_tools'
|
|
|
|
# Mapping structure: (Zip Pattern, Target Folder Structure, Executables to Extract)
|
|
# Target Folder Structure: e.g. "mysql/{version}" where {version} is extracted from filename
|
|
RULES = [
|
|
{
|
|
'pattern': r'mysql-(\d+\.\d+)\.\d+-winx64\.zip',
|
|
'type': 'mysql',
|
|
'bin_path': 'bin/', # usually inside root folder of zip
|
|
'executables': ['mysqldump.exe']
|
|
},
|
|
{
|
|
'pattern': r'mariadb-(\d+\.\d+)\.\d+-winx64.*\.zip',
|
|
'type': 'mariadb',
|
|
'bin_path': 'bin/',
|
|
'executables': ['mariadb-dump.exe', 'mysqldump.exe'] # Try both
|
|
},
|
|
{
|
|
'pattern': r'postgresql-(\d+\.\d+).*windows-x64-binaries\.zip',
|
|
'type': 'postgres',
|
|
'bin_path': 'pgsql/bin/', # pg binaries zip usually has pgsql/bin
|
|
'executables': ['pg_dump.exe', 'pg_dumpall.exe', 'libpq.dll', 'libiconv-2.dll', 'libintl-8.dll', 'libssl-1_1-x64.dll', 'libcrypto-1_1-x64.dll'] # DLLs might be needed!
|
|
# Modern PG zip structure might differ, checking pgsql/bin is standard for binaries zip
|
|
},
|
|
{
|
|
# Special handler for PG 18 if pattern differs or standard regex fails
|
|
'pattern': r'postgresql-(\d+)\.\d+.*windows-x64-binaries\.zip',
|
|
'type': 'postgres',
|
|
'bin_path': 'pgsql/bin/',
|
|
'executables': ['pg_dump.exe', 'pg_dumpall.exe']
|
|
}
|
|
]
|
|
|
|
def ensure_dir(path):
|
|
if not os.path.exists(path):
|
|
os.makedirs(path)
|
|
|
|
def extract_tools():
|
|
if not os.path.exists(SOURCE_DIR):
|
|
print("Source directory '{}' not found.".format(SOURCE_DIR))
|
|
return
|
|
|
|
ensure_dir(DEST_DIR)
|
|
|
|
files = [f for f in os.listdir(SOURCE_DIR) if f.lower().endswith('.zip')]
|
|
|
|
print("Found {} zip files.".format(len(files)))
|
|
|
|
for filename in files:
|
|
# Match rule
|
|
matched_rule = None
|
|
version = None
|
|
|
|
for rule in RULES:
|
|
match = re.search(rule['pattern'], filename)
|
|
if match:
|
|
matched_rule = rule
|
|
version = match.group(1)
|
|
break
|
|
|
|
if not matched_rule:
|
|
print("Skipping unknown file: {}".format(filename))
|
|
continue
|
|
|
|
db_type = matched_rule['type']
|
|
target_dir = os.path.join(DEST_DIR, db_type, version)
|
|
|
|
print("Processing {} -> {}...".format(filename, target_dir))
|
|
|
|
try:
|
|
with zipfile.ZipFile(os.path.join(SOURCE_DIR, filename), 'r') as zf:
|
|
# Find the internal path prefix (usually top folder)
|
|
# We assume binaries are in {top_folder}/{bin_path} or just {bin_path}
|
|
# Let's search for the executable to determine path
|
|
|
|
for exe in matched_rule['executables']:
|
|
# find file in zip
|
|
target_member = None
|
|
for name in zf.namelist():
|
|
if name.endswith("/{}".format(exe)) or name == exe:
|
|
# Verify if it looks like a bin folder
|
|
if matched_rule['bin_path'].strip('/') in name:
|
|
target_member = name
|
|
break
|
|
|
|
if target_member:
|
|
ensure_dir(target_dir)
|
|
source = zf.open(target_member)
|
|
target_file_path = os.path.join(target_dir, exe)
|
|
with open(target_file_path, "wb") as target:
|
|
shutil.copyfileobj(source, target)
|
|
print(" Extracted: {}".format(exe))
|
|
|
|
# For Postgres, we might need DLLs.
|
|
# Simple logic: if 'postgres' in db_type, try to grab standard DLLs in same dir as exe
|
|
if db_type == 'postgres':
|
|
parent = os.path.dirname(target_member)
|
|
for item in zf.namelist():
|
|
if os.path.dirname(item) == parent and item.lower().endswith('.dll'):
|
|
dll_name = os.path.basename(item)
|
|
with open(os.path.join(target_dir, dll_name), "wb") as dll_out:
|
|
shutil.copyfileobj(zf.open(item), dll_out)
|
|
|
|
else:
|
|
print(" Warning: {} not found in {}".format(exe, filename))
|
|
|
|
except Exception as e:
|
|
print(" Error extracting {}: {}".format(filename, e))
|
|
|
|
if __name__ == "__main__":
|
|
extract_tools()
|