init claude-code
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
import { appendFile, mkdir, readFile, writeFile } from 'fs/promises'
|
||||
import { homedir } from 'os'
|
||||
import { dirname, join } from 'path'
|
||||
import { getCwd } from '../cwd.js'
|
||||
import { getErrnoCode } from '../errors.js'
|
||||
import { execFileNoThrowWithCwd } from '../execFileNoThrow.js'
|
||||
import { dirIsInGitRepo } from '../git.js'
|
||||
import { logError } from '../log.js'
|
||||
|
||||
/**
|
||||
* Checks if a path is ignored by git (via `git check-ignore`).
|
||||
*
|
||||
* This consults all applicable gitignore sources: repo `.gitignore` files
|
||||
* (nested), `.git/info/exclude`, and the global gitignore — with correct
|
||||
* precedence, because git itself resolves it.
|
||||
*
|
||||
* Exit codes: 0 = ignored, 1 = not ignored, 128 = not in a git repo.
|
||||
* Returns `false` for 128, so callers outside a git repo fail open.
|
||||
*
|
||||
* @param filePath The path to check (absolute or relative to cwd)
|
||||
* @param cwd The working directory to run git from
|
||||
*/
|
||||
export async function isPathGitignored(
|
||||
filePath: string,
|
||||
cwd: string,
|
||||
): Promise<boolean> {
|
||||
const { code } = await execFileNoThrowWithCwd(
|
||||
'git',
|
||||
['check-ignore', filePath],
|
||||
{
|
||||
preserveOutputOnError: false,
|
||||
cwd,
|
||||
},
|
||||
)
|
||||
|
||||
return code === 0
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the path to the global gitignore file (.config/git/ignore)
|
||||
* @returns The path to the global gitignore file
|
||||
*/
|
||||
export function getGlobalGitignorePath(): string {
|
||||
return join(homedir(), '.config', 'git', 'ignore')
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a file pattern to the global gitignore file (.config/git/ignore)
|
||||
* if it's not already ignored by existing patterns in any gitignore file
|
||||
* @param filename The filename to add to gitignore
|
||||
* @param cwd The current working directory (optional)
|
||||
*/
|
||||
export async function addFileGlobRuleToGitignore(
|
||||
filename: string,
|
||||
cwd: string = getCwd(),
|
||||
): Promise<void> {
|
||||
try {
|
||||
if (!(await dirIsInGitRepo(cwd))) {
|
||||
return
|
||||
}
|
||||
|
||||
// First check if the pattern is already ignored by any gitignore file (including global)
|
||||
const gitignoreEntry = `**/${filename}`
|
||||
// For directory patterns (ending with /), check with a sample file inside
|
||||
const testPath = filename.endsWith('/')
|
||||
? `${filename}sample-file.txt`
|
||||
: filename
|
||||
if (await isPathGitignored(testPath, cwd)) {
|
||||
// File is already ignored by existing patterns (local or global)
|
||||
return
|
||||
}
|
||||
|
||||
// Use the global gitignore file in .config/git/ignore
|
||||
const globalGitignorePath = getGlobalGitignorePath()
|
||||
|
||||
// Create the directory if it doesn't exist
|
||||
const configGitDir = dirname(globalGitignorePath)
|
||||
await mkdir(configGitDir, { recursive: true })
|
||||
|
||||
// Add the entry to the global gitignore
|
||||
try {
|
||||
const content = await readFile(globalGitignorePath, { encoding: 'utf-8' })
|
||||
if (content.includes(gitignoreEntry)) {
|
||||
return // Pattern already exists, don't add again
|
||||
}
|
||||
await appendFile(globalGitignorePath, `\n${gitignoreEntry}\n`)
|
||||
} catch (e: unknown) {
|
||||
const code = getErrnoCode(e)
|
||||
if (code === 'ENOENT') {
|
||||
// Create global gitignore with entry
|
||||
await writeFile(globalGitignorePath, `${gitignoreEntry}\n`, 'utf-8')
|
||||
} else {
|
||||
throw e
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
logError(error)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user