Spaces:
Running
Running
thibaud frere
commited on
Commit
·
91b0400
1
Parent(s):
e01b523
update template sync
Browse files- app/scripts/sync-template.mjs +44 -44
app/scripts/sync-template.mjs
CHANGED
|
@@ -1,13 +1,13 @@
|
|
| 1 |
#!/usr/bin/env node
|
| 2 |
|
| 3 |
/**
|
| 4 |
-
*
|
| 5 |
*
|
| 6 |
-
*
|
| 7 |
-
* 1.
|
| 8 |
-
* 2.
|
| 9 |
-
* 3.
|
| 10 |
-
* 4.
|
| 11 |
*
|
| 12 |
* Usage: npm run sync:template [--dry-run] [--backup] [--force]
|
| 13 |
*/
|
|
@@ -23,26 +23,26 @@ const PROJECT_ROOT = path.resolve(APP_ROOT, '..');
|
|
| 23 |
const TEMP_DIR = path.join(PROJECT_ROOT, '.temp-template-sync');
|
| 24 |
const TEMPLATE_REPO = 'https://huggingface.co/spaces/tfrere/research-article-template';
|
| 25 |
|
| 26 |
-
//
|
| 27 |
const PRESERVE_PATHS = [
|
| 28 |
-
//
|
| 29 |
'app/src/content',
|
| 30 |
|
| 31 |
-
//
|
| 32 |
'app/public/data',
|
| 33 |
|
| 34 |
-
//
|
| 35 |
'app/package-lock.json',
|
| 36 |
'app/node_modules',
|
| 37 |
|
| 38 |
-
//
|
| 39 |
'app/scripts/sync-template.mjs',
|
| 40 |
|
| 41 |
-
//
|
| 42 |
'README.md',
|
| 43 |
'tools',
|
| 44 |
|
| 45 |
-
//
|
| 46 |
'.backup-*',
|
| 47 |
'.temp-*',
|
| 48 |
|
|
@@ -51,7 +51,7 @@ const PRESERVE_PATHS = [
|
|
| 51 |
'.gitignore'
|
| 52 |
];
|
| 53 |
|
| 54 |
-
//
|
| 55 |
const SENSITIVE_FILES = [
|
| 56 |
'app/package.json',
|
| 57 |
'app/astro.config.mjs',
|
|
@@ -61,15 +61,15 @@ const SENSITIVE_FILES = [
|
|
| 61 |
|
| 62 |
const args = process.argv.slice(2);
|
| 63 |
const isDryRun = args.includes('--dry-run');
|
| 64 |
-
const shouldBackup = args.includes('--backup'); //
|
| 65 |
const isForce = args.includes('--force');
|
| 66 |
|
| 67 |
-
console.log('🔄
|
| 68 |
-
console.log(`📁
|
| 69 |
console.log(`🎯 Template source: ${TEMPLATE_REPO}`);
|
| 70 |
-
if (isDryRun) console.log('🔍
|
| 71 |
-
if (shouldBackup) console.log('💾 Backup
|
| 72 |
-
if (!shouldBackup) console.log('🚫 Backup
|
| 73 |
console.log('');
|
| 74 |
|
| 75 |
async function executeCommand(command, options = {}) {
|
|
@@ -86,7 +86,7 @@ async function executeCommand(command, options = {}) {
|
|
| 86 |
});
|
| 87 |
return result;
|
| 88 |
} catch (error) {
|
| 89 |
-
console.error(`❌
|
| 90 |
console.error(error.message);
|
| 91 |
throw error;
|
| 92 |
}
|
|
@@ -116,28 +116,28 @@ async function createBackup(filePath) {
|
|
| 116 |
|
| 117 |
try {
|
| 118 |
await fs.copyFile(filePath, backupPath);
|
| 119 |
-
console.log(`💾 Backup
|
| 120 |
} catch (error) {
|
| 121 |
-
console.warn(`⚠️
|
| 122 |
}
|
| 123 |
}
|
| 124 |
|
| 125 |
async function syncFile(sourcePath, targetPath) {
|
| 126 |
const relativeTarget = path.relative(PROJECT_ROOT, targetPath);
|
| 127 |
|
| 128 |
-
//
|
| 129 |
if (await isPathPreserved(relativeTarget)) {
|
| 130 |
-
console.log(`🔒
|
| 131 |
return;
|
| 132 |
}
|
| 133 |
|
| 134 |
-
//
|
| 135 |
if (SENSITIVE_FILES.includes(relativeTarget)) {
|
| 136 |
if (!isForce) {
|
| 137 |
-
console.log(`⚠️
|
| 138 |
return;
|
| 139 |
} else {
|
| 140 |
-
console.log(`⚠️
|
| 141 |
}
|
| 142 |
}
|
| 143 |
|
|
@@ -154,7 +154,7 @@ async function syncFile(sourcePath, targetPath) {
|
|
| 154 |
}
|
| 155 |
|
| 156 |
if (isDryRun) {
|
| 157 |
-
console.log(`[DRY-RUN]
|
| 158 |
return;
|
| 159 |
}
|
| 160 |
|
|
@@ -165,11 +165,11 @@ async function syncFile(sourcePath, targetPath) {
|
|
| 165 |
try {
|
| 166 |
const sourceStats = await fs.lstat(sourcePath);
|
| 167 |
if (sourceStats.isSymbolicLink()) {
|
| 168 |
-
console.log(`🔗
|
| 169 |
return;
|
| 170 |
}
|
| 171 |
} catch (error) {
|
| 172 |
-
console.warn(`⚠️
|
| 173 |
return;
|
| 174 |
}
|
| 175 |
|
|
@@ -180,7 +180,7 @@ async function syncFile(sourcePath, targetPath) {
|
|
| 180 |
|
| 181 |
// Copier le fichier
|
| 182 |
await fs.copyFile(sourcePath, targetPath);
|
| 183 |
-
console.log(`✅
|
| 184 |
}
|
| 185 |
|
| 186 |
async function syncDirectory(sourceDir, targetDir) {
|
|
@@ -208,7 +208,7 @@ async function syncDirectory(sourceDir, targetDir) {
|
|
| 208 |
}
|
| 209 |
|
| 210 |
async function cloneOrUpdateTemplate() {
|
| 211 |
-
console.log('📥
|
| 212 |
|
| 213 |
// Nettoyer le dossier temporaire s'il existe
|
| 214 |
if (await pathExists(TEMP_DIR)) {
|
|
@@ -226,10 +226,10 @@ async function cloneOrUpdateTemplate() {
|
|
| 226 |
}
|
| 227 |
|
| 228 |
async function showSummary(templateDir) {
|
| 229 |
-
console.log('\n📊
|
| 230 |
console.log('================================');
|
| 231 |
|
| 232 |
-
console.log('\n🔒
|
| 233 |
for (const preserve of PRESERVE_PATHS) {
|
| 234 |
const fullPath = path.join(PROJECT_ROOT, preserve);
|
| 235 |
if (await pathExists(fullPath)) {
|
|
@@ -239,7 +239,7 @@ async function showSummary(templateDir) {
|
|
| 239 |
}
|
| 240 |
}
|
| 241 |
|
| 242 |
-
console.log('\n⚠️
|
| 243 |
for (const sensitive of SENSITIVE_FILES) {
|
| 244 |
const fullPath = path.join(PROJECT_ROOT, sensitive);
|
| 245 |
if (await pathExists(fullPath)) {
|
|
@@ -248,18 +248,18 @@ async function showSummary(templateDir) {
|
|
| 248 |
}
|
| 249 |
|
| 250 |
if (isDryRun) {
|
| 251 |
-
console.log('\n🔍
|
| 252 |
-
console.log('🔧
|
| 253 |
}
|
| 254 |
}
|
| 255 |
|
| 256 |
async function cleanup() {
|
| 257 |
-
console.log('\n🧹
|
| 258 |
if (await pathExists(TEMP_DIR)) {
|
| 259 |
if (!isDryRun) {
|
| 260 |
await fs.rm(TEMP_DIR, { recursive: true, force: true });
|
| 261 |
}
|
| 262 |
-
console.log(`🗑️
|
| 263 |
}
|
| 264 |
}
|
| 265 |
|
|
@@ -281,10 +281,10 @@ async function main() {
|
|
| 281 |
// Afficher le résumé
|
| 282 |
await showSummary(templateDir);
|
| 283 |
|
| 284 |
-
console.log('\n✅
|
| 285 |
|
| 286 |
} catch (error) {
|
| 287 |
-
console.error('\n❌
|
| 288 |
console.error(error.message);
|
| 289 |
process.exit(1);
|
| 290 |
} finally {
|
|
@@ -294,13 +294,13 @@ async function main() {
|
|
| 294 |
|
| 295 |
// Gestion des signaux pour nettoyer en cas d'interruption
|
| 296 |
process.on('SIGINT', async () => {
|
| 297 |
-
console.log('\n\n⚠️ Interruption
|
| 298 |
await cleanup();
|
| 299 |
process.exit(1);
|
| 300 |
});
|
| 301 |
|
| 302 |
process.on('SIGTERM', async () => {
|
| 303 |
-
console.log('\n\n⚠️
|
| 304 |
await cleanup();
|
| 305 |
process.exit(1);
|
| 306 |
});
|
|
|
|
| 1 |
#!/usr/bin/env node
|
| 2 |
|
| 3 |
/**
|
| 4 |
+
* Template synchronization script for research-article-template
|
| 5 |
*
|
| 6 |
+
* This script:
|
| 7 |
+
* 1. Clones or updates the template repo in a temporary directory
|
| 8 |
+
* 2. Copies all files EXCEPT those in ./src/content which contain specific content
|
| 9 |
+
* 3. Preserves important local configuration files
|
| 10 |
+
* 4. Creates backups of files that will be overwritten
|
| 11 |
*
|
| 12 |
* Usage: npm run sync:template [--dry-run] [--backup] [--force]
|
| 13 |
*/
|
|
|
|
| 23 |
const TEMP_DIR = path.join(PROJECT_ROOT, '.temp-template-sync');
|
| 24 |
const TEMPLATE_REPO = 'https://huggingface.co/spaces/tfrere/research-article-template';
|
| 25 |
|
| 26 |
+
// Files and directories to PRESERVE (do not overwrite)
|
| 27 |
const PRESERVE_PATHS = [
|
| 28 |
+
// Project-specific content
|
| 29 |
'app/src/content',
|
| 30 |
|
| 31 |
+
// Public data (symlink to our data)
|
| 32 |
'app/public/data',
|
| 33 |
|
| 34 |
+
// Local configuration
|
| 35 |
'app/package-lock.json',
|
| 36 |
'app/node_modules',
|
| 37 |
|
| 38 |
+
// Project-specific scripts (preserve our sync script)
|
| 39 |
'app/scripts/sync-template.mjs',
|
| 40 |
|
| 41 |
+
// Project configuration files
|
| 42 |
'README.md',
|
| 43 |
'tools',
|
| 44 |
|
| 45 |
+
// Backup and temporary files
|
| 46 |
'.backup-*',
|
| 47 |
'.temp-*',
|
| 48 |
|
|
|
|
| 51 |
'.gitignore'
|
| 52 |
];
|
| 53 |
|
| 54 |
+
// Files to handle with caution (require confirmation)
|
| 55 |
const SENSITIVE_FILES = [
|
| 56 |
'app/package.json',
|
| 57 |
'app/astro.config.mjs',
|
|
|
|
| 61 |
|
| 62 |
const args = process.argv.slice(2);
|
| 63 |
const isDryRun = args.includes('--dry-run');
|
| 64 |
+
const shouldBackup = args.includes('--backup'); // Disabled by default, use --backup to enable
|
| 65 |
const isForce = args.includes('--force');
|
| 66 |
|
| 67 |
+
console.log('🔄 Template synchronization script for research-article-template');
|
| 68 |
+
console.log(`📁 Working directory: ${PROJECT_ROOT}`);
|
| 69 |
console.log(`🎯 Template source: ${TEMPLATE_REPO}`);
|
| 70 |
+
if (isDryRun) console.log('🔍 DRY-RUN mode enabled - no files will be modified');
|
| 71 |
+
if (shouldBackup) console.log('💾 Backup enabled');
|
| 72 |
+
if (!shouldBackup) console.log('🚫 Backup disabled (use --backup to enable)');
|
| 73 |
console.log('');
|
| 74 |
|
| 75 |
async function executeCommand(command, options = {}) {
|
|
|
|
| 86 |
});
|
| 87 |
return result;
|
| 88 |
} catch (error) {
|
| 89 |
+
console.error(`❌ Error during execution: ${command}`);
|
| 90 |
console.error(error.message);
|
| 91 |
throw error;
|
| 92 |
}
|
|
|
|
| 116 |
|
| 117 |
try {
|
| 118 |
await fs.copyFile(filePath, backupPath);
|
| 119 |
+
console.log(`💾 Backup created: ${path.relative(PROJECT_ROOT, backupPath)}`);
|
| 120 |
} catch (error) {
|
| 121 |
+
console.warn(`⚠️ Unable to create backup for ${filePath}: ${error.message}`);
|
| 122 |
}
|
| 123 |
}
|
| 124 |
|
| 125 |
async function syncFile(sourcePath, targetPath) {
|
| 126 |
const relativeTarget = path.relative(PROJECT_ROOT, targetPath);
|
| 127 |
|
| 128 |
+
// Check if the file should be preserved
|
| 129 |
if (await isPathPreserved(relativeTarget)) {
|
| 130 |
+
console.log(`🔒 PRESERVED: ${relativeTarget}`);
|
| 131 |
return;
|
| 132 |
}
|
| 133 |
|
| 134 |
+
// Check if it's a sensitive file
|
| 135 |
if (SENSITIVE_FILES.includes(relativeTarget)) {
|
| 136 |
if (!isForce) {
|
| 137 |
+
console.log(`⚠️ SENSITIVE (ignored): ${relativeTarget} (use --force to overwrite)`);
|
| 138 |
return;
|
| 139 |
} else {
|
| 140 |
+
console.log(`⚠️ SENSITIVE (forced): ${relativeTarget}`);
|
| 141 |
}
|
| 142 |
}
|
| 143 |
|
|
|
|
| 154 |
}
|
| 155 |
|
| 156 |
if (isDryRun) {
|
| 157 |
+
console.log(`[DRY-RUN] COPY: ${relativeTarget}`);
|
| 158 |
return;
|
| 159 |
}
|
| 160 |
|
|
|
|
| 165 |
try {
|
| 166 |
const sourceStats = await fs.lstat(sourcePath);
|
| 167 |
if (sourceStats.isSymbolicLink()) {
|
| 168 |
+
console.log(`🔗 SYMLINK (ignored): ${relativeTarget}`);
|
| 169 |
return;
|
| 170 |
}
|
| 171 |
} catch (error) {
|
| 172 |
+
console.warn(`⚠️ Unable to check source ${sourcePath}: ${error.message}`);
|
| 173 |
return;
|
| 174 |
}
|
| 175 |
|
|
|
|
| 180 |
|
| 181 |
// Copier le fichier
|
| 182 |
await fs.copyFile(sourcePath, targetPath);
|
| 183 |
+
console.log(`✅ COPIED: ${relativeTarget}`);
|
| 184 |
}
|
| 185 |
|
| 186 |
async function syncDirectory(sourceDir, targetDir) {
|
|
|
|
| 208 |
}
|
| 209 |
|
| 210 |
async function cloneOrUpdateTemplate() {
|
| 211 |
+
console.log('📥 Fetching template...');
|
| 212 |
|
| 213 |
// Nettoyer le dossier temporaire s'il existe
|
| 214 |
if (await pathExists(TEMP_DIR)) {
|
|
|
|
| 226 |
}
|
| 227 |
|
| 228 |
async function showSummary(templateDir) {
|
| 229 |
+
console.log('\n📊 SYNCHRONIZATION SUMMARY');
|
| 230 |
console.log('================================');
|
| 231 |
|
| 232 |
+
console.log('\n🔒 Preserved files/directories:');
|
| 233 |
for (const preserve of PRESERVE_PATHS) {
|
| 234 |
const fullPath = path.join(PROJECT_ROOT, preserve);
|
| 235 |
if (await pathExists(fullPath)) {
|
|
|
|
| 239 |
}
|
| 240 |
}
|
| 241 |
|
| 242 |
+
console.log('\n⚠️ Sensitive files (require --force):');
|
| 243 |
for (const sensitive of SENSITIVE_FILES) {
|
| 244 |
const fullPath = path.join(PROJECT_ROOT, sensitive);
|
| 245 |
if (await pathExists(fullPath)) {
|
|
|
|
| 248 |
}
|
| 249 |
|
| 250 |
if (isDryRun) {
|
| 251 |
+
console.log('\n🔍 To execute for real: npm run sync:template');
|
| 252 |
+
console.log('🔧 To force sensitive files: npm run sync:template -- --force');
|
| 253 |
}
|
| 254 |
}
|
| 255 |
|
| 256 |
async function cleanup() {
|
| 257 |
+
console.log('\n🧹 Cleaning up...');
|
| 258 |
if (await pathExists(TEMP_DIR)) {
|
| 259 |
if (!isDryRun) {
|
| 260 |
await fs.rm(TEMP_DIR, { recursive: true, force: true });
|
| 261 |
}
|
| 262 |
+
console.log(`🗑️ Temporary directory removed: ${TEMP_DIR}`);
|
| 263 |
}
|
| 264 |
}
|
| 265 |
|
|
|
|
| 281 |
// Afficher le résumé
|
| 282 |
await showSummary(templateDir);
|
| 283 |
|
| 284 |
+
console.log('\n✅ Synchronization completed!');
|
| 285 |
|
| 286 |
} catch (error) {
|
| 287 |
+
console.error('\n❌ Error during synchronization:');
|
| 288 |
console.error(error.message);
|
| 289 |
process.exit(1);
|
| 290 |
} finally {
|
|
|
|
| 294 |
|
| 295 |
// Gestion des signaux pour nettoyer en cas d'interruption
|
| 296 |
process.on('SIGINT', async () => {
|
| 297 |
+
console.log('\n\n⚠️ Interruption detected, cleaning up...');
|
| 298 |
await cleanup();
|
| 299 |
process.exit(1);
|
| 300 |
});
|
| 301 |
|
| 302 |
process.on('SIGTERM', async () => {
|
| 303 |
+
console.log('\n\n⚠️ Shutdown requested, cleaning up...');
|
| 304 |
await cleanup();
|
| 305 |
process.exit(1);
|
| 306 |
});
|