removed recursion
This commit is contained in:
@@ -1,3 +0,0 @@
|
|||||||
eclipse.preferences.version=1
|
|
||||||
encoding//kodi/context.kino.control/main.py=utf-8
|
|
||||||
encoding//kodi/context.kino.control/resources/lib/context.py=utf-8
|
|
||||||
@@ -15,9 +15,10 @@ REDMINE_URL = "https://redmine.maketank.net" # e.g., https://redmine.example.co
|
|||||||
REDMINE_API_KEY = "62120b7ed6bf84023b2a1d7d5a265cf172f8d607"
|
REDMINE_API_KEY = "62120b7ed6bf84023b2a1d7d5a265cf172f8d607"
|
||||||
PROJECT_ID = "bastelstube" # e.g., "my-project"
|
PROJECT_ID = "bastelstube" # e.g., "my-project"
|
||||||
|
|
||||||
GITEA_WIKI_URL = "https://git.maketank.net/chaos/spielplatz.wiki.git" # Gitea wiki Git URL
|
#GITEA_WIKI_URL = "https://git.maketank.net/chaos/spielplatz.wiki.git" # Gitea wiki Git URL
|
||||||
GITEA_USERNAME = "do"
|
GITEA_WIKI_URL = "ssh://git@git.maketank.net:2222/chaos/spielplatz.wiki.git"
|
||||||
GITEA_TOKEN = "2d2be00637182c6d5411512f456218ee59fa1f81" # Use a personal access token
|
#GITEA_USERNAME = "do"
|
||||||
|
#GITEA_TOKEN = "2d2be00637182c6d5411512f456218ee59fa1f81" # Use a personal access token
|
||||||
|
|
||||||
# Optional: Gitea API for creating pages (if you want to use it instead of Git)
|
# Optional: Gitea API for creating pages (if you want to use it instead of Git)
|
||||||
# GITEA_API_URL = "https://gitea.example.com/api/v1"
|
# GITEA_API_URL = "https://gitea.example.com/api/v1"
|
||||||
@@ -26,7 +27,7 @@ GITEA_TOKEN = "2d2be00637182c6d5411512f456218ee59fa1f81" # Use a personal acces
|
|||||||
|
|
||||||
def redmine_get_wiki_pages():
|
def redmine_get_wiki_pages():
|
||||||
"""Get all wiki pages from Redmine project"""
|
"""Get all wiki pages from Redmine project"""
|
||||||
# First get the list of pages
|
# First get the list of pages and their parent information
|
||||||
index_url = f"{REDMINE_URL}/projects/{PROJECT_ID}/wiki/index.xml"
|
index_url = f"{REDMINE_URL}/projects/{PROJECT_ID}/wiki/index.xml"
|
||||||
headers = {"X-Redmine-API-Key": REDMINE_API_KEY}
|
headers = {"X-Redmine-API-Key": REDMINE_API_KEY}
|
||||||
response = requests.get(index_url, headers=headers)
|
response = requests.get(index_url, headers=headers)
|
||||||
@@ -35,11 +36,16 @@ def redmine_get_wiki_pages():
|
|||||||
soup = BeautifulSoup(response.content, "xml")
|
soup = BeautifulSoup(response.content, "xml")
|
||||||
pages = []
|
pages = []
|
||||||
|
|
||||||
# Get all page titles from the index
|
|
||||||
for page in soup.find_all("wiki_page"):
|
for page in soup.find_all("wiki_page"):
|
||||||
title = page.find("title").text
|
title = page.find("title").text
|
||||||
logger.info(f"Found page: {title}")
|
parent = page.find('parent')
|
||||||
|
if parent:
|
||||||
|
parent = parent['title']
|
||||||
|
else:
|
||||||
|
parent = None # Root level pages have no parent
|
||||||
|
|
||||||
|
logger.info(f"Found page: {title} (Parent: {parent})")
|
||||||
|
|
||||||
# Fetch individual page content
|
# Fetch individual page content
|
||||||
page_url = f"{REDMINE_URL}/projects/{PROJECT_ID}/wiki/{title}.xml"
|
page_url = f"{REDMINE_URL}/projects/{PROJECT_ID}/wiki/{title}.xml"
|
||||||
try:
|
try:
|
||||||
@@ -49,23 +55,36 @@ def redmine_get_wiki_pages():
|
|||||||
page_soup = BeautifulSoup(page_response.content, "xml")
|
page_soup = BeautifulSoup(page_response.content, "xml")
|
||||||
content = page_soup.find("text").text if page_soup.find("text") else ""
|
content = page_soup.find("text").text if page_soup.find("text") else ""
|
||||||
|
|
||||||
pages.append({"title": title, "content": content})
|
pages.append({"title": title, "parent": parent, "content": content})
|
||||||
logger.info(f"Fetched content for: {title}")
|
logger.info(f"Fetched content for: {title}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning(f"Failed to fetch content for page '{title}': {e}")
|
logger.warning(f"Failed to fetch content for page '{title}': {e}")
|
||||||
# Add empty content if fetch fails
|
# Add empty content if fetch fails
|
||||||
pages.append({"title": title, "content": ""})
|
pages.append({"title": title, "parent": parent, "content": ""})
|
||||||
|
|
||||||
return pages
|
return pages
|
||||||
|
|
||||||
|
def redmine_markup_to_markdown(content, pages):
|
||||||
|
"""Convert Redmine wiki markup to Markdown"""
|
||||||
|
|
||||||
def redmine_markup_to_markdown(content):
|
# Convert links - handle both [[page]] and [page] syntax
|
||||||
"""Convert Redmine wiki markup (textile) to Markdown"""
|
def replace_link(match):
|
||||||
# Replace Redmine-specific syntax to Markdown
|
link = match.group(1)
|
||||||
|
|
||||||
# Handle child_pages macro - remove it since we're importing all pages
|
if link in pages: # Ensure the linked page exists
|
||||||
content = re.sub(r'\{\{child_pages(?:\([^)]*\))?\}\}', '', content)
|
# Create a relative path based on parent-child hierarchy
|
||||||
|
href = f"{pages[link]['title'].replace(' ', '_')}.md"
|
||||||
|
|
||||||
|
return f"[{link}]({href})"
|
||||||
|
|
||||||
|
else:
|
||||||
|
logger.warning(f"Linked page not found: {link}")
|
||||||
|
# Return original link if linked page not found
|
||||||
|
return match.group()
|
||||||
|
|
||||||
|
# Replace [[page]] with [page](page_url)
|
||||||
|
content = re.sub(r'\[\[(.*?)\]\]', replace_link, content)
|
||||||
|
|
||||||
# Convert bold (strong in textile)
|
# Convert bold (strong in textile)
|
||||||
content = re.sub(r'\*\*(.*?)\*\*', r'**\1**', content)
|
content = re.sub(r'\*\*(.*?)\*\*', r'**\1**', content)
|
||||||
content = re.sub(r'\*(.*?)\*', r'*\1*', content)
|
content = re.sub(r'\*(.*?)\*', r'*\1*', content)
|
||||||
@@ -82,10 +101,6 @@ def redmine_markup_to_markdown(content):
|
|||||||
content = re.sub(r'^\s*\* (.*?)$', r'- \1', content, flags=re.MULTILINE)
|
content = re.sub(r'^\s*\* (.*?)$', r'- \1', content, flags=re.MULTILINE)
|
||||||
content = re.sub(r'^\s*\# (.*?)$', r'1. \1', content, flags=re.MULTILINE)
|
content = re.sub(r'^\s*\# (.*?)$', r'1. \1', content, flags=re.MULTILINE)
|
||||||
|
|
||||||
# Convert links - handle both [[page]] and [page] syntax
|
|
||||||
content = re.sub(r'\[\[(.*?)\]\]', r'[\1](\1)', content) # Simple link
|
|
||||||
content = re.sub(r'\[(.*?)\](.*?)\]', r'[\1](\2)', content) # [text](url)
|
|
||||||
|
|
||||||
# Convert images - handle !image! and 
|
# Convert images - handle !image! and 
|
||||||
content = re.sub(r'!\[(.*?)\]\((.*?)\)', r'', content)
|
content = re.sub(r'!\[(.*?)\]\((.*?)\)', r'', content)
|
||||||
content = re.sub(r'!(.*?)!', r'', content)
|
content = re.sub(r'!(.*?)!', r'', content)
|
||||||
@@ -104,6 +119,28 @@ def redmine_markup_to_markdown(content):
|
|||||||
|
|
||||||
return content
|
return content
|
||||||
|
|
||||||
|
def download_image(image_url, local_dir):
|
||||||
|
"""Download an image from Redmine and save it locally"""
|
||||||
|
try:
|
||||||
|
headers = {"X-Redmine-API-Key": REDMINE_API_KEY}
|
||||||
|
response = requests.get(f"{REDMINE_URL}{image_url}", headers=headers)
|
||||||
|
response.raise_for_status()
|
||||||
|
|
||||||
|
# Extract filename from URL
|
||||||
|
filename = os.path.basename(image_url)
|
||||||
|
filepath = os.path.join(local_dir, "images", filename)
|
||||||
|
|
||||||
|
# Create images directory if it doesn't exist
|
||||||
|
os.makedirs(os.path.dirname(filepath), exist_ok=True)
|
||||||
|
|
||||||
|
with open(filepath, 'wb') as f:
|
||||||
|
f.write(response.content)
|
||||||
|
|
||||||
|
logger.info(f"Downloaded image: {filename}")
|
||||||
|
return f"./images/{filename}"
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f"Failed to download image from {image_url}: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
def clone_or_init_wiki_repo(repo_url, local_dir):
|
def clone_or_init_wiki_repo(repo_url, local_dir):
|
||||||
"""Clone or initialize the Gitea wiki repo"""
|
"""Clone or initialize the Gitea wiki repo"""
|
||||||
@@ -114,11 +151,14 @@ def clone_or_init_wiki_repo(repo_url, local_dir):
|
|||||||
logger.info(f"Using existing local wiki repo: {local_dir}")
|
logger.info(f"Using existing local wiki repo: {local_dir}")
|
||||||
os.chdir(local_dir)
|
os.chdir(local_dir)
|
||||||
subprocess.run(["git", "pull"], check=True)
|
subprocess.run(["git", "pull"], check=True)
|
||||||
|
os.chdir('..')
|
||||||
return local_dir
|
return local_dir
|
||||||
|
|
||||||
|
|
||||||
def push_to_gitea_wiki(local_dir, pages):
|
def push_to_gitea_wiki(local_dir, pages):
|
||||||
"""Add pages as Markdown files and push to Gitea"""
|
"""Add pages as Markdown files and push to Gitea"""
|
||||||
|
page_map = {page['title']: page for page in pages} # Map titles to their data
|
||||||
|
curr_dir = os.getcwd()
|
||||||
|
logger.info(f"We are in: {curr_dir}")
|
||||||
# Remove all existing files in the repo (except .git folder)
|
# Remove all existing files in the repo (except .git folder)
|
||||||
for item in os.listdir(local_dir):
|
for item in os.listdir(local_dir):
|
||||||
if item != '.git':
|
if item != '.git':
|
||||||
@@ -128,43 +168,94 @@ def push_to_gitea_wiki(local_dir, pages):
|
|||||||
elif os.path.isdir(item_path):
|
elif os.path.isdir(item_path):
|
||||||
import shutil
|
import shutil
|
||||||
shutil.rmtree(item_path)
|
shutil.rmtree(item_path)
|
||||||
|
|
||||||
# Create pages as .md files
|
# Create pages as .md files
|
||||||
for page in pages:
|
for page in pages:
|
||||||
filename = f"{page['title'].replace(' ', '_')}.md"
|
title = page['title']
|
||||||
|
parent = page.get('parent')
|
||||||
|
|
||||||
|
if title == 'Wiki':
|
||||||
|
filename = "Home.md"
|
||||||
|
else:
|
||||||
|
filename = f"{title.replace(' ', '_')}.md"
|
||||||
|
|
||||||
filepath = os.path.join(local_dir, filename)
|
filepath = os.path.join(local_dir, filename)
|
||||||
|
|
||||||
# Convert content to Markdown
|
if parent and parent in page_map:
|
||||||
markdown_content = redmine_markup_to_markdown(page['content'])
|
# If this page has a parent, create relative path from the parent's directory
|
||||||
|
parent_filename = f"{parent.replace(' ', '_')}.md"
|
||||||
|
parent_filepath = os.path.join(local_dir, parent_filename)
|
||||||
|
|
||||||
|
if os.path.exists(parent_filepath):
|
||||||
|
# Parent directory exists, create subdirectory for this page
|
||||||
|
page_subdir = os.path.dirname(filepath)
|
||||||
|
os.makedirs(page_subdir, exist_ok=True)
|
||||||
|
|
||||||
|
else:
|
||||||
|
# This is a root level page, no need to create subdirectories
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Convert content to Markdown and handle links
|
||||||
|
markdown_content = redmine_markup_to_markdown(page['content'], page_map)
|
||||||
|
|
||||||
|
# Find all images in the content to log them
|
||||||
|
image_pattern = r'!(.*?)!'
|
||||||
|
found_images = re.findall(image_pattern, markdown_content)
|
||||||
|
if found_images:
|
||||||
|
logger.info(f"Found images on page '{title}': {found_images}")
|
||||||
|
|
||||||
|
# Download images referenced in the content
|
||||||
|
# First, we need to find all image URLs and download them
|
||||||
|
# Look for Redmine-style image tags like !image.png!
|
||||||
|
def replace_image(match):
|
||||||
|
image_name = match.group(1)
|
||||||
|
|
||||||
|
# Try to find the actual image URL by searching for it in the page content
|
||||||
|
# This is a simplified approach - we'll assume the image name matches
|
||||||
|
# what's found in Redmine's image system
|
||||||
|
if image_name:
|
||||||
|
# In Redmine, images are usually at /attachments/... path
|
||||||
|
image_url = f"/attachments/download/{image_name}"
|
||||||
|
logger.info(f"Attempting to download image: {image_name}")
|
||||||
|
|
||||||
|
downloaded_path = download_image(image_url, local_dir)
|
||||||
|
if downloaded_path:
|
||||||
|
return f""
|
||||||
|
else:
|
||||||
|
# If download fails, keep the original format
|
||||||
|
return f"!{image_name}!"
|
||||||
|
return match.group(0)
|
||||||
|
|
||||||
|
# We need to handle both !image.png! and  formats
|
||||||
|
# For now, we'll process !image.png! patterns specifically
|
||||||
|
markdown_content = re.sub(image_pattern, replace_image, markdown_content)
|
||||||
|
|
||||||
# Write to file
|
# Write to file
|
||||||
with open(filepath, 'w', encoding='utf-8') as f:
|
with open(filepath, 'w', encoding='utf-8') as f:
|
||||||
f.write(f"# {page['title']}\n\n")
|
f.write(f"# {title}\n\n")
|
||||||
f.write(markdown_content)
|
f.write(markdown_content)
|
||||||
|
|
||||||
logger.info(f"Saved page: {filename}")
|
logger.info(f"Saved page: {filename}")
|
||||||
|
|
||||||
# Add, commit, and push
|
# Add, commit, and push
|
||||||
os.chdir(local_dir)
|
os.chdir(local_dir)
|
||||||
subprocess.run(["git", "add", "."], check=True)
|
subprocess.run(["git", "add", "."], check=True)
|
||||||
subprocess.run(["git", "commit", "-m", "ImportRedminewikipages"], check=True)
|
subprocess.run(["git", "commit", "-m", "'Import Redmine wiki pages'"], check=False)
|
||||||
subprocess.run(["git", "push", "origin", "main"], check=True)
|
subprocess.run(["git", "push", "origin", "main"], check=True)
|
||||||
|
|
||||||
logger.info("✅ Wiki pages pushed to Gitea!")
|
logger.info("✅ Wiki pages pushed to Gitea!")
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
# Step 1: Get wiki pages from Redmine
|
# Step 1: Get wiki pages from Redmine
|
||||||
logger.info("Fetching Redmine wiki pages...")
|
logger.info("Fetching Redmine wiki pages...")
|
||||||
pages = redmine_get_wiki_pages()
|
pages = redmine_get_wiki_pages()
|
||||||
|
|
||||||
# Step 2: Prepare local directory for Gitea wiki
|
# Step 2: Prepare local directory for Gitea wiki
|
||||||
local_wiki_dir = "gitea_wiki_clone"
|
local_wiki_dir = "gitea_wiki_clone"
|
||||||
clone_or_init_wiki_repo(GITEA_WIKI_URL, local_wiki_dir)
|
clone_or_init_wiki_repo(GITEA_WIKI_URL, local_wiki_dir)
|
||||||
|
|
||||||
# Step 3: Push pages to Gitea
|
# Step 3: Push pages to Gitea
|
||||||
push_to_gitea_wiki(local_wiki_dir, pages)
|
push_to_gitea_wiki(local_wiki_dir, pages)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
Reference in New Issue
Block a user