Spaces:
Sleeping
Sleeping
# app.py | |
import streamlit as st | |
import tempfile | |
import shutil | |
from pathlib import Path | |
import git # GitPython | |
from core.file_scanner import FileScanner, FileInfo | |
# セッション状態の初期化 | |
if 'scanned_files' not in st.session_state: | |
st.session_state.scanned_files = [] # スキャンしたFileInfoリスト | |
if 'selected_files' not in st.session_state: | |
st.session_state.selected_files = set() # ユーザーが選択中のファイルパス | |
if 'cloned_repo_dir' not in st.session_state: | |
st.session_state.cloned_repo_dir = None # クローン先ディレクトリのパス文字列 | |
st.title("Gitリポジトリ スキャナー (削除ボタン付き)") | |
# --- 1) ユーザー入力: GitリポジトリURL --- | |
repo_url = st.text_input("GitリポジトリURLを入力 (例: https://github.com/username/repo.git)") | |
# --- 2) スキャン対象拡張子の選択 --- | |
st.subheader("スキャン対象拡張子") | |
available_exts = [".py", ".js", ".ts", ".md", ".txt", ".java", ".cpp",".sh"] | |
chosen_exts = [] | |
for ext in available_exts: | |
default_checked = (ext in [".py", ".md"]) # デモ用に.pyと.mdを初期オン | |
if st.checkbox(ext, key=f"ext_{ext}", value=default_checked): | |
chosen_exts.append(ext) | |
# --- 3) 「スキャン開始」ボタンで clone + scan --- | |
if st.button("スキャン開始"): | |
if not repo_url.strip(): | |
st.error("リポジトリURLを入力してください") | |
else: | |
# 既にクローンしたフォルダがあれば削除 | |
if st.session_state.cloned_repo_dir and Path(st.session_state.cloned_repo_dir).exists(): | |
shutil.rmtree(st.session_state.cloned_repo_dir, ignore_errors=True) | |
# 一時フォルダを作成 | |
tmp_dir = tempfile.mkdtemp() | |
clone_path = Path(tmp_dir) / "cloned_repo" | |
st.write(f"リポジトリを一時ディレクトリへクローン中: {clone_path}") | |
try: | |
git.Repo.clone_from(repo_url, clone_path) | |
st.session_state.cloned_repo_dir = str(clone_path) | |
except Exception as e: | |
st.error(f"クローン失敗: {e}") | |
st.stop() | |
# スキャン | |
scanner = FileScanner(base_dir=clone_path, target_extensions=set(chosen_exts)) | |
found_files = scanner.scan_files() | |
# スキャン結果をセッションに保存 | |
st.session_state.scanned_files = found_files | |
st.session_state.selected_files = set() | |
st.success(f"スキャン完了: {len(found_files)}個のファイルを検出") | |
# --- 4) データ削除ボタン --- | |
if st.session_state.cloned_repo_dir: | |
# クローンに成功している場合のみ表示 | |
if st.button("クローン済みリポジトリを削除"): | |
# クローン先フォルダを削除 | |
shutil.rmtree(st.session_state.cloned_repo_dir, ignore_errors=True) | |
st.session_state.cloned_repo_dir = None | |
st.session_state.scanned_files = [] | |
st.session_state.selected_files = set() | |
st.success("クローンしたデータを削除しました") | |
# --- 5) スキャン結果の表示 + チェックボックスで選択 --- | |
if st.session_state.scanned_files: | |
st.write("## スキャン結果 (指定拡張子のみ)") | |
col1, col2 = st.columns(2) | |
with col1: | |
if st.button("すべて選択"): | |
base_path = Path(st.session_state.cloned_repo_dir) | |
st.session_state.selected_files = { | |
f.path.relative_to(base_path) for f in st.session_state.scanned_files | |
} | |
with col2: | |
if st.button("すべて解除"): | |
st.session_state.selected_files = set() | |
base_path = Path(st.session_state.cloned_repo_dir) | |
for file_info in st.session_state.scanned_files: | |
rel_path = file_info.path.relative_to(base_path) | |
checked = (rel_path in st.session_state.selected_files) | |
# ファイルのチェックボックスを表示 | |
new_checked = st.checkbox( | |
f"{rel_path} ({file_info.formatted_size})", | |
value=checked, | |
key=str(rel_path) # key 重複回避のため文字列化 | |
) | |
if new_checked: | |
st.session_state.selected_files.add(rel_path) | |
else: | |
st.session_state.selected_files.discard(rel_path) | |
# --- 6) 選択したファイルをまとめてMarkdown化 & ダウンロード --- | |
def create_markdown_for_selected(files, selected_paths, base_dir: Path) -> str: | |
""" | |
選択されたファイルを1つのMarkdownとして連結。 | |
""" | |
output = [] | |
for f in files: | |
rel_path = f.path.relative_to(base_dir) | |
if rel_path in selected_paths: | |
output.append(f"## {rel_path}") | |
output.append("------------") | |
if f.content is not None: | |
output.append(f.content) | |
else: | |
output.append("# Failed to read content") | |
output.append("") # ファイルごとに空行 | |
return "\n".join(output) | |
if st.session_state.scanned_files: | |
st.write("## 選択ファイルをMarkdownとしてダウンロード") | |
if st.button("選択ファイルをダウンロード"): | |
base_path = Path(st.session_state.cloned_repo_dir) | |
markdown_text = create_markdown_for_selected( | |
st.session_state.scanned_files, | |
st.session_state.selected_files, | |
base_path | |
) | |
# ダウンロードボタン | |
st.download_button( | |
label="Markdownダウンロード", | |
data=markdown_text, | |
file_name="selected_files.md", | |
mime="text/markdown" | |
) | |