DeL-TaiseiOzaki commited on
Commit
9970b5c
·
verified ·
1 Parent(s): 681ede6

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +65 -37
app.py CHANGED
@@ -1,53 +1,86 @@
1
  # app.py
2
 
3
  import streamlit as st
 
 
4
  from pathlib import Path
 
5
  from core.file_scanner import FileScanner, FileInfo
6
 
7
- # セッション状態を初期化
 
8
  if 'scanned_files' not in st.session_state:
9
- st.session_state.scanned_files = [] # List[FileInfo]
10
  if 'selected_files' not in st.session_state:
11
- st.session_state.selected_files = set() # {Path} 相対パス or 絶対パス
 
 
12
 
13
- st.title("指定拡張子のみディレクトリスキャン & 選択ダウンロード")
14
 
15
- # --- 1) ユーザー入力: スキャンしたいローカルディレクトリパス ---
16
- dir_path_str = st.text_input("ローカルディレクトリパス", value=".")
17
 
18
- # --- 2) ユーザー入力: スキャン対象拡張子選択 ---
19
  st.subheader("スキャン対象拡張子")
20
  available_exts = [".py", ".js", ".ts", ".md", ".txt", ".java", ".cpp"]
21
  chosen_exts = []
22
  for ext in available_exts:
23
- if st.checkbox(ext, key=f"ext_{ext}", value=(ext in [".py", ".md"])):
 
24
  chosen_exts.append(ext)
25
 
26
- # --- 3) 「スキャン実行」ボタン ---
27
  if st.button("スキャン開始"):
28
- base_path = Path(dir_path_str).resolve()
29
- if not base_path.is_dir():
30
- st.error("有効なディレクトリを指定してください")
31
  else:
32
- scanner = FileScanner(base_path, set(chosen_exts))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  found_files = scanner.scan_files()
34
 
 
35
  st.session_state.scanned_files = found_files
36
- st.session_state.selected_files = set() # スキャン毎に選択リセット
37
 
38
- st.success(f"スキャン完了: {len(found_files)}個のファイル")
39
 
40
- # --- 4) ファイルを表示するUI(ディレクトリ構造 or リスト) + 全選択 / 全解除 ---
 
 
 
 
 
 
 
 
 
41
 
 
 
42
  if st.session_state.scanned_files:
43
- # 全選択 / 全解除ボタン
 
44
  col1, col2 = st.columns(2)
45
-
46
  with col1:
47
  if st.button("すべて選択"):
48
- # すべてのファイルを選択
49
- base_path = Path(dir_path_str).resolve()
50
- # relative_to で相対パスを使うか、絶対パスを使うかは好みでOK
51
  st.session_state.selected_files = {
52
  f.path.relative_to(base_path) for f in st.session_state.scanned_files
53
  }
@@ -55,32 +88,27 @@ if st.session_state.scanned_files:
55
  if st.button("すべて解除"):
56
  st.session_state.selected_files = set()
57
 
58
- st.write("### ファイル一覧 (指定拡張子のみ)")
59
- base_path = Path(dir_path_str).resolve()
60
-
61
  for file_info in st.session_state.scanned_files:
62
- # 相対パスで扱う例
63
  rel_path = file_info.path.relative_to(base_path)
64
  checked = (rel_path in st.session_state.selected_files)
65
 
66
- # チェックボックス + ファイル名表示
67
  new_checked = st.checkbox(
68
  f"{rel_path} ({file_info.formatted_size})",
69
  value=checked,
70
- key=str(rel_path) # keyは重複しないように文字列にしておく
71
  )
72
-
73
- # 選択状態を更新
74
  if new_checked:
75
  st.session_state.selected_files.add(rel_path)
76
  else:
77
  st.session_state.selected_files.discard(rel_path)
78
 
79
- # --- 5) 選択ファイルをまとめてMarkdown化 & ダウンロード ---
80
 
 
81
  def create_markdown_for_selected(files, selected_paths, base_dir: Path) -> str:
82
  """
83
- 選択されたファイルだけをMarkdownテキストとして返す
84
  """
85
  output = []
86
  for f in files:
@@ -92,22 +120,22 @@ def create_markdown_for_selected(files, selected_paths, base_dir: Path) -> str:
92
  output.append(f.content)
93
  else:
94
  output.append("# Failed to read content")
95
- output.append("") # 空行
96
 
97
  return "\n".join(output)
98
 
99
  if st.session_state.scanned_files:
100
- st.write("### 選択ファイルをMarkdownダウンロード")
101
- if st.button("選択ファイルをまとめてダウンロード"):
102
- base_path = Path(dir_path_str).resolve()
103
  markdown_text = create_markdown_for_selected(
104
  st.session_state.scanned_files,
105
  st.session_state.selected_files,
106
  base_path
107
  )
108
-
109
  st.download_button(
110
- label="ダウンロード",
111
  data=markdown_text,
112
  file_name="selected_files.md",
113
  mime="text/markdown"
 
1
  # app.py
2
 
3
  import streamlit as st
4
+ import tempfile
5
+ import shutil
6
  from pathlib import Path
7
+ import git # GitPython
8
  from core.file_scanner import FileScanner, FileInfo
9
 
10
+
11
+ # セッション状態の初期化
12
  if 'scanned_files' not in st.session_state:
13
+ st.session_state.scanned_files = [] # スキャンしたFileInfoリスト
14
  if 'selected_files' not in st.session_state:
15
+ st.session_state.selected_files = set() # ユーザーが選択中のファイルパス
16
+ if 'cloned_repo_dir' not in st.session_state:
17
+ st.session_state.cloned_repo_dir = None # クローン先ディレクトリのパス文字列
18
 
19
+ st.title("Gitリポジトリ スキャナー (削除ボタン付き)")
20
 
21
+ # --- 1) ユーザー入力: GitリポジトリURL ---
22
+ repo_url = st.text_input("GitリポジトリURLを入力 (例: https://github.com/username/repo.git)")
23
 
24
+ # --- 2) スキャン対象拡張子の選択 ---
25
  st.subheader("スキャン対象拡張子")
26
  available_exts = [".py", ".js", ".ts", ".md", ".txt", ".java", ".cpp"]
27
  chosen_exts = []
28
  for ext in available_exts:
29
+ default_checked = (ext in [".py", ".md"]) # デモ用に.pyと.mdを初期オン
30
+ if st.checkbox(ext, key=f"ext_{ext}", value=default_checked):
31
  chosen_exts.append(ext)
32
 
33
+ # --- 3) 「スキャン開始」ボタンで clone + scan ---
34
  if st.button("スキャン開始"):
35
+ if not repo_url.strip():
36
+ st.error("リポジトリURLを入力してください")
 
37
  else:
38
+ # 既にクローンしたフォルダがあれば削除
39
+ if st.session_state.cloned_repo_dir and Path(st.session_state.cloned_repo_dir).exists():
40
+ shutil.rmtree(st.session_state.cloned_repo_dir, ignore_errors=True)
41
+
42
+ # 一時フォルダを作成
43
+ tmp_dir = tempfile.mkdtemp()
44
+ clone_path = Path(tmp_dir) / "cloned_repo"
45
+
46
+ st.write(f"リポジトリを一時ディレクトリへクローン中: {clone_path}")
47
+ try:
48
+ git.Repo.clone_from(repo_url, clone_path)
49
+ st.session_state.cloned_repo_dir = str(clone_path)
50
+ except Exception as e:
51
+ st.error(f"クローン失敗: {e}")
52
+ st.stop()
53
+
54
+ # スキャン
55
+ scanner = FileScanner(base_dir=clone_path, target_extensions=set(chosen_exts))
56
  found_files = scanner.scan_files()
57
 
58
+ # スキャン結果をセッションに保存
59
  st.session_state.scanned_files = found_files
60
+ st.session_state.selected_files = set()
61
 
62
+ st.success(f"スキャン完了: {len(found_files)}個のファイルを検出")
63
 
64
+ # --- 4) データ削除ボタン ---
65
+ if st.session_state.cloned_repo_dir:
66
+ # クローンに成功している場合のみ表示
67
+ if st.button("クローン済みリポジトリを削除"):
68
+ # クローン先フォルダを削除
69
+ shutil.rmtree(st.session_state.cloned_repo_dir, ignore_errors=True)
70
+ st.session_state.cloned_repo_dir = None
71
+ st.session_state.scanned_files = []
72
+ st.session_state.selected_files = set()
73
+ st.success("クローンしたデータを削除しました")
74
 
75
+
76
+ # --- 5) スキャン結果の表示 + チェックボックスで選択 ---
77
  if st.session_state.scanned_files:
78
+ st.write("## スキャン結果 (指定拡張子のみ)")
79
+
80
  col1, col2 = st.columns(2)
 
81
  with col1:
82
  if st.button("すべて選択"):
83
+ base_path = Path(st.session_state.cloned_repo_dir)
 
 
84
  st.session_state.selected_files = {
85
  f.path.relative_to(base_path) for f in st.session_state.scanned_files
86
  }
 
88
  if st.button("すべて解除"):
89
  st.session_state.selected_files = set()
90
 
91
+ base_path = Path(st.session_state.cloned_repo_dir)
 
 
92
  for file_info in st.session_state.scanned_files:
 
93
  rel_path = file_info.path.relative_to(base_path)
94
  checked = (rel_path in st.session_state.selected_files)
95
 
96
+ # ファイルのチェックボックスを表示
97
  new_checked = st.checkbox(
98
  f"{rel_path} ({file_info.formatted_size})",
99
  value=checked,
100
+ key=str(rel_path) # key 重複回避のため文字列化
101
  )
 
 
102
  if new_checked:
103
  st.session_state.selected_files.add(rel_path)
104
  else:
105
  st.session_state.selected_files.discard(rel_path)
106
 
 
107
 
108
+ # --- 6) 選択したファイルをまとめてMarkdown化 & ダウンロード ---
109
  def create_markdown_for_selected(files, selected_paths, base_dir: Path) -> str:
110
  """
111
+ 選択されたファイルを1つのMarkdownとして連結。
112
  """
113
  output = []
114
  for f in files:
 
120
  output.append(f.content)
121
  else:
122
  output.append("# Failed to read content")
123
+ output.append("") # ファイルごとに空行
124
 
125
  return "\n".join(output)
126
 
127
  if st.session_state.scanned_files:
128
+ st.write("## 選択ファイルをMarkdownとしてダウンロード")
129
+ if st.button("選択ファイルをダウンロード"):
130
+ base_path = Path(st.session_state.cloned_repo_dir)
131
  markdown_text = create_markdown_for_selected(
132
  st.session_state.scanned_files,
133
  st.session_state.selected_files,
134
  base_path
135
  )
136
+ # ダウンロードボタン
137
  st.download_button(
138
+ label="Markdownダウンロード",
139
  data=markdown_text,
140
  file_name="selected_files.md",
141
  mime="text/markdown"