1 | import * as path from 'path'
|
2 | import { _since } from '@naturalcycles/js-lib'
|
3 | import * as cpFile from 'cp-file'
|
4 | import * as fs from 'fs-extra'
|
5 | import * as moveFile from 'move-file'
|
6 | import { boldWhite, dimGrey, grey, yellow } from '../colors'
|
7 | import { globby } from '../index'
|
8 |
|
9 |
|
10 |
|
11 |
|
12 | export interface KpyOptions {
|
13 | |
14 |
|
15 |
|
16 | baseDir: string
|
17 |
|
18 | |
19 |
|
20 |
|
21 | inputPatterns?: string[]
|
22 |
|
23 | |
24 |
|
25 |
|
26 | outputDir: string
|
27 |
|
28 | silent?: boolean
|
29 | verbose?: boolean
|
30 |
|
31 | |
32 |
|
33 |
|
34 |
|
35 |
|
36 | noOverwrite?: boolean
|
37 |
|
38 | dotfiles?: boolean
|
39 | flat?: boolean
|
40 | dry?: boolean
|
41 |
|
42 | |
43 |
|
44 |
|
45 | move?: boolean
|
46 | }
|
47 |
|
48 | export async function kpy(opt: KpyOptions): Promise<void> {
|
49 | const started = Date.now()
|
50 |
|
51 | kpyPrepare(opt)
|
52 |
|
53 | const filenames = await globby(opt.inputPatterns!, {
|
54 | cwd: opt.baseDir,
|
55 | dot: opt.dotfiles,
|
56 | })
|
57 |
|
58 | kpyLogFilenames(opt, filenames)
|
59 |
|
60 | const overwrite = !opt.noOverwrite
|
61 |
|
62 | await Promise.all(
|
63 | filenames.map(async filename => {
|
64 | const basename = path.basename(filename)
|
65 | const srcFilename = path.resolve(opt.baseDir, filename)
|
66 | const destFilename = path.resolve(opt.outputDir, opt.flat ? basename : filename)
|
67 |
|
68 | if (!opt.dry) {
|
69 | if (opt.move) {
|
70 | await moveFile(srcFilename, destFilename, { overwrite })
|
71 | } else {
|
72 | await cpFile(srcFilename, destFilename, { overwrite })
|
73 | }
|
74 | }
|
75 |
|
76 | if (opt.verbose) {
|
77 | console.log(grey(` ${filename}`))
|
78 | }
|
79 | }),
|
80 | )
|
81 |
|
82 | kpyLogResult(opt, filenames, started)
|
83 | }
|
84 |
|
85 | export function kpySync(opt: KpyOptions): void {
|
86 | const started = Date.now()
|
87 |
|
88 | kpyPrepare(opt)
|
89 |
|
90 | const filenames = globby.sync(opt.inputPatterns!, {
|
91 | cwd: opt.baseDir,
|
92 | dot: opt.dotfiles,
|
93 | })
|
94 |
|
95 | kpyLogFilenames(opt, filenames)
|
96 |
|
97 | const overwrite = !opt.noOverwrite
|
98 |
|
99 | filenames.forEach(filename => {
|
100 | const basename = path.basename(filename)
|
101 | const srcFilename = path.resolve(opt.baseDir, filename)
|
102 | const destFilename = path.resolve(opt.outputDir, opt.flat ? basename : filename)
|
103 |
|
104 | if (!opt.dry) {
|
105 | if (opt.move) {
|
106 | moveFile.sync(srcFilename, destFilename, { overwrite })
|
107 | } else {
|
108 | cpFile.sync(srcFilename, destFilename, { overwrite })
|
109 | }
|
110 | }
|
111 |
|
112 | if (opt.verbose) {
|
113 | console.log(grey(` ${filename}`))
|
114 | }
|
115 | })
|
116 |
|
117 | kpyLogResult(opt, filenames, started)
|
118 | }
|
119 |
|
120 | function kpyPrepare(opt: KpyOptions): void {
|
121 |
|
122 | if (!opt.inputPatterns?.length) opt.inputPatterns = ['**']
|
123 |
|
124 |
|
125 | opt.baseDir ||= '.'
|
126 | opt.outputDir ||= '.'
|
127 |
|
128 | if (!fs.existsSync(opt.baseDir)) {
|
129 | console.log(`kpy: baseDir doesn't exist: ${boldWhite(opt.baseDir)}`)
|
130 | return
|
131 | }
|
132 |
|
133 | fs.ensureDirSync(opt.outputDir)
|
134 | }
|
135 |
|
136 | function kpyLogFilenames(opt: KpyOptions, filenames: string[]): void {
|
137 | if (opt.silent) return
|
138 |
|
139 |
|
140 | console.log(
|
141 | `Will ${opt.move ? 'move' : 'copy'} ${yellow(filenames.length)} files from ${dimGrey(
|
142 | opt.baseDir,
|
143 | )} to ${dimGrey(opt.outputDir)} (${dimGrey(opt.inputPatterns!.join(' '))})`,
|
144 | )
|
145 | }
|
146 |
|
147 | function kpyLogResult(opt: KpyOptions, filenames: string[], started: number): void {
|
148 | if (opt.silent || filenames.length === 0) return
|
149 |
|
150 | console.log(
|
151 | `${opt.move ? 'Moved' : 'Copied'} ${yellow(filenames.length)} files to ${dimGrey(
|
152 | opt.outputDir,
|
153 | )} ${dimGrey(_since(started))}`,
|
154 | )
|
155 | }
|