| 161 | const GIT_SHADOW_EXCLUDE_PATTERNS: &[&str] = &["/.atomic/", "/.vault/", "/.atomicignore"]; |
| 162 | |
| 163 | fn ensure_git_shadow_excludes(git_dir: &Path) -> CliResult<bool> { |
| 164 | let info_dir = git_dir.join("info"); |
| 165 | std::fs::create_dir_all(&info_dir)?; |
| 166 | |
| 167 | let exclude_path = info_dir.join("exclude"); |
| 168 | let mut content = match std::fs::read_to_string(&exclude_path) { |
| 169 | Ok(content) => content, |
| 170 | Err(e) if e.kind() == ErrorKind::NotFound => String::new(), |
| 171 | Err(e) => return Err(e.into()), |
| 172 | }; |
| 173 | |
| 174 | let missing: Vec<&str> = GIT_SHADOW_EXCLUDE_PATTERNS |
| 175 | .iter() |
| 176 | .copied() |
| 177 | .filter(|pattern| !content.lines().any(|line| line.trim() == *pattern)) |
| 178 | .collect(); |
| 179 | |
| 180 | if missing.is_empty() { |
| 181 | return Ok(false); |
| 182 | } |
| 183 | |
| 184 | if !content.is_empty() && !content.ends_with('\n') { |
| 185 | content.push('\n'); |
| 186 | } |
| 187 | if !content.is_empty() { |
| 188 | content.push('\n'); |
| 189 | } |
| 190 | content.push_str("# Atomic local state (managed by atomic git import)\n"); |
| 191 | for pattern in missing { |
| 192 | content.push_str(pattern); |
| 193 | content.push('\n'); |
| 194 | } |
| 195 | |
| 196 | std::fs::write(exclude_path, content)?; |
| 197 | Ok(true) |
| 198 | } |
| 199 | |
| 200 | impl Import { |
| 201 | /// Import a single branch into an Atomic view using parallel processing. |