-
Notifications
You must be signed in to change notification settings - Fork 31
Expand file tree
/
Copy pathproject-files.ts
More file actions
131 lines (113 loc) · 4.19 KB
/
Copy pathproject-files.ts
File metadata and controls
131 lines (113 loc) · 4.19 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
import { ContentMapping } from '@dcl/schemas/dist/misc/content-mapping'
import { CliComponents } from '../components'
import { getDCLIgnorePatterns } from './dcl-ignore'
import { globSync, statSync, Dirent } from 'fs'
import ignore from 'ignore'
import i18next from 'i18next'
import os from 'os'
import path, { resolve } from 'path'
import { CliError } from './error'
export type ProjectFile = {
absolutePath: string
hash: string
}
/**
* Returns an array of the publishable files for a given folder.
*
*/
export async function getPublishableFiles(
components: Pick<CliComponents, 'fs'>,
projectRoot: string
): Promise<Array<string>> {
const ignorePatterns = await getDCLIgnorePatterns(components, projectRoot)
const ig = ignore().add(ignorePatterns)
const allFiles = globSync('**/*', {
cwd: projectRoot,
// prune walking into trees ig.filter below always excludes anyway (perf only;
// exclude receives a string on some Node versions and a Dirent on others)
exclude: (entry: string | Dirent) => {
const name = typeof entry === 'string' ? path.basename(entry) : entry.name
return name.startsWith('.') || name === 'node_modules'
}
})
return ig.filter(allFiles).filter((file) => statSync(resolve(projectRoot, file)).isFile())
}
/**
* This function converts paths to decentraland-compatible paths.
* - From windows separators to unix separators.
* - All to lowercase
*/
export function normalizeDecentralandFilename(projectRoot: string, filename: string) {
const newAbsolute = path.resolve(projectRoot, filename)
const relativePath = path.relative(projectRoot, newAbsolute)
// 1. win->unix style
// 2. remove heading /
return relativePath.replace(/(\\)/g, '/').replace(/^\/+/, '').toLowerCase()
}
/**
* This function normalizes the content mappings of a project to be used by the
* Decentraland file system
*/
export function projectFilesToContentMappings(projectRoot: string, files: ProjectFile[]): ContentMapping[] {
return files.map((file) => {
return {
file: normalizeDecentralandFilename(projectRoot, file.absolutePath),
hash: file.hash
}
})
}
/**
* Returns the content mappings for a specific project folder.
* NOTE: the result of this function IS NOT NORMALIZED. Paths sould be normalized
* with normalizeDecentralandFilename before usage
*
* TODO: Unit test this function
*/
export async function getProjectPublishableFilesWithHashes(
components: Pick<CliComponents, 'fs'>,
projectRoot: string,
hashingFunction: (filePath: string) => Promise<string>
): Promise<ProjectFile[]> {
const projectFiles = await getPublishableFiles(components, projectRoot)
const ret: ProjectFile[] = []
const usedFilenames = new Set<string>()
for (const file of projectFiles) {
const absolutePath = path.resolve(projectRoot, file)
/* istanbul ignore if */
if (!(await components.fs.fileExists(absolutePath))) continue
const normalizedFile = normalizeDecentralandFilename(projectRoot, file)
/* istanbul ignore if */
if (usedFilenames.has(normalizedFile)) {
throw new CliError('PROJECT_FILES_DUPLICATE_FILE', i18next.t('errors.project_files.duplicate_file', { file }))
}
usedFilenames.add(normalizedFile)
ret.push({
absolutePath,
hash: await hashingFunction(absolutePath)
})
}
return ret
}
export const machineId = os.hostname() || os.userInfo().username
export const b64HashingFunction = (str: string) => {
const unique = `${str}-${machineId}`
return 'b64-' + Buffer.from(unique).toString('base64')
}
// export const ipfsHashingFunction = async (str: string) => hashV1(Buffer.from(str, 'utf8'))
interface PackageJson {
dependencies: Record<string, string>
devDependencies: Record<string, string>
}
/* istanbul ignore next */
export async function getPackageJson(components: Pick<CliComponents, 'fs'>, projectRoot: string) {
try {
const packageJsonRaw = await components.fs.readFile(resolve(projectRoot, 'package.json'), 'utf8')
const packageJson = JSON.parse(packageJsonRaw) as PackageJson
return packageJson
} catch (err: any) {
throw new CliError(
'PROJECT_FILES_INVALID_PACKAGE_JSON',
i18next.t('errors.project_files.invalid_package_json', { error: err.message })
)
}
}