-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathinit.ts
More file actions
136 lines (121 loc) · 3.57 KB
/
init.ts
File metadata and controls
136 lines (121 loc) · 3.57 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
import path from 'node:path'
import { homedir, tmpdir } from 'node:os'
import fs from 'fs-extra'
import { downloadTemplate } from 'giget'
import type { InitContext, InitOptions } from './types.js'
import { generate } from './templates.js'
export interface InitFlags {
offline?: boolean
}
const resolveTemplateCacheDir = (template: string): string => {
return path.join(homedir(), '.picgo/templates', template.replace(/[/:]/g, '-'))
}
const toGigetSource = (input: string): string => {
if (/^(https?:\/\/)/.test(input) || input.includes(':')) {
return input
}
return `github:${input}`
}
const makeWritable = (target: string): void => {
if (!fs.existsSync(target)) {
return
}
try {
const stats = fs.lstatSync(target)
if (stats.isDirectory()) {
fs.chmodSync(target, 0o777)
for (const entry of fs.readdirSync(target)) {
makeWritable(path.join(target, entry))
}
} else {
fs.chmodSync(target, 0o666)
}
} catch {
// best-effort; ignore permission errors here
}
}
const removeTemplateDir = (ctx: InitContext, target: string): boolean => {
if (!fs.existsSync(target)) {
return true
}
try {
fs.rmSync(target, { recursive: true, force: true })
return true
} catch {
// fallthrough
}
try {
makeWritable(target)
fs.rmSync(target, { recursive: true, force: true })
return true
} catch (removeError) {
ctx.log.warn(`Failed to clean template cache at ${target}: ${String(removeError)}`)
return false
}
}
const createTempDownloadDir = (): string => {
const cacheRoot = path.join(homedir(), '.picgo/templates')
try {
fs.ensureDirSync(cacheRoot)
return fs.mkdtempSync(path.join(cacheRoot, 'picgo-init-'))
} catch {
return fs.mkdtempSync(path.join(tmpdir(), 'picgo-init-'))
}
}
const createInitOptions = (template: string, project: string | undefined, flags: InitFlags): InitOptions => {
const hasSlash = template.includes('/')
const inPlace = !project || project === '.'
const dest = path.resolve(project || '.')
const offline = Boolean(flags.offline)
const tmp = resolveTemplateCacheDir(template)
const templatePath = offline ? tmp : template
return {
template: templatePath,
project,
hasSlash,
inPlace,
dest,
tmp,
offline
}
}
const downloadAndGenerate = async (ctx: InitContext, options: InitOptions): Promise<void> => {
const cleaned = removeTemplateDir(ctx, options.tmp)
const downloadDir = cleaned ? options.tmp : createTempDownloadDir()
if (!cleaned) {
ctx.log.warn(`Using temporary directory for template download: ${downloadDir}`)
}
ctx.log.info('Template files are downloading...')
const source = toGigetSource(options.template)
try {
await downloadTemplate(source, {
dir: downloadDir,
forceClean: true,
force: true,
silent: true
})
ctx.log.success('Template files are downloaded!')
await generate(ctx, {
...options,
tmp: downloadDir
})
} catch (error) {
ctx.log.error(error instanceof Error ? error : String(error))
}
}
const runInit = async (ctx: InitContext, options: InitOptions): Promise<void> => {
if (options.offline) {
if (fs.existsSync(options.template)) {
await generate(ctx, options)
} else {
ctx.log.error(`Local template ${options.template} not found`)
}
return
}
const resolved = {
...options,
template: options.hasSlash ? options.template : `PicGo/picgo-template-${options.template}`
}
await downloadAndGenerate(ctx, resolved)
}
export { createInitOptions, resolveTemplateCacheDir, runInit, toGigetSource }