@@ -40,9 +40,12 @@ use crate::cache::s3::S3Cache;
4040 feature = "s3" ,
4141 feature = "webdav" ,
4242 feature = "oss" ,
43- feature = "cos"
43+ feature = "cos" ,
44+ feature = "vercel_artifacts"
4445) ) ]
4546use crate :: cache:: utils:: normalize_key;
47+ #[ cfg( feature = "vercel_artifacts" ) ]
48+ use crate :: cache:: vercel_artifacts:: VercelArtifactsCache ;
4649#[ cfg( feature = "webdav" ) ]
4750use crate :: cache:: webdav:: WebdavCache ;
4851use crate :: compiler:: PreprocessorCacheEntry ;
@@ -169,6 +172,10 @@ pub trait Storage: Send + Sync {
169172pub struct RemoteStorage {
170173 operator : opendal:: Operator ,
171174 basedirs : Vec < Vec < u8 > > ,
175+ /// Optional transform applied to every key (including health-check paths)
176+ /// before it is sent to the operator. Used by backends like Vercel Artifacts
177+ /// that only accept alphanumeric artifact IDs.
178+ key_transform : Option < fn ( & str ) -> String > ,
172179}
173180
174181#[ cfg( any(
@@ -184,7 +191,31 @@ pub struct RemoteStorage {
184191) ) ]
185192impl RemoteStorage {
186193 pub fn new ( operator : opendal:: Operator , basedirs : Vec < Vec < u8 > > ) -> Self {
187- Self { operator, basedirs }
194+ Self {
195+ operator,
196+ basedirs,
197+ key_transform : None ,
198+ }
199+ }
200+
201+ pub fn new_with_key_transform (
202+ operator : opendal:: Operator ,
203+ basedirs : Vec < Vec < u8 > > ,
204+ key_transform : fn ( & str ) -> String ,
205+ ) -> Self {
206+ Self {
207+ operator,
208+ basedirs,
209+ key_transform : Some ( key_transform) ,
210+ }
211+ }
212+
213+ fn key_path ( & self , key : & str ) -> String {
214+ let normalized = normalize_key ( key) ;
215+ match self . key_transform {
216+ Some ( transform) => transform ( & normalized) ,
217+ None => normalized,
218+ }
188219 }
189220}
190221
@@ -203,7 +234,7 @@ impl RemoteStorage {
203234#[ async_trait]
204235impl Storage for RemoteStorage {
205236 async fn get ( & self , key : & str ) -> Result < Cache > {
206- match self . operator . read ( & normalize_key ( key) ) . await {
237+ match self . operator . read ( & self . key_path ( key) ) . await {
207238 Ok ( res) => {
208239 let hit = CacheRead :: from ( io:: Cursor :: new ( res. to_bytes ( ) ) ) ?;
209240 Ok ( Cache :: Hit ( hit) )
@@ -226,10 +257,10 @@ impl Storage for RemoteStorage {
226257 async fn check ( & self ) -> Result < CacheMode > {
227258 use opendal:: ErrorKind ;
228259
229- let path = ".sccache_check" ;
260+ let path = self . key_path ( ".sccache_check" ) ;
230261
231262 // Read is required, return error directly if we can't read .
232- match self . operator . read ( path) . await {
263+ match self . operator . read ( & path) . await {
233264 Ok ( _) => ( ) ,
234265 // Read not exist file with not found is ok.
235266 Err ( err) if err. kind ( ) == ErrorKind :: NotFound => ( ) ,
@@ -248,7 +279,7 @@ impl Storage for RemoteStorage {
248279 Err ( err) => bail ! ( "cache storage failed to read: {:?}" , err) ,
249280 }
250281
251- let can_write = match self . operator . write ( path, "Hello, World!" ) . await {
282+ let can_write = match self . operator . write ( & path, "Hello, World!" ) . await {
252283 Ok ( _) => true ,
253284 Err ( err) if err. kind ( ) == ErrorKind :: AlreadyExists => true ,
254285 // Tolerate all other write errors because we can do read at least.
@@ -306,7 +337,7 @@ impl Storage for RemoteStorage {
306337 /// which would corrupt the cache entry when written to another level.
307338 async fn get_raw ( & self , key : & str ) -> Result < Option < Vec < u8 > > > {
308339 trace ! ( "opendal::Operator::get_raw({})" , key) ;
309- match self . operator . read ( & normalize_key ( key) ) . await {
340+ match self . operator . read ( & self . key_path ( key) ) . await {
310341 Ok ( res) => {
311342 let data = res. to_vec ( ) ;
312343 trace ! (
@@ -337,7 +368,7 @@ impl Storage for RemoteStorage {
337368 trace ! ( "opendal::Operator::put_raw({}, {} bytes)" , key, data. len( ) ) ;
338369 let start = std:: time:: Instant :: now ( ) ;
339370
340- self . operator . write ( & normalize_key ( key) , data) . await ?;
371+ self . operator . write ( & self . key_path ( key) , data) . await ?;
341372
342373 Ok ( start. elapsed ( ) )
343374 }
@@ -542,6 +573,24 @@ pub fn build_single_cache(
542573 let storage = RemoteStorage :: new ( operator, basedirs. to_vec ( ) ) ;
543574 Ok ( Arc :: new ( storage) )
544575 }
576+ #[ cfg( feature = "vercel_artifacts" ) ]
577+ CacheType :: VercelArtifacts ( c) => {
578+ debug ! ( "Init vercel artifacts cache" ) ;
579+
580+ let operator = VercelArtifactsCache :: build (
581+ & c. access_token ,
582+ c. endpoint . as_deref ( ) ,
583+ c. team_id . as_deref ( ) ,
584+ c. team_slug . as_deref ( ) ,
585+ )
586+ . map_err ( |err| anyhow ! ( "create vercel artifacts cache failed: {err:?}" ) ) ?;
587+ let storage = RemoteStorage :: new_with_key_transform (
588+ operator,
589+ basedirs. to_vec ( ) ,
590+ crate :: cache:: vercel_artifacts:: sanitize_key,
591+ ) ;
592+ Ok ( Arc :: new ( storage) )
593+ }
545594 #[ allow( unreachable_patterns) ]
546595 _ => {
547596 bail ! ( "Cache type not supported with current feature configuration" )
0 commit comments