DeL-TaiseiOzaki's picture
Update app.py
05b4d6c verified
raw
history blame
5.68 kB
# 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"
)