mirror of https://github.com/buster-so/buster.git
Refactor .env file copying script to implement custom gitignore handling
This update enhances the script by replacing the glob-based search for .env files with a custom directory traversal method that respects .gitignore rules. The new implementation allows for more precise control over which files are included, improving the script's functionality in various project structures.
This commit is contained in:
parent
9aed7a612e
commit
83952f4554
|
@ -1,22 +1,128 @@
|
|||
#!/usr/bin/env tsx
|
||||
|
||||
import { promises as fs } from 'node:fs';
|
||||
import { join, relative, dirname } from 'node:path';
|
||||
import { glob } from 'glob';
|
||||
import { join, relative, dirname, basename } from 'node:path';
|
||||
|
||||
const SOURCE_REPO = join(process.env.HOME!, 'buster', 'buster');
|
||||
const TARGET_REPO = process.cwd();
|
||||
|
||||
interface GitignoreRules {
|
||||
patterns: string[];
|
||||
directory: string;
|
||||
}
|
||||
|
||||
// Simple gitignore pattern matcher
|
||||
function matchesGitignorePattern(path: string, pattern: string): boolean {
|
||||
// Remove leading/trailing slashes
|
||||
pattern = pattern.trim();
|
||||
if (pattern.startsWith('#') || pattern === '') return false;
|
||||
|
||||
const isNegation = pattern.startsWith('!');
|
||||
if (isNegation) pattern = pattern.slice(1);
|
||||
|
||||
// Handle directory-only patterns (ending with /)
|
||||
const isDirPattern = pattern.endsWith('/');
|
||||
if (isDirPattern) pattern = pattern.slice(0, -1);
|
||||
|
||||
// Simple glob matching (basic implementation)
|
||||
// Convert pattern to regex
|
||||
let regexPattern = pattern
|
||||
.replace(/\./g, '\\.')
|
||||
.replace(/\*/g, '[^/]*')
|
||||
.replace(/\?/g, '[^/]')
|
||||
.replace(/\*\*/g, '.*');
|
||||
|
||||
// If pattern doesn't start with /, it can match anywhere
|
||||
if (!pattern.startsWith('/')) {
|
||||
regexPattern = `(^|/)${regexPattern}`;
|
||||
} else {
|
||||
regexPattern = `^${regexPattern.slice(1)}`;
|
||||
}
|
||||
|
||||
if (isDirPattern) {
|
||||
regexPattern += '(/|$)';
|
||||
} else {
|
||||
regexPattern += '(/|$)';
|
||||
}
|
||||
|
||||
const regex = new RegExp(regexPattern);
|
||||
const matches = regex.test(path);
|
||||
|
||||
return isNegation ? !matches : matches;
|
||||
}
|
||||
|
||||
async function loadGitignoreRules(dir: string): Promise<string[]> {
|
||||
try {
|
||||
const gitignorePath = join(dir, '.gitignore');
|
||||
const content = await fs.readFile(gitignorePath, 'utf-8');
|
||||
return content
|
||||
.split('\n')
|
||||
.map(line => line.trim())
|
||||
.filter(line => line && !line.startsWith('#'));
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
function isIgnored(path: string, gitignoreStack: GitignoreRules[]): boolean {
|
||||
for (const rules of gitignoreStack) {
|
||||
const relativePath = relative(rules.directory, path);
|
||||
if (relativePath && !relativePath.startsWith('..')) {
|
||||
for (const pattern of rules.patterns) {
|
||||
if (matchesGitignorePattern(relativePath, pattern)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
async function findEnvFiles(dir: string, baseDir: string = dir): Promise<string[]> {
|
||||
const envFiles: string[] = [];
|
||||
|
||||
async function walkDir(currentDir: string, gitignoreStack: GitignoreRules[]) {
|
||||
try {
|
||||
// Load gitignore rules for current directory
|
||||
const localRules = await loadGitignoreRules(currentDir);
|
||||
if (localRules.length > 0) {
|
||||
gitignoreStack = [...gitignoreStack, { patterns: localRules, directory: currentDir }];
|
||||
}
|
||||
|
||||
const entries = await fs.readdir(currentDir, { withFileTypes: true });
|
||||
|
||||
for (const entry of entries) {
|
||||
const fullPath = join(currentDir, entry.name);
|
||||
const relativePath = relative(baseDir, fullPath);
|
||||
|
||||
// Check if this path is ignored
|
||||
if (isIgnored(fullPath, gitignoreStack)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (entry.isDirectory()) {
|
||||
// Always skip .git directory
|
||||
if (entry.name === '.git') continue;
|
||||
await walkDir(fullPath, gitignoreStack);
|
||||
} else if (entry.name.startsWith('.env')) {
|
||||
envFiles.push(relativePath);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
// Skip directories we can't read
|
||||
console.warn(`Skipping directory: ${currentDir}`);
|
||||
}
|
||||
}
|
||||
|
||||
await walkDir(dir, []);
|
||||
return envFiles;
|
||||
}
|
||||
|
||||
async function copyEnvFiles() {
|
||||
try {
|
||||
console.info(`Searching for .env files in ${SOURCE_REPO}...`);
|
||||
|
||||
const envFiles = await glob('**/.env*', {
|
||||
cwd: SOURCE_REPO,
|
||||
absolute: false,
|
||||
dot: true,
|
||||
ignore: ['**/node_modules/**', '**/.git/**']
|
||||
});
|
||||
const envFiles = await findEnvFiles(SOURCE_REPO);
|
||||
|
||||
if (envFiles.length === 0) {
|
||||
console.warn('No .env files found in source repository');
|
||||
|
|
Loading…
Reference in New Issue