UNPKG

3.07 kBJavaScriptView Raw
1const { homedir } = require('os')
2const { resolve, join, sep } = require('path')
3const { cwd: getCwd } = require('process')
4
5const { getCacheDir } = require('./dir')
6
7// Find the paths of the file before/after caching
8const parsePath = async function(path, cacheDir) {
9 const srcPath = getSrcPath(path)
10 const cachePath = await getCachePath(srcPath, cacheDir)
11 return { srcPath, cachePath }
12}
13
14// Retrieve absolute path to the local file to cache/restore
15const getSrcPath = function(path) {
16 const cwd = getCwd()
17 const srcPath = resolve(cwd, path)
18 checkSrcPath(srcPath, cwd)
19 return srcPath
20}
21
22// Caching the whole repository creates many issues:
23// - It caches many directories that are not related to Gatsby but take lots of
24// space, such as node_modules
25// - It caches directories that are not meant to restored across builds. For
26// example .git (beside being big).
27// - It undoes any build operations inside the repository that might have
28// happened before this plugin starts restoring the cache, leading to
29// conflicts with other plugins, Netlify Build or the buildbot.
30const checkSrcPath = function(srcPath, cwd) {
31 if (isParentPath(srcPath, cwd)) {
32 throw new Error(`Cannot cache ${srcPath} because it is the current directory (${cwd}) or a parent directory`)
33 }
34}
35
36// Note: srcPath and cwd are already normalized and absolute
37const isParentPath = function(srcPath, cwd) {
38 return `${cwd}${sep}`.startsWith(`${srcPath}${sep}`)
39}
40
41const getCachePath = async function(srcPath, cacheDir) {
42 const cacheDirA = await getCacheDir(cacheDir)
43 const { name, relPath } = findBase(srcPath)
44 const cachePath = join(cacheDirA, name, relPath)
45 return cachePath
46}
47
48// The cached path is the path relative to the base which can be either the
49// current directory, the home directory or the root directory. Each is tried
50// in order.
51const findBase = function(srcPath) {
52 const srcPathA = normalizeWindows(srcPath)
53 return BASES.map(({ name, base }) => parseBase(name, base, srcPathA)).find(Boolean)
54}
55
56// Windows drives are problematic:
57// - they cannot be used in `relPath` since directories cannot be called `C:`
58// for example.
59// - they make comparing between drives harder
60// For the moment, we simply strip them. This does mean two files with the same
61// paths but inside different drives would be cached together, which is not
62// correct.
63// This also means `cache.list()` always assumes the source files are on the
64// current drive.
65// TODO: fix it.
66const normalizeWindows = function(srcPath) {
67 return srcPath.replace(WINDOWS_DRIVE_REGEX, '\\')
68}
69
70const WINDOWS_DRIVE_REGEX = /^[a-zA-Z]:\\/
71
72// This logic works when `base` and `path` are on different Windows drives
73const parseBase = function(name, base, srcPath) {
74 if (srcPath === base || !srcPath.startsWith(base)) {
75 return
76 }
77
78 const relPath = srcPath.replace(base, '')
79 return { name, relPath }
80}
81
82const BASES = [
83 { name: 'cwd', base: getCwd() },
84 { name: 'home', base: homedir() },
85 { name: 'root', base: sep },
86]
87
88module.exports = { parsePath, BASES }