콘텐츠로 이동

저장소 부트스트랩

dojang init --from SOURCE는 기존 저장소를 새 머신으로 가져오고, 해당 머신을 등록한 다음, 최초 dojang apply를 실행할지 묻습니다. 가져오기 작업은 대상 디렉터리와 같은 상위 디렉터리에 만들고 소유자만 접근할 수 있는 임시 디렉터리에서 진행됩니다. POSIX 시스템은 디렉터리를 만들 때 비공개 모드를 요청한 뒤 다시 적용하므로, 프로세스의 umask가 엄격해도 준비 디렉터리를 사용할 수 없게 되지 않습니다. Windows는 보호되며 하위 항목에 상속되는 소유자 전용 접근 제어 목록(ACL)을 적용합니다. 이 보호를 강제할 수 없는 파일시스템은 거부합니다. Dojang은 준비된 dojang.toml을 확인한 뒤 저장소를 게시하므로, 올바르지 않거나 불완전한 원본이 대상에 아무것도 게시하지 않습니다.

대상 경로는 존재하지 않아야 합니다. 저장소 디렉터리의 기본값은 현재 디렉터리이므로, 부트스트랩할 때는 -r 또는 --repository-dir로 새 경로를 선택하세요. 빈 디렉터리라도 이미 존재하는 경로는 거부합니다. Dojang은 저장된 권한을 저장소가 준비 영역에서 비공개 상태일 때 복원한 뒤, 기존 항목을 대체하지 않는 원자적 디렉터리 rename 한 번으로 게시합니다. 다른 프로세스가 대상 경로를 먼저 만들면 그 항목을 변경하지 않고 게시에 실패합니다. 기존 항목을 대체하지 않는 원자적 rename을 지원하지 않는 파일시스템에서는 항목별 대체 절차를 사용하지 않고 거부합니다. 정리가 필요하면 먼저 준비 트리를 운영체제 난수로 만든 격리 경로로 옮기고, 옮긴 항목의 정체성을 확인합니다. 경쟁 중 바뀐 항목은 삭제하지 않고 원래 경로로 복원합니다. 복원에 실패하면 격리 경로를 그대로 보존하고 복구할 경로를 출력합니다.

로컬 디렉터리와 아카이브

로컬 디렉터리에는 전송 방식 옵션이 필요하지 않습니다.

dojang -r ~/.dotfiles init --from /media/backup/dotfiles

Dojang은 로컬 디렉터리 원본 안에 있는 대상 경로를 준비 영역을 만들기 전에 거부합니다. 원본과 같은 상위 디렉터리의 다른 경로나 서로 겹치지 않는 경로를 선택하세요.

Dojang은 심볼릭 링크를 따라가지 않고 링크로 복사합니다. 디렉터리 원본의 나머지 항목은 정규 파일 또는 디렉터리여야 하며, FIFO, 소켓, 장치를 비롯한 특수 파일은 읽기 전에 거부합니다. 각 디렉터리를 열어 둔 채 항목을 열거하고, 하위 디렉터리는 링크를 따라가지 않는 방식으로 엽니다. 따라서 순회 중 디렉터리가 링크로 바뀌면 그 대상을 훑지 않고 중단하거나 링크 자체를 관측합니다. 항목을 열거한 뒤 그 이름이 사라지면 가져온 스냅샷에서 누락하지 않고 원본의 동시 변경으로 처리합니다. 또한 항목을 복사하기 전에 대소문자 접기 또는 유니코드 정규화 후 충돌하는 원본 경로도 거부합니다. 따라서 대소문자를 구분하는 원본 파일시스템의 서로 다른 이름이 준비 영역에서 하나로 합쳐지지 않습니다. 검사하는 동안 원본 루트와 모든 항목의 정체성을 기록합니다. 디렉터리 권한은 해당 정체성과 같은 파일시스템 관측에서 가져옵니다. 정규 파일은 복사에 사용하는 것과 같은 열린 파일 핸들로 정체성을 확인하며, 복사를 마친 뒤 원본 트리의 항목 목록을 다시 만듭니다. 항목이 추가되거나 삭제되었거나, 타입이 바뀌었거나, 기록한 정체성 및 변경 메타데이터와 더 이상 일치하지 않으면 준비된 사본을 게시하지 않고 중단합니다. .zip, .tar, .tar.gz, .tgz 아카이브도 사용할 수 있습니다.

dojang -r ~/.dotfiles init --from ~/Downloads/dotfiles.tar.gz

아카이브 원본은 정규 파일로 확인되어야 합니다. 정규 아카이브 파일을 가리키는 심볼릭 링크는 허용하지만 FIFO를 비롯한 특수 파일은 읽지 않고 거부합니다. 제한된 읽기를 마치면 열린 아카이브의 변경 메타데이터를 다시 확인합니다. 읽는 동안 아카이브가 바뀌었다면 부트스트랩을 중단하고 안정된 원본으로 다시 시도하도록 안내합니다.

아카이브 항목은 압축을 풀기 전에 검사합니다. 절대 경로, 상위 디렉터리 순회, 역슬래시 경로, 링크, Windows에서 예약되었거나 유효하지 않은 파일 이름 구성 요소, 대소문자 접기 또는 유니코드 정규화 후 충돌하는 항목은 거부합니다. 아카이브에서 생략한 상위 디렉터리도 충돌 검사에 포함합니다. POSIX 시스템에서는 Unix ZIP 항목이 FIFO, 소켓, 장치 또는 그 밖의 지원하지 않는 타입을 선언한 경우에도 정규 파일로 바꾸지 않고 거부합니다. DOS 디렉터리 속성이 표시된 ZIP 디렉터리 항목은 이름 끝에 관례적인 슬래시가 없어도 허용합니다. 아카이브 입력은 16 MiB, 압축을 푼 파일 내용은 64 MiB, 항목 수는 10,000개, 각 항목 경로는 4,096자, 경로 깊이는 256개 구성 요소로 제한합니다. 압축한 tar를 해석할 때도 크기를 제한하므로 올바르지 않거나 압축률이 매우 높거나 비정상적으로 깊은 입력이 리소스를 제한 없이 소비하지 않습니다. POSIX 시스템에서는 실행 권한을 포함하여 아카이브에 저장된 권한 비트를 대상 파일시스템이 지원할 때 복원합니다. 파일시스템 호출이 성공했다는 사실만으로 모든 권한 비트가 복원되었다고 간주하지 않고, 적용 후의 권한을 검사합니다. 정확히 복원할 수 없는 경우에는 내용을 게시하고 권한을 복원하지 못했다는 경고를 출력합니다. 원자적으로 게시하기 전에는 최종 저장 권한을 적용한 상태에서 매니페스트를 다시 읽고 해석합니다. 아카이브의 최종 파일 권한이나 상위 디렉터리 권한 때문에 매니페스트에 접근할 수 없다면 저장소가 아직 비공개 준비 영역에 있을 때 거부합니다. 새 목적지는 디렉터리 원본이나 tar 루트의 권한을 이어받습니다. 디렉터리 원본 자체가 심볼릭 링크라면 링크가 아니라 대상 디렉터리의 권한을 이어받습니다.

외부 전송 방식

Git, HTTPS 클라이언트 같은 네트워크 도구는 머신별 로컬 외부 전송 방식으로 설정합니다. Dojang은 셸을 거치지 않고 설정한 실행 파일을 직접 시작합니다. 원본과 임시 목적지는 각각 하나의 완전한 인자로 전달되므로, 공백과 셸 특수 문자는 명령 문법이 아니라 데이터로 유지됩니다. 외부 전송 방식에 전달하는 목적지는 소유자만 접근할 수 있는 디렉터리의 하위 경로이므로, 가져오는 동안 전송 방식의 기본 권한으로 생성한 파일도 다른 로컬 사용자에게 노출되지 않습니다. POSIX에서는 원본, 준비 대상, 물려받은 환경 변수 값의 파일시스템 바이트 표현을 유니코드로 다시 변환하지 않고 자식 프로세스에 전달합니다.

Dojang은 대상 상위 디렉터리를 한 번 해석하고 준비를 시작하기 전에 그 물리 디렉터리와 모든 조상의 파일시스템 정체성을 기록합니다. 준비, 가져오기, 검사, 게시를 마칠 때마다 어휘적 대상과 전체 물리 디렉터리 사슬을 다시 검사하며, 교체를 관측하면 중단합니다. 이 경계 검사는 원자적 잠금이 아닙니다. 검사와 다음 파일시스템 변경 사이에 경로가 교체되면 준비 영역이나 게시된 사본이 다른 위치에 남을 수 있습니다. 정리 또는 게시 후 검사에서 이 상황을 발견하면 직접 잔여 항목을 삭제할 수 있도록 경고합니다.

기본 설정 파일 경로는 다음과 같습니다.

  • Linux 및 그 밖의 POSIX 시스템:
    • $XDG_CONFIG_HOME/dojang/transports.toml, 또는
    • XDG_CONFIG_HOME이 없거나 상대 경로이면 ~/.config/dojang/transports.toml
  • macOS: ~/Library/Application Support/dojang/transports.toml
  • Windows: %APPDATA%\dojang\transports.toml. APPDATA가 없거나 상대 경로이면 %USERPROFILE%\AppData\Roaming\dojang\transports.toml

다음 예시는 Git 전송 방식을 추가합니다.

[transports.git]
command = ["git", "clone", "--", "{source}", "{destination}"]
inherit-environment = ["HOME", "PATH", "SSH_AUTH_SOCK"]

[transports.git.environment]
GIT_TERMINAL_PROMPT = "1"

각 명령에는 완전한 인자 하나를 차지하는 {source}{destination} 자리 표시자가 정확히 하나씩 있어야 합니다. 실행 파일에는 자리 표시자를 쓸 수 없습니다. 외부 전송 방식은 inherit-environment에 이름을 적지 않은 호스트 환경 변수를 받지 않습니다. environment의 값은 물려받은 값을 덮어씁니다. 이 파일에는 인증 정보를 저장하지 마세요.

전송 방식 이름을 지정하여 사용합니다.

dojang -r ~/.dotfiles init \
  --from git@github.com:USER/dotfiles.git \
  --transport git

다른 설정 파일을 선택하려면 --transport NAME과 함께 --transport-file PATH를 사용합니다. 전송 방식 이름은 대소문자를 구분하고 ASCII 문자로 시작해야 하며, ASCII 문자, 숫자, 하이픈, 밑줄을 쓸 수 있습니다. directoryarchive는 예약된 이름입니다.

머신 등록과 최초 적용

가져온 뒤에는 dojang init이 선언 파일을 확인하고 현재 머신을 등록합니다. 일반 저장소 초기화와 같은 --fact KEY=VALUE--facts-file PATH 옵션을 사용할 수 있습니다. 이어서 저장소를 적용할지 묻습니다. 적용하지 않으면 대상 파일을 바꾸지 않고, 올바르게 등록된 체크아웃만 남습니다.

선택한 선언 파일 경로는 드라이브 접두사가 없는 상대 경로여야 하고 가져온 저장소 안에 있어야 하며, 상위 디렉터리나 심볼릭 링크인 구성 요소를 포함할 수 없습니다. 따라서 준비 영역에서 검사한 선언 파일과 게시 후 머신 등록에서 읽는 선언 파일이 항상 같습니다. 선언 파일은 16 MiB 이하의 정규 파일이어야 합니다. Dojang은 확인된 같은 파일 핸들에서 읽은 바이트를 파싱하며, FIFO나 장치는 읽지 않고 거부하고 읽는 동안 관측된 제자리 변경도 거부합니다.

비대화식 부트스트랩에는 명시적인 승인이 필요합니다.

dojang -r ~/.dotfiles init \
  --from /media/backup/dotfiles.tar.gz \
  --no-interactive \
  --yes

--yes는 최초 변경 적용만 승인합니다. 선언 파일, 머신 정보, 대상 디렉터리, 전송 방식, 아카이브 검사를 건너뛰지 않습니다.

부트스트랩 미리 보기

전역 --dry-run 옵션은 init 앞에 둡니다.

dojang --dry-run -r ~/.dotfiles init --from /media/backup/dotfiles

모의 실행은 저장소를 게시하거나 머신 등록을 저장하거나 파일을 적용하지 않습니다. 대상이 존재하지 않아야 한다는 조건은 실제 실행과 똑같이 적용하고, 가져오기와 게시 과정은 파일시스템을 변경하지 않고 모사합니다. 로컬 디렉터리와 아카이브 원본에서는 가상 게시가 준비 영역 루트와 하위 디렉터리 권한을 보존하므로, 머신 등록과 적용 미리 보기가 실제 이름 변경과 같은 메타데이터를 관찰합니다. 외부 전송 방식에서는 원본 인자와 환경 변수 값을 가린 실행 요청만 출력합니다. 원본의 파일시스템 바이트 표현이 UTF-8이 아니어도 가림 처리를 유지하며 프로그램은 시작하지 않습니다. 따라서 파일을 가져오지 않으며 원격 선언 파일도 확인할 수 없습니다. 실제 부트스트랩을 실행하면 임시 디렉터리에서 선언 파일을 확인합니다.