[Git 만들어보기 - Geet] status 명령어로 개체 상태 출력하기

송준섭 Junseop Song·2024년 3월 18일

Git 만들어보기 - Geet

목록 보기
20/21
post-thumbnail

2024-03-06 구현

status 명령은 이번엔 index를 적극적으로 사용해서 저번에 구현할 때 보다 비교적 쉽게 할 수 있었다.

// geet/command/geetStatus.kt
package geet.command

import geet.enums.StageObjectStatus
import geet.exception.BadRequest
import geet.geetobject.GeetBlob
import geet.util.const.*
import geet.util.getRelativePathFromRoot
import java.io.File

data class StatusObject(  // status 결과로 나오는 개체들의 상태를 나타내는 data class
    val newFiles: MutableList<String> = mutableListOf(),
    val modifiedFiles: MutableList<String> = mutableListOf(),
    val deletedFiles: MutableList<String> = mutableListOf()
)

data class StatusResult(  // status 결과를 나타내는 data class
    val staged: StatusObject,
    val unstaged: StatusObject,
    val untracked: List<String>
)

fun geetStatus(commandLines: Array<String>): Unit {
    if (commandLines.size != 1) {  // 항상 'geet status'와 같은 식으로 입력 받음
        throw BadRequest("status 명령어는 다른 옵션을 가지지 않습니다.: ${red}${commandLines.joinToString(" ")}${resetColor}")
    }

    val statusResult = getStatusResult()
    printStatusResult(statusResult)
}

fun getUntrackedFiles(dir: File): List<String> {  // dir 하위 파일들 중 추적하지 않는 파일들 목록을 얻는 함수
    val untrackedFiles = mutableListOf<String>()
    dir.listFiles()?.forEach {
        if (ignoreManager.isIgnored(it)) {
            return@forEach
        }

        if (it.isDirectory) {
            untrackedFiles.addAll(getUntrackedFiles(it))
        } else {
            val filePath = getRelativePathFromRoot(it)
            val objectInStage = indexManager.searchObjectFromStage(filePath)
            val objectInLastCommit = indexManager.searchObjectFromLastCommit(filePath)

						// 스테이지에도 없고 최근 커밋에도 없으면 추적하지 않는 파일
            if (objectInStage == null && objectInLastCommit == null) {
                untrackedFiles.add(filePath)
            }
        }
    }
    return untrackedFiles
}

fun getStatusResult(): StatusResult {  // 스테이터스 결과를 반환하는 함수
    val statusResult = StatusResult(
        staged = StatusObject(),
        unstaged = StatusObject(),
        untracked = getUntrackedFiles(File("."))
    )

		// 스테이지 개체들로 루프
    indexManager.indexData.stageObjects.forEach { stageObject ->
        val file = File(stageObject.blob.filePath)
        val blob = GeetBlob(content = file.readText(), filePath = getRelativePathFromRoot(file))

        when (stageObject.status) {  // 개체 상태에 따라
            StageObjectStatus.NEW -> {  // 새로운 개체라면
                if (stageObject.blob.hash != blob.hash) {  // 현재 작업 디렉토리와 다르면 언스테이지 목록에도 추가
                    statusResult.unstaged.newFiles.add(stageObject.blob.filePath)
                }
								// 스테이지 목록에 추가
                statusResult.staged.newFiles.add(stageObject.blob.filePath)
            }
            StageObjectStatus.MODIFIED -> {  // 수정된 개체라면
                if (stageObject.blob.hash != blob.hash) {
                    statusResult.unstaged.modifiedFiles.add(stageObject.blob.filePath)
                }

                statusResult.staged.modifiedFiles.add(stageObject.blob.filePath)
            }
						// 삭제된 개체라면 스테이지만 추가(스테이지에 추가되었는데 언스테이지일 수가 없음)
            StageObjectStatus.DELETED -> statusResult.staged.deletedFiles.add(stageObject.blob.filePath)
            else -> return@forEach
        }
    }

		// 스테이지에 추가되지 않은 삭제된 파일들 추가
    indexManager.indexData.lastCommitObjects.forEach { lastCommitObject ->
        val file = File(lastCommitObject.filePath)
        val objectInStage = indexManager.searchObjectFromStage(lastCommitObject.filePath)

				// 파일이 존재하지 않으면서 스테이지에 같은 경로의 개체가 없거나 그 개체의 상태가 새로운 파일 또는 수정된 파일인 경우
        if (!file.exists() && (objectInStage == null || objectInStage.status != DELETED)) {
            statusResult.unstaged.deletedFiles.add(lastCommitObject.filePath)
        }
    }

    return statusResult
}

// StatusResult 토대로 결과 출력
fun printStatusResult(statusResult: StatusResult): Unit {
    println("** 스테이지된 변경사항 **")
    statusResult.staged.newFiles.forEach { println("${green}  새로운 파일: $it${resetColor}") }
    statusResult.staged.modifiedFiles.forEach { println("${green}  수정된 파일: $it${resetColor}") }
    statusResult.staged.deletedFiles.forEach { println("${green}  삭제된 파일: $it${resetColor}") }
    println()

    println("** 스테이지되지 않은 변경사항 **")
    statusResult.unstaged.newFiles.forEach { println("${yellow}  새로운 파일: $it${resetColor}") }
    statusResult.unstaged.modifiedFiles.forEach { println("${yellow}  수정된 파일: $it${resetColor}") }
    statusResult.unstaged.deletedFiles.forEach { println("${yellow}  삭제된 파일: $it${resetColor}") }
    println()

    println("** 추적되지 않는 파일 **")
    statusResult.untracked.forEach { println("${red}  $it${resetColor}") }
    println()
}

0개의 댓글