@@ -18,6 +18,8 @@ const fsExists = promisify(fs.exists)
1818const fsReadFile = promisify ( fs . readFile )
1919const fsWriteFile = promisify ( fs . writeFile )
2020const fsCopyFile = promisify ( fs . copyFile )
21+ const fsReadDir = promisify ( fs . readdir )
22+ const fsLstat = promisify ( fs . lstat )
2123
2224type ChunkGraphManifest = {
2325 sharedFiles : string [ ] | undefined
@@ -27,8 +29,42 @@ type ChunkGraphManifest = {
2729 hashes : { [ page : string ] : string }
2830}
2931
32+ function isShuttleValid ( {
33+ manifestPath,
34+ pagesDirectory,
35+ parentCacheIdentifier,
36+ } : {
37+ manifestPath : string
38+ pagesDirectory : string
39+ parentCacheIdentifier : string
40+ } ) {
41+ const manifest = require ( manifestPath ) as ChunkGraphManifest
42+ const { sharedFiles, hashes } = manifest
43+ if ( ! sharedFiles ) {
44+ return false
45+ }
46+
47+ return ! sharedFiles
48+ . map ( file => {
49+ const filePath = path . join ( path . dirname ( pagesDirectory ) , file )
50+ const exists = fs . existsSync ( filePath )
51+ if ( ! exists ) {
52+ return true
53+ }
54+
55+ const hash = crypto
56+ . createHash ( 'sha1' )
57+ . update ( parentCacheIdentifier )
58+ . update ( fs . readFileSync ( filePath ) )
59+ . digest ( 'hex' )
60+ return hash !== hashes [ file ]
61+ } )
62+ . some ( Boolean )
63+ }
64+
3065export class FlyingShuttle {
31- private shuttleDirectory : string
66+ private apexShuttleDirectory : string
67+ private flyingShuttleId : string
3268
3369 private buildId : string
3470 private pagesDirectory : string
@@ -57,20 +93,59 @@ export class FlyingShuttle {
5793 cacheIdentifier : string
5894 } ) {
5995 mkdirpModule . sync (
60- ( this . shuttleDirectory = path . join (
96+ ( this . apexShuttleDirectory = path . join (
6197 distDirectory ,
6298 'cache' ,
6399 'next-flying-shuttle'
64100 ) )
65101 )
102+ this . flyingShuttleId = crypto . randomBytes ( 16 ) . toString ( 'hex' )
66103
67104 this . buildId = buildId
68105 this . pagesDirectory = pagesDirectory
69106 this . distDirectory = distDirectory
70107 this . parentCacheIdentifier = cacheIdentifier
71108 }
72109
110+ get shuttleDirectory ( ) {
111+ return path . join ( this . apexShuttleDirectory , this . flyingShuttleId )
112+ }
113+
114+ private getShuttleIds = async ( ) =>
115+ ( await Promise . all (
116+ await fsReadDir ( this . apexShuttleDirectory ) . then ( shuttleFiles =>
117+ shuttleFiles . map ( async f => ( {
118+ file : f ,
119+ stats : await fsLstat ( path . join ( this . apexShuttleDirectory , f ) ) ,
120+ } ) )
121+ )
122+ ) )
123+ . filter ( ( { stats } ) => stats . isDirectory ( ) )
124+ . map ( ( { file } ) => file )
125+
126+ private findShuttleId = async ( ) => {
127+ const shuttles = await this . getShuttleIds ( )
128+ return shuttles . find ( shuttleId => {
129+ try {
130+ const manifestPath = path . join (
131+ this . apexShuttleDirectory ,
132+ shuttleId ,
133+ CHUNK_GRAPH_MANIFEST
134+ )
135+ return isShuttleValid ( {
136+ manifestPath,
137+ pagesDirectory : this . pagesDirectory ,
138+ parentCacheIdentifier : this . parentCacheIdentifier ,
139+ } )
140+ } catch ( _ ) { }
141+ return false
142+ } )
143+ }
144+
73145 hasShuttle = async ( ) => {
146+ const existingFlyingShuttleId = await this . findShuttleId ( )
147+ this . flyingShuttleId = existingFlyingShuttleId || this . flyingShuttleId
148+
74149 const found =
75150 this . shuttleBuildId &&
76151 ( await fsExists ( path . join ( this . shuttleDirectory , CHUNK_GRAPH_MANIFEST ) ) )
0 commit comments