# -*- coding: utf-8 -*-
"""SLUY_20250509_00.ipynb

Automatically generated by Colab.

Original file is located at
    https://colab.research.google.com/drive/13uiSZL4KNWfAxk_BJk-8MjvLcEzfiXbX

# SymlinksUtility
シンボリックリンクを生成します。


```
2025/05/10 0.1.0 完成
2025/05/10 0.1.1 バグ取り
```
---

# SymlinksUility

## 1. モジュール定義
"""

# @title a. SymlinksUtility 定義
import os, sys, shutil, logging
from pathlib import Path

logger = logging.getLogger(__name__)
# 他スクリプトから import される場合に備えて handler チェック
if not logger.hasHandlers():
    logging.basicConfig(
        level=logging.INFO,
        format="%(asctime)s [%(levelname)s] %(name)s: %(message)s",
        force=True
    )

class SymlinksUtility:
    def __init__(self, gd_root: Path, sd_root: Path):
        """
        SymlinksUtility コンストラクタ
        - gd_root: Google Drive 側の root パス
        - sd_root: SD WebUI 側の root パス
        """
        self.gd_root = Path(gd_root)
        self.sd_root = Path(sd_root)

        # フォルダペア：SD側 → GDrive側のフォルダ名
        self.folder_pairs = {
            "models/Stable-diffusion":  "CheckPoint",
            "models/Lora":              "Lora",
            "models/VAE":               "VAE",
            "models/ESRGAN":            "ESRGAN",
            "models/ControlNet":        "ControlNet",
            "models/hypernetworks":     "hypernetworks",
            "models/embeddings":        "embeddings",
            "models/extensions":        "extensions"
        }

        # ファイルペア：SD側 → GDrive側のファイル名
        self.file_pairs = {
            "Config/config.json":       "config.json",
            "Config/styles.csv":        "styles.csv",
            "Config/webui-user.sh":     "webui-user.sh"
        }

    def _create_symlink(self, sd_path: Path, gd_path: Path, is_dir: bool = False):
        """シンボリックリンクを作成（既存削除含む）"""
        if sd_path.exists() or sd_path.is_symlink():
            if sd_path.is_dir() and not sd_path.is_symlink():
                shutil.rmtree(sd_path)
            else:
                sd_path.unlink()
            logger.info(f"既存 {'フォルダ' if is_dir else 'ファイル'} 削除: {sd_path}")

        sd_path.parent.mkdir(parents=True, exist_ok=True)
        sd_path.symlink_to(gd_path, target_is_directory=is_dir)
        logger.info(f"シンボリックリンク作成: {sd_path} → {gd_path}")

    def _initialize_file(self, gd_file: Path, default_content: str = ""):
        """必要に応じて Google Drive 側に初期ファイルを作成"""
        gd_file.parent.mkdir(parents=True, exist_ok=True)  # ← これを追加
        if not gd_file.exists():
            gd_file.write_text(default_content, encoding='utf-8')
            logger.info(f"初期ファイル作成: {gd_file}")

    def create_symlinks(self):
        """ファイル＆フォルダのシンボリックリンク作成"""
        logger.info("=== ファイルのシンボリックリンク作成 ===")
        for sd_rel, gd_rel in self.file_pairs.items():
            sd_file = self.sd_root / sd_rel
            gd_file = self.gd_root / gd_rel

            if gd_file.name == "config.json":
                self._initialize_file(gd_file, "{}")
            elif gd_file.name == "styles.csv":
                self._initialize_file(gd_file, "")
            elif gd_file.name == "webui-user.sh":
                # webui-user.sh は別クラスで初期化する場合
                WebUIUserShHandler().ensure_file(gd_file)

            self._create_symlink(sd_file, gd_file, is_dir=False)

        logger.info("=== フォルダのシンボリックリンク作成 ===")
        for sd_rel, gd_rel in self.folder_pairs.items():
            sd_dir = self.sd_root / sd_rel
            gd_dir = self.gd_root / gd_rel
            if not gd_dir.exists():
                gd_dir.mkdir(parents=True)
                logger.info(f"GoogleDrive 側フォルダ作成: {gd_dir}")
            self._create_symlink(sd_dir, gd_dir, is_dir=True)

# @title b. WebUIUserShHandler 定義
import logging
from pathlib import Path

logger = logging.getLogger(__name__)
if not logger.hasHandlers():
    logging.basicConfig(
        level=logging.INFO,
        format="%(asctime)s [%(levelname)s] %(name)s: %(message)s",
        force=True
    )

try:
    from an_envmanager import EnvManager
except ImportError:
    get_ipython().system( "pip install an_EnvManager" )
    from an_envmanager import EnvManager

class WebUIUserShHandler:
    def __init__(self):
        """
        webui-user.sh の初期ファイル作成を担当
        """
        self.envmanager   = EnvManager(env_files=["settings_sdm.env"])
        # self.sd_repo_folder     = str( self.envmanager.get_env_var("Sdm_repo_folder") )
        self.models_hub_folder  = self.envmanager.get_env_var("Sdm_models_hub_folder")
        logger.info(f"models_hub_folder: { self.models_hub_folder }")

    def ensure_file( self, path: Path ):
        """
        webui-user.sh の初期ファイル作成
        args:
            path( Path ): ファイルパス
        """
        if not path.exists():
            # 必要ならデフォルト内容をここに書く
            default_file = self.models_hub_folder.joinpath("default", "webui-user.sh")
            logger.info( f"default_file( webui-user.sh ): { default_file }" )
            if not default_file.exists():
                raise FileNotFoundError(f"デフォルトファイルが見つかりません: {default_file}")
            default_content = default_file.read_text(encoding='utf-8')
            path.write_text(default_content, encoding='utf-8')
            logger.info(f"webui-user.sh を初期化ファイルとして作成: {path}")

"""## 2. テスト"""

import shutil

try:
    from an_envmanager import EnvManager
except ImportError:
    get_ipython().system( "pip install an_EnvManager" )
    from an_envmanager import EnvManager
try:
    from an_easyven import EasyVen
except ImportError:
    get_ipython().system( "pip install an_EasyVen" )
    from an_easyven import EasyVen
try:
    from an_toolkit import ToolKit
except ImportError:
    get_ipython().system( "pip install an_ToolKit" )
    from an_toolkit import ToolKit

logger = logging.getLogger(__name__)
# 他スクリプトから import される場合に備えて handler チェック
if not logger.hasHandlers():
    logging.basicConfig(
        level=logging.INFO,
        format="%(asctime)s [%(levelname)s] %(name)s: %(message)s",
        force=True
    )

class MainLoop:
    def __init__( self, venv_name ):
        self.venv_name = venv_name
        # 仮想環境のセットアップ
        self.even = EasyVen()
        ( self.bch_path,
          self.dst_path,
          self.cur_path,
          self.src_path,
          self.arc_path,
          self.arz_path,
          self.lcl_path,
          self.bin_path,
          self.lib_path,
          self.tmp_path,
          self.org_path,
          self.orz_path,
          self.enva_path,
          self.envb_path,
          self.uni_path ) = self.even.setup(venv_name=self.venv_name)

        # シンボリックリンクと環境変数マネージャ
        self.envmanager   = EnvManager(env_files=["settings_sdm.env"])
        # 各種ツール初期化
        # self.quickviper             = QuickViper3(venv_name=self.venv_name)
        self.repo_url_sd            = "https://github.com/AUTOMATIC1111/stable-diffusion-webui.git"
        self.target_dir_sd          = Path( self.tmp_path ) / "StableDiffusionWebUI"
        self.req_path_sd            = Path( self.target_dir_sd ) / "requirements.txt"
        self.req_path_sd_versions   = Path( self.target_dir_sd ) / "requirements_versions.txt"
        self.python_path            = self.bin_path / "python"
        self.stable_tag             = "v1.10.1"
        self.toolkit                = ToolKit()
        # self.toolkit.executor(cmd=["bash", str(self.uni_path), self.venv_name], shell=False)

        self.sd_repo_folder     = str( self.tmp_path.joinpath( self.envmanager.get_env_var("Sdm_repo_folder") ) )
        self.models_hub_folder  = self.envmanager.get_env_var("Sdm_models_hub_folder")
        logger.info(f"sd_repo_folder   : { self.sd_repo_folder }")
        logger.info(f"models_hub_folder: { self.models_hub_folder }")
        self.symlinks_util = SymlinksUtility( self.sd_repo_folder, self.models_hub_folder )

    def clone_repository(self):
        """
        リポジトリクローン＆サブモジュール更新
        """
        if (self.target_dir_sd / ".git").exists():
            logger.info("Repository already cloned, skipping clone")
            return
        parent_dir = self.target_dir_sd.parent              # リポジトリのクローニングには、親フォルダが存在していることが必要
        if not parent_dir.exists():
            parent_dir.mkdir(parents=True, exist_ok=True)
        if self.target_dir_sd.exists():
            shutil.rmtree(self.target_dir_sd)
        self.target_dir_sd.mkdir( parents=True, exist_ok=True )
        # クローンコマンド生成
        if self.stable_tag is not None:
            cmd = [
                "git", "clone",
                "--branch", self.stable_tag,
                "--depth", "1",
                "--recursive",
                str( self.repo_url_sd ), str(self.target_dir_sd)
            ]
        else:
            cmd = ["git", "clone", "--recursive", str( self.repo_url_sd ), str(self.target_dir_sd)]

        logger.info(f"Running git clone: {' '.join(cmd)}")
        # 実行
        self.toolkit.executor_sync(cmd=cmd, shell=False)
        logger.info("Repository cloned successfully.")
        # サブモジュール更新
        cwd = os.getcwd()
        os.chdir(str(self.target_dir_sd))
        subm_cmd = ["git", "submodule", "update", "--init", "--recursive"]
        self.toolkit.executor_sync(cmd=subm_cmd, shell=False)
        logger.info("Submodules updated successfully.")
        os.chdir(cwd)

    def run( self ):
        self.clone_repository()
        self.symlinks_util.create_symlinks()



if __name__ == "__main__":
    import logging
    logging.basicConfig(
        level=logging.INFO,
        format='%(asctime)s [%(levelname)s] %(name)s: %(message)s',
        force=True
    )
    mainloop = MainLoop( venv_name = "sd_env")
    mainloop.run()