forked from ducktors/turborepo-remote-cache
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.ts
More file actions
120 lines (108 loc) · 4.08 KB
/
index.ts
File metadata and controls
120 lines (108 loc) · 4.08 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
import { join } from 'path'
import { Readable, pipeline as pipelineCallback } from 'stream'
import { promisify } from 'util'
import { STORAGE_PROVIDERS } from '../../../env'
import { createS3, type S3Options as S3Opts } from './s3'
import { createLocal, type LocalOptions as LocalOpts } from './local'
import {
createGoogleCloudStorage,
type GoogleCloudStorageOptions as GCSOpts,
} from './google-cloud-storage'
const pipeline = promisify(pipelineCallback)
const TURBO_CACHE_FOLDER_NAME = 'turborepocache' as const
const TURBO_CACHE_USE_TMP_FOLDER = true as const
type LocalOptions = Partial<LocalOpts>
type S3Options = Omit<S3Opts, 'bucket'> & LocalOptions
type GoogleCloudStorageOptions = Omit<GCSOpts, 'bucket'> & LocalOptions
type ProviderOptions<Provider extends STORAGE_PROVIDERS> = Provider extends STORAGE_PROVIDERS.LOCAL
? LocalOptions
: Provider extends STORAGE_PROVIDERS.S3
? S3Options
: Provider extends STORAGE_PROVIDERS.s3
? S3Options
: Provider extends STORAGE_PROVIDERS.GOOGLE_CLOUD_STORAGE
? GoogleCloudStorageOptions
: never
// https://github.com/maxogden/abstract-blob-store#api
export interface StorageProvider {
exists: (artifactPath: string, cb: (err: Error | null, exists?: boolean) => void) => void
createReadStream: (artifactPath: string) => NodeJS.ReadStream
createWriteStream: (artifactPath: string) => NodeJS.WritableStream
}
function createStorageLocation<Provider extends STORAGE_PROVIDERS>(
provider: Provider,
providerOptions: ProviderOptions<Provider>,
): StorageProvider {
const { path = TURBO_CACHE_FOLDER_NAME, useTmp = TURBO_CACHE_USE_TMP_FOLDER } = providerOptions
switch (provider) {
case STORAGE_PROVIDERS.LOCAL: {
return createLocal({ path, useTmp })
}
case STORAGE_PROVIDERS.S3:
case STORAGE_PROVIDERS.s3: {
const { accessKey, secretKey, region, endpoint } = providerOptions as S3Options
return createS3({ accessKey, secretKey, bucket: path, region, endpoint })
}
case STORAGE_PROVIDERS.GOOGLE_CLOUD_STORAGE: {
const { clientEmail, privateKey, projectId } = providerOptions as GoogleCloudStorageOptions
return createGoogleCloudStorage({ bucket: path, clientEmail, privateKey, projectId })
}
default:
throw new Error(
`Unsupported storage provider '${provider}'. Please select one of the following: ${Object.values(
STORAGE_PROVIDERS,
).join(', ')}!`,
)
}
}
export function createLocation<Provider extends STORAGE_PROVIDERS>(
provider: Provider,
providerOptions: ProviderOptions<Provider>,
) {
const location = createStorageLocation(provider, providerOptions)
async function getCachedArtifact(artifactId: string, teamId: string) {
return new Promise((resolve, reject) => {
const artifactPath = join(teamId, artifactId)
location.exists(artifactPath, (err, exists) => {
if (err) {
return reject(err)
}
if (!exists) {
return reject(new Error(`Artifact ${artifactPath} doesn't exist.`))
}
resolve(location.createReadStream(artifactPath))
})
})
}
async function existsCachedArtifact(artifactId: string, teamId: string) {
return new Promise<void>((resolve, reject) => {
const artifactPath = join(teamId, artifactId)
location.exists(artifactPath, (err, exists) => {
if (err) {
return reject(err)
}
if (!exists) {
return reject(new Error(`Artifact ${artifactPath} doesn't exist.`))
}
resolve()
})
})
}
async function createCachedArtifact(artifactId: string, teamId: string, artifact: Readable) {
return pipeline(artifact, location.createWriteStream(join(teamId, artifactId)))
}
return {
getCachedArtifact,
createCachedArtifact,
existsCachedArtifact,
}
}
declare module 'fastify' {
interface FastifyInstance {
location: {
existsCachedArtifact: ReturnType<typeof createLocation>['existsCachedArtifact']
getCachedArtifact: ReturnType<typeof createLocation>['getCachedArtifact']
createCachedArtifact: ReturnType<typeof createLocation>['createCachedArtifact']
}
}
}