forked from BetaHuhn/repo-file-sync-action
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathhelpers.js
169 lines (142 loc) · 5 KB
/
helpers.js
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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
import * as fs from 'fs-extra'
import readfiles from 'node-readfiles'
import { exec } from 'child_process'
import * as core from '@actions/core'
import * as path from 'path'
import * as nunjucks from 'nunjucks'
nunjucks.configure({ autoescape: true, trimBlocks: true, lstripBlocks: true })
// From https://github.com/toniov/p-iteration/blob/master/lib/static-methods.js - MIT © Antonio V
export async function forEach(array, callback) {
for (let index = 0; index < array.length; index++) {
// eslint-disable-next-line callback-return
await callback(array[index], index, array)
}
}
// From https://github.com/MartinKolarik/dedent-js/blob/master/src/index.ts - MIT © 2015 Martin Kolárik
export function dedent(templateStrings, ...values) {
const matches = []
const strings = typeof templateStrings === 'string' ? [ templateStrings ] : templateStrings.slice()
strings[strings.length - 1] = strings[strings.length - 1].replace(/\r?\n([\t ]*)$/, '')
for (let i = 0; i < strings.length; i++) {
let match
// eslint-disable-next-line no-cond-assign
if (match = strings[i].match(/\n[\t ]+/g)) {
matches.push(...match)
}
}
if (matches.length) {
const size = Math.min(...matches.map((value) => value.length - 1))
const pattern = new RegExp(`\n[\t ]{${ size }}`, 'g')
for (let i = 0; i < strings.length; i++) {
strings[i] = strings[i].replace(pattern, '\n')
}
}
strings[0] = strings[0].replace(/^\r?\n/, '')
let string = strings[0]
for (let i = 0; i < values.length; i++) {
string += values[i] + strings[i + 1]
}
return string
}
export function execCmd(command, workingDir, trimResult = true) {
core.debug(`EXEC: "${ command }" IN ${ workingDir }`)
return new Promise((resolve, reject) => {
exec(
command,
{
cwd: workingDir,
maxBuffer: 1024 * 1024 * 4
},
function(error, stdout) {
error ? reject(error) : resolve(
trimResult ? stdout.trim() : stdout
)
}
)
})
}
export function addTrailingSlash(str) {
return str.endsWith('/') ? str : str + '/'
}
export async function pathIsDirectory(path) {
const stat = await fs.lstat(path)
return stat.isDirectory()
}
export async function write(src, dest, context) {
if (typeof context !== 'object') {
context = {}
}
const content = nunjucks.render(src, context)
await fs.outputFile(dest, content)
}
export async function copy(src, dest, isDirectory, file) {
const deleteOrphaned = isDirectory && file.deleteOrphaned
const exclude = file.exclude
const filterFunc = (file) => {
if (exclude !== undefined) {
// Check if file-path is one of the present filepaths in the excluded paths
// This has presedence over the single file, and therefore returns before the single file check
let filePath = ''
if (file.endsWith('/')) {
// File item is a folder
filePath = file
} else {
// File item is a file
filePath = file.split('\/').slice(0, -1).join('/') + '/'
}
if (exclude.includes(filePath)) {
core.debug(`Excluding file ${ file } since its path is included as one of the excluded paths.`)
return false
}
// Or if the file itself is in the excluded files
if (exclude.includes(file)) {
core.debug(`Excluding file ${ file } since it is explicitly added in the exclusion list.`)
return false
}
}
return true
}
if (file.template) {
if (isDirectory) {
core.debug(`Render all files in directory ${ src } to ${ dest }`)
const srcFileList = await readfiles(src, { readContents: false, hidden: true })
for (const srcFile of srcFileList) {
if (!filterFunc(srcFile)) { continue }
const srcPath = path.join(src, srcFile)
const destPath = path.join(dest, srcFile)
await write(srcPath, destPath, file.template)
}
} else {
core.debug(`Render file ${ src } to ${ dest }`)
await write(src, dest, file.template)
}
} else {
core.debug(`Copy ${ src } to ${ dest }`)
await fs.copy(src, dest, file.exclude !== undefined && { filter: filterFunc })
}
// If it is a directory and deleteOrphaned is enabled - check if there are any files that were removed from source dir and remove them in destination dir
if (deleteOrphaned) {
const srcFileList = await readfiles(src, { readContents: false, hidden: true })
const destFileList = await readfiles(dest, { readContents: false, hidden: true })
for (const destFile of destFileList) {
if (destFile.startsWith('.git')) return
if (srcFileList.indexOf(destFile) === -1) {
const filePath = path.join(dest, destFile)
core.debug(`Found an orphaned file in the target repo - ${ filePath }`)
if (file.exclude !== undefined && file.exclude.includes(path.join(src, destFile))) {
core.debug(`Excluding file ${ destFile }`)
} else {
core.debug(`Removing file ${ destFile }`)
await fs.remove(filePath)
}
}
}
}
}
export async function remove(src) {
core.debug(`RM: ${ src }`)
return fs.remove(src)
}
export function arrayEquals(array1, array2) {
return Array.isArray(array1) && Array.isArray(array2) && array1.length === array2.length && array1.every((value, i) => value === array2[i])
}