From df8fb68a1d3ae817e8ad5584c4d33850035e91c9 Mon Sep 17 00:00:00 2001 From: yenru0 Date: Tue, 5 May 2026 20:04:07 +0900 Subject: [PATCH] refactoring stage 5 - fix export command --- run.py | 144 ++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 86 insertions(+), 58 deletions(-) diff --git a/run.py b/run.py index 089e389..8b1c6a5 100755 --- a/run.py +++ b/run.py @@ -207,6 +207,17 @@ class Language(Enum): case _: return Language.UNDEFINED + @staticmethod + def languages() -> list["Language"]: + return [ + Language.PYTHON, + Language.C, + Language.CPP, + Language.RUST, + Language.KOTLIN, + Language.LUA, + ] + def _dispatch_target(target: str) -> tuple[str, str, Language]: splited = target.split("/") @@ -341,7 +352,12 @@ class StorageManager: return None def save_file( - self, location: str, lang: Language, filename: str, content: bytes, completed: bool + self, + location: str, + lang: Language, + filename: str, + content: bytes, + completed: bool, ) -> None: path = STORAGE_DIR / location / lang.value / ("completed" if completed else "") os.makedirs(path, exist_ok=True) @@ -392,6 +408,18 @@ class StorageManager: if os.path.isfile(completed_file): os.rename(completed_file, uncompleted_file) + @staticmethod + def construct_target_path( + location: str, lang: Language, filename: str, completed: bool + ) -> pathlib.Path: + return ( + STORAGE_DIR + / location + / lang.value + / ("completed" if completed else "") + / f"{filename}.{lang.value}" + ) + # ======================= # MAIN CLI LOGIC @@ -482,7 +510,7 @@ def create(target: str, completed: bool, template: bool, force: bool): @click.argument("lang", type=str, nargs=1, required=True) @click.option("--testcase", "-t", default=["1"], multiple=True) @click.option("--verbose/--no-verbose", "-v/-nv", default=True) -def run(lang: str, testcase: list[str], verbose: bool): +def run(lang: str, testcase: tuple[str, ...], verbose: bool): """ 지정된 언어로 빌드 및 실행하는 명령어 """ @@ -500,6 +528,7 @@ def run(lang: str, testcase: list[str], verbose: bool): ) # 테케 분석 + testcase: list[str] = list(testcase) tcs: list[int] = _parse_range_string_list(testcase) # build @@ -608,73 +637,72 @@ def load(target: str, force: bool): @click.command(name="export") -@click.option("--from", "from_", type=str, required=True) +@click.argument("from", "from_", type=str, nargs=-1) @click.option( - "--completed/--no-completed", "-c/-nc", is_flag=True, flag_value=False, default=None + "--all", "all_", default=False, is_flag=True, help="Export all files in the space" ) -@click.option("--copy", is_flag=True, help="is copy from state or move") -def export(from_: str, completed: bool, copy: bool): - # Language 알기 - from_language = Language.convert_name(from_) +@click.option( + "--force", + "-f", + is_flag=True, + help="Overwrite existing file in storage if it already exists", +) +def export(from_: tuple[str, ...], all_: bool, force: bool): + """ + space에 있는 파일을 storage의 각 location으로 이동시키는 명령. + """ - if from_language is Language.UNDEFINED: - raise click.ClickException("Undefined Language Exception") - try: - with open("state.yml", "r", encoding="utf-8") as f: - state = yaml.safe_load(f) - except FileNotFoundError as e: - raise click.ClickException(e) - except yaml.YAMLError as e: - raise click.ClickException(e) + def _export_sub_command(from_language: Language): + space = StateManager().get_space(from_language) - if "space" not in state: - raise click.ClickException("State(state.yml) Exception") - elif not state["space"]: - click.secho("state.space has no member", fg="yellow", bold=True) - state["space"] = {} - - lang_space_state: dict | None - if from_language.value not in state["space"]: - lang_space_state = None - else: - lang_space_state = state["space"][from_language.value] - - if lang_space_state is None or not lang_space_state: - raise click.ClickException("Export Exception: There are no pre-defined state") - - s_file = lang_space_state["file"] - s_loc = lang_space_state["location"] - s_is_completed = lang_space_state["is_completed"] - - if not s_file: - raise click.ClickException( - f"Export Exception: There is no file in {from_language.value} space" + s_file, s_loc, s_is_completed = ( + space["file"], + space["location"], + space["is_completed"], ) - if not s_loc: - raise click.ClickException(f"Export Exception: Location {s_loc} is not defined") + path = StorageManager.construct_target_path( + s_loc, from_language, s_file, s_is_completed + ) - if completed: - s_is_completed = True + if path.is_file() and not force: + raise click.ClickException( + f"File '{path.name}' already exists in location '{s_loc}'. Use --force to overwrite." + ) - dest_path: str = f"{STORAGE_DIR}/{s_loc}/{from_language.value}{'/completed' if s_is_completed else ''}/{s_file}.{from_language.value}" - source_path: str = ( - f"{SRC_SPACE_DIR}/src-{from_language.value}/src/main.{from_language.value}" - ) + src_path = ( + SRC_SPACE_DIR + / f"src-{from_language.value}" + / "src" + / f"main.{from_language.value}" + ) - os.makedirs(os.path.dirname(dest_path), exist_ok=True) + with open(src_path, "rb") as f_src: + content = f_src.read() - with open(source_path, "rb") as f_src, open(dest_path, "wb") as f_dst: - f_dst.write(f_src.read()) + StorageManager().save_file( + s_loc, from_language, s_file, content, s_is_completed + ) + click.secho( + f"Exported '{s_file}.{from_language.value}' to location '{s_loc}'", + fg="cyan", + bold=True, + ) - click.echo(f"File {s_file}.{from_language.value} successfully ") - - if not copy: - with open("state.yml", "w", encoding="utf-8") as f: - state["space"][from_language.value] = {} - yaml.safe_dump(state, f) - - os.remove(source_path) + if all_: + for l in Language.languages(): + if StateManager().check_space(l): + _export_sub_command(l) + else: + froms = map(lambda x: Language.convert_name(x), from_) + for l in froms: + if not StateManager().check_space(l): + click.secho( + f"No loaded file for language '{l.value}' in space. Skipping export for this language.", + fg="yellow", + ) + continue + _export_sub_command(l) @click.command(name="state")