rootless-config 1.6.3 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/cli/commands/migrate.js +35 -10
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/*-------- rootless migrate — moves existing root configs into .root container --------*/
|
|
2
2
|
|
|
3
3
|
import path from 'node:path'
|
|
4
|
-
import { readdir, unlink } from 'node:fs/promises'
|
|
4
|
+
import { readdir, unlink, cp, rm } from 'node:fs/promises'
|
|
5
5
|
import { createLogger } from '../../utils/logger.js'
|
|
6
6
|
import { fileExists, ensureDir, atomicWrite, copyFile, readJsonFile } from '../../utils/fsUtils.js'
|
|
7
7
|
import { confirm } from '../../utils/prompt.js'
|
|
@@ -12,6 +12,15 @@ const SYSTEM_FILES = new Set([
|
|
|
12
12
|
'.DS_Store', 'Thumbs.db', 'desktop.ini', '.git', '.svn',
|
|
13
13
|
])
|
|
14
14
|
|
|
15
|
+
// Directories that must never be migrated
|
|
16
|
+
const NEVER_MIGRATE_DIRS = new Set([
|
|
17
|
+
'node_modules', '.git', '.svn', '.hg', '.root',
|
|
18
|
+
'dist', 'build', 'out', '.next', '.nuxt', '.output',
|
|
19
|
+
'.github', '.gitlab', '.circleci',
|
|
20
|
+
'.vscode', '.idea', '.vs',
|
|
21
|
+
'__pycache__', '.cache', '.parcel-cache', '.turbo',
|
|
22
|
+
])
|
|
23
|
+
|
|
15
24
|
/**
|
|
16
25
|
* Determine which .root sub-folder a file should land in:
|
|
17
26
|
* env/ — .env* files (always copied to root by prepare)
|
|
@@ -25,21 +34,21 @@ function getDestSubdir(filename) {
|
|
|
25
34
|
}
|
|
26
35
|
|
|
27
36
|
/**
|
|
28
|
-
* Returns ALL files in projectRoot that should be migrated.
|
|
29
|
-
* Excludes:
|
|
37
|
+
* Returns ALL files AND directories in projectRoot that should be migrated.
|
|
38
|
+
* Excludes: package manager locks, OS noise, VCS dirs, build outputs, editor dirs.
|
|
30
39
|
*/
|
|
31
40
|
async function findMigratableFiles(projectRoot) {
|
|
32
41
|
const entries = await readdir(projectRoot, { withFileTypes: true })
|
|
33
42
|
return entries
|
|
34
43
|
.filter(e => {
|
|
35
|
-
if (!e.isFile()) return false
|
|
36
44
|
if (NEVER_MIGRATE.has(e.name)) return false
|
|
37
45
|
if (SYSTEM_FILES.has(e.name)) return false
|
|
38
46
|
if (e.name === '.root') return false
|
|
39
|
-
|
|
47
|
+
if (e.isDirectory()) return !NEVER_MIGRATE_DIRS.has(e.name)
|
|
48
|
+
return e.isFile()
|
|
40
49
|
})
|
|
41
|
-
.map(e => e.name)
|
|
42
|
-
.sort()
|
|
50
|
+
.map(e => ({ name: e.name, isDir: e.isDirectory() }))
|
|
51
|
+
.sort((a, b) => a.name.localeCompare(b.name))
|
|
43
52
|
}
|
|
44
53
|
|
|
45
54
|
async function getProjectMode(containerPath) {
|
|
@@ -68,7 +77,10 @@ export default {
|
|
|
68
77
|
return
|
|
69
78
|
}
|
|
70
79
|
|
|
71
|
-
|
|
80
|
+
const fileCount = candidates.filter(c => !c.isDir).length
|
|
81
|
+
const dirCount = candidates.filter(c => c.isDir).length
|
|
82
|
+
const summary = candidates.map(c => c.isDir ? `${c.name}/` : c.name).join('\n ')
|
|
83
|
+
logger.info(`Found ${fileCount} files + ${dirCount} directories to migrate:\n ${summary}`)
|
|
72
84
|
|
|
73
85
|
if (isCleanMode) {
|
|
74
86
|
logger.info('Mode: clean — originals will be DELETED from root, package.json scripts will be patched')
|
|
@@ -82,14 +94,27 @@ export default {
|
|
|
82
94
|
return
|
|
83
95
|
}
|
|
84
96
|
|
|
85
|
-
for (const name of candidates) {
|
|
97
|
+
for (const { name, isDir } of candidates) {
|
|
86
98
|
const src = path.join(projectRoot, name)
|
|
87
|
-
|
|
99
|
+
// Directories always go to assets/; files use normal routing
|
|
100
|
+
const destSubdir = isDir ? 'assets' : getDestSubdir(name)
|
|
88
101
|
const destDir = path.join(containerPath, destSubdir)
|
|
89
102
|
|
|
90
103
|
await ensureDir(destDir)
|
|
91
104
|
const dest = path.join(destDir, name)
|
|
92
105
|
|
|
106
|
+
if (isDir) {
|
|
107
|
+
// Recursively copy entire directory tree, then delete source
|
|
108
|
+
await cp(src, dest, { recursive: true })
|
|
109
|
+
if (isCleanMode) {
|
|
110
|
+
await rm(src, { recursive: true, force: true })
|
|
111
|
+
logger.success(`Moved dir .root/${destSubdir}/${name}/ (deleted from root)`)
|
|
112
|
+
} else {
|
|
113
|
+
logger.success(`Copied dir .root/${destSubdir}/${name}/`)
|
|
114
|
+
}
|
|
115
|
+
continue
|
|
116
|
+
}
|
|
117
|
+
|
|
93
118
|
if (isCleanMode) {
|
|
94
119
|
// Binary-safe stream copy — works for .png, .js, .css, etc.
|
|
95
120
|
await copyFile(src, dest)
|