| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859 |
- import os
- from typing import List, Optional
- from google.cloud import storage
- from openhands.storage.files import FileStore
- class GoogleCloudFileStore(FileStore):
- def __init__(self, bucket_name: Optional[str] = None) -> None:
- """
- Create a new FileStore. If GOOGLE_APPLICATION_CREDENTIALS is defined in the
- environment it will be used for authentication. Otherwise access will be
- anonymous.
- """
- if bucket_name is None:
- bucket_name = os.environ['GOOGLE_CLOUD_BUCKET_NAME']
- self.storage_client = storage.Client()
- self.bucket = self.storage_client.bucket(bucket_name)
- def write(self, path: str, contents: str | bytes) -> None:
- blob = self.bucket.blob(path)
- with blob.open('w') as f:
- f.write(contents)
- def read(self, path: str) -> str:
- blob = self.bucket.blob(path)
- with blob.open('r') as f:
- return f.read()
- def list(self, path: str) -> List[str]:
- if not path or path == '/':
- path = ''
- elif not path.endswith('/'):
- path += '/'
- # The delimiter logic screens out directories, so we can't use it. :(
- # For example, given a structure:
- # foo/bar/zap.txt
- # foo/bar/bang.txt
- # ping.txt
- # prefix=None, delimiter="/" yields ["ping.txt"] # :(
- # prefix="foo", delimiter="/" yields [] # :(
- blobs = set()
- prefix_len = len(path)
- for blob in self.bucket.list_blobs(prefix=path):
- name = blob.name
- if name == path:
- continue
- try:
- index = name.index('/', prefix_len + 1)
- if index != prefix_len:
- blobs.add(name[: index + 1])
- except ValueError:
- blobs.add(name)
- return list(blobs)
- def delete(self, path: str) -> None:
- blob = self.bucket.blob(path)
- blob.delete()
|