opendal 0.1.6.pre.rc.1-arm64-darwin-23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (191) hide show
  1. checksums.yaml +7 -0
  2. data/.standard.yml +20 -0
  3. data/.tool-versions +1 -0
  4. data/.yardopts +1 -0
  5. data/DEPENDENCIES.md +9 -0
  6. data/DEPENDENCIES.rust.tsv +277 -0
  7. data/Gemfile +35 -0
  8. data/README.md +159 -0
  9. data/Rakefile +149 -0
  10. data/core/CHANGELOG.md +4929 -0
  11. data/core/CONTRIBUTING.md +61 -0
  12. data/core/DEPENDENCIES.md +3 -0
  13. data/core/DEPENDENCIES.rust.tsv +185 -0
  14. data/core/LICENSE +201 -0
  15. data/core/README.md +228 -0
  16. data/core/benches/README.md +18 -0
  17. data/core/benches/ops/README.md +26 -0
  18. data/core/benches/types/README.md +9 -0
  19. data/core/benches/vs_fs/README.md +35 -0
  20. data/core/benches/vs_s3/README.md +55 -0
  21. data/core/edge/README.md +3 -0
  22. data/core/edge/file_write_on_full_disk/README.md +14 -0
  23. data/core/edge/s3_aws_assume_role_with_web_identity/README.md +18 -0
  24. data/core/edge/s3_read_on_wasm/.gitignore +3 -0
  25. data/core/edge/s3_read_on_wasm/README.md +42 -0
  26. data/core/edge/s3_read_on_wasm/webdriver.json +15 -0
  27. data/core/examples/README.md +23 -0
  28. data/core/examples/basic/README.md +15 -0
  29. data/core/examples/concurrent-upload/README.md +15 -0
  30. data/core/examples/multipart-upload/README.md +15 -0
  31. data/core/fuzz/.gitignore +5 -0
  32. data/core/fuzz/README.md +68 -0
  33. data/core/src/docs/comparisons/vs_object_store.md +183 -0
  34. data/core/src/docs/performance/concurrent_write.md +101 -0
  35. data/core/src/docs/performance/http_optimization.md +124 -0
  36. data/core/src/docs/rfcs/0000_example.md +74 -0
  37. data/core/src/docs/rfcs/0000_foyer_integration.md +111 -0
  38. data/core/src/docs/rfcs/0041_object_native_api.md +185 -0
  39. data/core/src/docs/rfcs/0044_error_handle.md +198 -0
  40. data/core/src/docs/rfcs/0057_auto_region.md +160 -0
  41. data/core/src/docs/rfcs/0069_object_stream.md +145 -0
  42. data/core/src/docs/rfcs/0090_limited_reader.md +155 -0
  43. data/core/src/docs/rfcs/0112_path_normalization.md +79 -0
  44. data/core/src/docs/rfcs/0191_async_streaming_io.md +328 -0
  45. data/core/src/docs/rfcs/0203_remove_credential.md +96 -0
  46. data/core/src/docs/rfcs/0221_create_dir.md +89 -0
  47. data/core/src/docs/rfcs/0247_retryable_error.md +87 -0
  48. data/core/src/docs/rfcs/0293_object_id.md +67 -0
  49. data/core/src/docs/rfcs/0337_dir_entry.md +191 -0
  50. data/core/src/docs/rfcs/0409_accessor_capabilities.md +67 -0
  51. data/core/src/docs/rfcs/0413_presign.md +154 -0
  52. data/core/src/docs/rfcs/0423_command_line_interface.md +268 -0
  53. data/core/src/docs/rfcs/0429_init_from_iter.md +107 -0
  54. data/core/src/docs/rfcs/0438_multipart.md +163 -0
  55. data/core/src/docs/rfcs/0443_gateway.md +73 -0
  56. data/core/src/docs/rfcs/0501_new_builder.md +111 -0
  57. data/core/src/docs/rfcs/0554_write_refactor.md +96 -0
  58. data/core/src/docs/rfcs/0561_list_metadata_reuse.md +210 -0
  59. data/core/src/docs/rfcs/0599_blocking_api.md +157 -0
  60. data/core/src/docs/rfcs/0623_redis_service.md +300 -0
  61. data/core/src/docs/rfcs/0627_split_capabilities.md +89 -0
  62. data/core/src/docs/rfcs/0661_path_in_accessor.md +126 -0
  63. data/core/src/docs/rfcs/0793_generic_kv_services.md +209 -0
  64. data/core/src/docs/rfcs/0926_object_reader.md +93 -0
  65. data/core/src/docs/rfcs/0977_refactor_error.md +151 -0
  66. data/core/src/docs/rfcs/1085_object_handler.md +73 -0
  67. data/core/src/docs/rfcs/1391_object_metadataer.md +110 -0
  68. data/core/src/docs/rfcs/1398_query_based_metadata.md +125 -0
  69. data/core/src/docs/rfcs/1420_object_writer.md +147 -0
  70. data/core/src/docs/rfcs/1477_remove_object_concept.md +159 -0
  71. data/core/src/docs/rfcs/1735_operation_extension.md +117 -0
  72. data/core/src/docs/rfcs/2083_writer_sink_api.md +106 -0
  73. data/core/src/docs/rfcs/2133_append_api.md +88 -0
  74. data/core/src/docs/rfcs/2299_chain_based_operator_api.md +99 -0
  75. data/core/src/docs/rfcs/2602_object_versioning.md +138 -0
  76. data/core/src/docs/rfcs/2758_merge_append_into_write.md +79 -0
  77. data/core/src/docs/rfcs/2774_lister_api.md +66 -0
  78. data/core/src/docs/rfcs/2779_list_with_metakey.md +143 -0
  79. data/core/src/docs/rfcs/2852_native_capability.md +58 -0
  80. data/core/src/docs/rfcs/2884_merge_range_read_into_read.md +80 -0
  81. data/core/src/docs/rfcs/3017_remove_write_copy_from.md +94 -0
  82. data/core/src/docs/rfcs/3197_config.md +237 -0
  83. data/core/src/docs/rfcs/3232_align_list_api.md +69 -0
  84. data/core/src/docs/rfcs/3243_list_prefix.md +128 -0
  85. data/core/src/docs/rfcs/3356_lazy_reader.md +111 -0
  86. data/core/src/docs/rfcs/3526_list_recursive.md +59 -0
  87. data/core/src/docs/rfcs/3574_concurrent_stat_in_list.md +80 -0
  88. data/core/src/docs/rfcs/3734_buffered_reader.md +64 -0
  89. data/core/src/docs/rfcs/3898_concurrent_writer.md +66 -0
  90. data/core/src/docs/rfcs/3911_deleter_api.md +165 -0
  91. data/core/src/docs/rfcs/4382_range_based_read.md +213 -0
  92. data/core/src/docs/rfcs/4638_executor.md +215 -0
  93. data/core/src/docs/rfcs/5314_remove_metakey.md +120 -0
  94. data/core/src/docs/rfcs/5444_operator_from_uri.md +162 -0
  95. data/core/src/docs/rfcs/5479_context.md +140 -0
  96. data/core/src/docs/rfcs/5485_conditional_reader.md +112 -0
  97. data/core/src/docs/rfcs/5495_list_with_deleted.md +81 -0
  98. data/core/src/docs/rfcs/5556_write_returns_metadata.md +121 -0
  99. data/core/src/docs/rfcs/5871_read_returns_metadata.md +112 -0
  100. data/core/src/docs/rfcs/6189_remove_native_blocking.md +106 -0
  101. data/core/src/docs/rfcs/6209_glob_support.md +132 -0
  102. data/core/src/docs/rfcs/6213_options_api.md +142 -0
  103. data/core/src/docs/rfcs/README.md +62 -0
  104. data/core/src/docs/upgrade.md +1556 -0
  105. data/core/src/services/aliyun_drive/docs.md +61 -0
  106. data/core/src/services/alluxio/docs.md +45 -0
  107. data/core/src/services/azblob/docs.md +77 -0
  108. data/core/src/services/azdls/docs.md +73 -0
  109. data/core/src/services/azfile/docs.md +65 -0
  110. data/core/src/services/b2/docs.md +54 -0
  111. data/core/src/services/cacache/docs.md +38 -0
  112. data/core/src/services/cloudflare_kv/docs.md +21 -0
  113. data/core/src/services/cos/docs.md +55 -0
  114. data/core/src/services/d1/docs.md +48 -0
  115. data/core/src/services/dashmap/docs.md +38 -0
  116. data/core/src/services/dbfs/docs.md +57 -0
  117. data/core/src/services/dropbox/docs.md +64 -0
  118. data/core/src/services/etcd/docs.md +45 -0
  119. data/core/src/services/foundationdb/docs.md +42 -0
  120. data/core/src/services/fs/docs.md +49 -0
  121. data/core/src/services/ftp/docs.md +42 -0
  122. data/core/src/services/gcs/docs.md +76 -0
  123. data/core/src/services/gdrive/docs.md +65 -0
  124. data/core/src/services/ghac/docs.md +84 -0
  125. data/core/src/services/github/docs.md +52 -0
  126. data/core/src/services/gridfs/docs.md +46 -0
  127. data/core/src/services/hdfs/docs.md +140 -0
  128. data/core/src/services/hdfs_native/docs.md +35 -0
  129. data/core/src/services/http/docs.md +45 -0
  130. data/core/src/services/huggingface/docs.md +61 -0
  131. data/core/src/services/ipfs/docs.md +45 -0
  132. data/core/src/services/ipmfs/docs.md +14 -0
  133. data/core/src/services/koofr/docs.md +51 -0
  134. data/core/src/services/lakefs/docs.md +62 -0
  135. data/core/src/services/memcached/docs.md +47 -0
  136. data/core/src/services/memory/docs.md +36 -0
  137. data/core/src/services/mini_moka/docs.md +19 -0
  138. data/core/src/services/moka/docs.md +42 -0
  139. data/core/src/services/mongodb/docs.md +49 -0
  140. data/core/src/services/monoiofs/docs.md +46 -0
  141. data/core/src/services/mysql/docs.md +47 -0
  142. data/core/src/services/obs/docs.md +54 -0
  143. data/core/src/services/onedrive/docs.md +115 -0
  144. data/core/src/services/opfs/docs.md +18 -0
  145. data/core/src/services/oss/docs.md +74 -0
  146. data/core/src/services/pcloud/docs.md +51 -0
  147. data/core/src/services/persy/docs.md +43 -0
  148. data/core/src/services/postgresql/docs.md +47 -0
  149. data/core/src/services/redb/docs.md +41 -0
  150. data/core/src/services/redis/docs.md +43 -0
  151. data/core/src/services/rocksdb/docs.md +54 -0
  152. data/core/src/services/s3/compatible_services.md +126 -0
  153. data/core/src/services/s3/docs.md +244 -0
  154. data/core/src/services/seafile/docs.md +54 -0
  155. data/core/src/services/sftp/docs.md +49 -0
  156. data/core/src/services/sled/docs.md +39 -0
  157. data/core/src/services/sqlite/docs.md +46 -0
  158. data/core/src/services/surrealdb/docs.md +54 -0
  159. data/core/src/services/swift/compatible_services.md +53 -0
  160. data/core/src/services/swift/docs.md +52 -0
  161. data/core/src/services/tikv/docs.md +43 -0
  162. data/core/src/services/upyun/docs.md +51 -0
  163. data/core/src/services/vercel_artifacts/docs.md +40 -0
  164. data/core/src/services/vercel_blob/docs.md +45 -0
  165. data/core/src/services/webdav/docs.md +49 -0
  166. data/core/src/services/webhdfs/docs.md +90 -0
  167. data/core/src/services/yandex_disk/docs.md +45 -0
  168. data/core/tests/behavior/README.md +77 -0
  169. data/core/tests/data/normal_dir/.gitkeep +0 -0
  170. data/core/tests/data/normal_file.txt +1041 -0
  171. data/core/tests/data/special_dir !@#$%^&()_+-=;',/.gitkeep +0 -0
  172. data/core/tests/data/special_file !@#$%^&()_+-=;',.txt +1041 -0
  173. data/core/users.md +13 -0
  174. data/extconf.rb +24 -0
  175. data/lib/opendal.rb +25 -0
  176. data/lib/opendal_ruby/entry.rb +35 -0
  177. data/lib/opendal_ruby/io.rb +70 -0
  178. data/lib/opendal_ruby/metadata.rb +44 -0
  179. data/lib/opendal_ruby/opendal_ruby.bundle +0 -0
  180. data/lib/opendal_ruby/operator.rb +29 -0
  181. data/lib/opendal_ruby/operator_info.rb +26 -0
  182. data/opendal.gemspec +91 -0
  183. data/test/blocking_op_test.rb +112 -0
  184. data/test/capability_test.rb +42 -0
  185. data/test/io_test.rb +172 -0
  186. data/test/lister_test.rb +77 -0
  187. data/test/metadata_test.rb +78 -0
  188. data/test/middlewares_test.rb +46 -0
  189. data/test/operator_info_test.rb +35 -0
  190. data/test/test_helper.rb +36 -0
  191. metadata +240 -0
@@ -0,0 +1,268 @@
1
+ - Proposal Name: `command_line_interface`
2
+ - Start Date: 2022-07-08
3
+ - RFC PR: [apache/opendal#423](https://github.com/apache/opendal/pull/423)
4
+ - Tracking Issue: [apache/opendal#422](https://github.com/apache/opendal/issues/422)
5
+
6
+ # Summary
7
+
8
+ Add command line interface for OpenDAL.
9
+
10
+ # Motivation
11
+
12
+ > **Q**: There are so many cli out there, why we still need a cli for OpenDAL?
13
+ >
14
+ > **A**: Because there are so many cli out there.
15
+
16
+ To manipulate our date store in different could service, we need to install different clis:
17
+
18
+ - [`aws-cli`]/[`s3cmd`]/... for AWS (S3)
19
+ - [`azcopy`] for Azure Storage Service
20
+ - [`gcloud`] for Google Cloud
21
+
22
+ Those clis provide native and seamless experiences for their own products but also lock us and our data.
23
+
24
+ However, for 80% cases, we just want to do simple jobs like `cp`, `mv` and `rm`. It's boring to figure out how to use them:
25
+
26
+ - `aws --endpoint-url http://127.0.0.1:9900/ s3 cp data s3://testbucket/data --recursive`
27
+ - `azcopy copy 'C:\myDirectory' 'https://mystorageaccount.blob.core.windows.net/mycontainer' --recursive`
28
+ - `gsutil cp data gs://testbucket/`
29
+
30
+ Can we use them in the same way? Can we let the data flow freely?
31
+
32
+ Let's look back OpenDAL's slogan:
33
+
34
+ **Open Data Access Layer that connect the whole world together**
35
+
36
+ This is a natural extension for OpenDAL: providing a command line interface!
37
+
38
+ # Guide-level explanation
39
+
40
+ OpenDAL will provide a new cli called: `oli`. It's a shortcut of `OpenDAL Command Line Interface`.
41
+
42
+ Users can install this cli via:
43
+
44
+ ```shell
45
+ cargo install oli
46
+ ```
47
+
48
+ Or using they favourite package management:
49
+
50
+ ```shell
51
+ # Archlinux
52
+ pacman -S oli
53
+ # Debian / Ubuntu
54
+ apt install oli
55
+ # Rocky Linux / Fedora
56
+ dnf install oli
57
+ # macOS
58
+ brew install oli
59
+ ```
60
+
61
+ With `oli`, users can:
62
+
63
+ - Upload files to s3: `oli cp books.csv s3://bucket/books.csv`
64
+ - Download files from azblob: `oli cp azblob://bucket/books.csv /tmp/books.csv`
65
+ - Move data between storage services: `oli mv s3://bucket/dir azblob://bucket/dir`
66
+ - Delete all files: `oli rm -rf s3://bucket`
67
+
68
+ `oli` also provide alias to make cloud data manipulating even natural:
69
+
70
+ - `ocp` for `oli cp`
71
+ - `ols` for `oli ls`
72
+ - `omv` for `oli mv`
73
+ - `orm` for `oli rm`
74
+ - `ostat` for `oli stat`
75
+
76
+ `oli` will provide profile management so users don't need to provide credential every time:
77
+
78
+ - `oli profile add my_s3 --bucket test --access-key-id=example --secret-access-key=example`
79
+ - `ocp my_s3://dir /tmp/dir`
80
+
81
+ # Reference-level explanation
82
+
83
+ `oli` will be a separate crate apart from `opendal` so we will not pollute the dependencies of `opendal`. But `oli` will be releases at the same time with the same version of `opendal`. That means `oli` will always use the same (latest) version of opendal.
84
+
85
+ Most operations of `oli` should be trivial, we will propose new RFCs if requiring big changes.
86
+
87
+ `oli` won't keep configuration. All config will go through environment, for example:
88
+
89
+ - `OIL_COLOR=always`
90
+ - `OIL_CONCURRENCY=16`
91
+
92
+ Besides, `oil` will read profile from env like `cargo`:
93
+
94
+ - `OIL_PROFILE_TEST_TYPE=s3`
95
+ - `OIL_PROFILE_TEST_ENDPOINT=http://127.0.0.1:1090`
96
+ - `OIL_PROFILE_TEST_BUCKET=test_bucket`
97
+ - `OIL_PROFILE_TEST_ACCESS_KEPT_ID=access_key_id`
98
+ - `OIL_PROFILE_TEST_SECRET_ACCESS_KEY=secret_access_key`
99
+
100
+ With those environments, we can:
101
+
102
+ ```shell
103
+ ocp path/to/dir test://test/to/dir
104
+ ```
105
+
106
+ # Drawbacks
107
+
108
+ None
109
+
110
+ # Rationale and alternatives
111
+
112
+ ## s3cmd
113
+
114
+ [s3cmd](https://s3tools.org/s3cmd) is a command line s3 client for Linux and Mac.
115
+
116
+ ```shell
117
+ Usage: s3cmd [options] COMMAND [parameters]
118
+
119
+ S3cmd is a tool for managing objects in Amazon S3 storage. It allows for
120
+ making and removing "buckets" and uploading, downloading and removing
121
+ "objects" from these buckets.
122
+
123
+ Commands:
124
+ Make bucket
125
+ s3cmd mb s3://BUCKET
126
+ Remove bucket
127
+ s3cmd rb s3://BUCKET
128
+ List objects or buckets
129
+ s3cmd ls [s3://BUCKET[/PREFIX]]
130
+ List all object in all buckets
131
+ s3cmd la
132
+ Put file into bucket
133
+ s3cmd put FILE [FILE...] s3://BUCKET[/PREFIX]
134
+ Get file from bucket
135
+ s3cmd get s3://BUCKET/OBJECT LOCAL_FILE
136
+ Delete file from bucket
137
+ s3cmd del s3://BUCKET/OBJECT
138
+ Delete file from bucket (alias for del)
139
+ s3cmd rm s3://BUCKET/OBJECT
140
+ Restore file from Glacier storage
141
+ s3cmd restore s3://BUCKET/OBJECT
142
+ Synchronize a directory tree to S3 (checks files freshness using
143
+ size and md5 checksum, unless overridden by options, see below)
144
+ s3cmd sync LOCAL_DIR s3://BUCKET[/PREFIX] or s3://BUCKET[/PREFIX] LOCAL_DIR
145
+ Disk usage by buckets
146
+ s3cmd du [s3://BUCKET[/PREFIX]]
147
+ Get various information about Buckets or Files
148
+ s3cmd info s3://BUCKET[/OBJECT]
149
+ Copy object
150
+ s3cmd cp s3://BUCKET1/OBJECT1 s3://BUCKET2[/OBJECT2]
151
+ Modify object metadata
152
+ s3cmd modify s3://BUCKET1/OBJECT
153
+ Move object
154
+ s3cmd mv s3://BUCKET1/OBJECT1 s3://BUCKET2[/OBJECT2]
155
+ Modify Access control list for Bucket or Files
156
+ s3cmd setacl s3://BUCKET[/OBJECT]
157
+ Modify Bucket Policy
158
+ s3cmd setpolicy FILE s3://BUCKET
159
+ Delete Bucket Policy
160
+ s3cmd delpolicy s3://BUCKET
161
+ Modify Bucket CORS
162
+ s3cmd setcors FILE s3://BUCKET
163
+ Delete Bucket CORS
164
+ s3cmd delcors s3://BUCKET
165
+ Modify Bucket Requester Pays policy
166
+ s3cmd payer s3://BUCKET
167
+ Show multipart uploads
168
+ s3cmd multipart s3://BUCKET [Id]
169
+ Abort a multipart upload
170
+ s3cmd abortmp s3://BUCKET/OBJECT Id
171
+ List parts of a multipart upload
172
+ s3cmd listmp s3://BUCKET/OBJECT Id
173
+ Enable/disable bucket access logging
174
+ s3cmd accesslog s3://BUCKET
175
+ Sign arbitrary string using the secret key
176
+ s3cmd sign STRING-TO-SIGN
177
+ Sign an S3 URL to provide limited public access with expiry
178
+ s3cmd signurl s3://BUCKET/OBJECT <expiry_epoch|+expiry_offset>
179
+ Fix invalid file names in a bucket
180
+ s3cmd fixbucket s3://BUCKET[/PREFIX]
181
+ Create Website from bucket
182
+ s3cmd ws-create s3://BUCKET
183
+ Delete Website
184
+ s3cmd ws-delete s3://BUCKET
185
+ Info about Website
186
+ s3cmd ws-info s3://BUCKET
187
+ Set or delete expiration rule for the bucket
188
+ s3cmd expire s3://BUCKET
189
+ Upload a lifecycle policy for the bucket
190
+ s3cmd setlifecycle FILE s3://BUCKET
191
+ Get a lifecycle policy for the bucket
192
+ s3cmd getlifecycle s3://BUCKET
193
+ Remove a lifecycle policy for the bucket
194
+ s3cmd dellifecycle s3://BUCKET
195
+ List CloudFront distribution points
196
+ s3cmd cflist
197
+ Display CloudFront distribution point parameters
198
+ s3cmd cfinfo [cf://DIST_ID]
199
+ Create CloudFront distribution point
200
+ s3cmd cfcreate s3://BUCKET
201
+ Delete CloudFront distribution point
202
+ s3cmd cfdelete cf://DIST_ID
203
+ Change CloudFront distribution point parameters
204
+ s3cmd cfmodify cf://DIST_ID
205
+ Display CloudFront invalidation request(s) status
206
+ s3cmd cfinvalinfo cf://DIST_ID[/INVAL_ID]
207
+ ```
208
+
209
+ ## aws-cli
210
+
211
+ [aws-cli](https://aws.amazon.com/cli/) is the official cli provided by AWS.
212
+
213
+ ```shell
214
+ $ aws s3 ls s3://mybucket
215
+ LastWriteTime Length Name
216
+ ------------ ------ ----
217
+ PRE myfolder/
218
+ 2013-09-03 10:00:00 1234 myfile.txt
219
+
220
+ $ aws s3 cp myfolder s3://mybucket/myfolder --recursive
221
+ upload: myfolder/file1.txt to s3://mybucket/myfolder/file1.txt
222
+ upload: myfolder/subfolder/file1.txt to s3://mybucket/myfolder/subfolder/file1.txt
223
+
224
+ $ aws s3 sync myfolder s3://mybucket/myfolder --exclude *.tmp
225
+ upload: myfolder/newfile.txt to s3://mybucket/myfolder/newfile.txt
226
+ ```
227
+
228
+ ## azcopy
229
+
230
+ [azcopy](https://github.com/Azure/azure-storage-azcopy) is the new Azure Storage data transfer utility.
231
+
232
+ ```shell
233
+ azcopy copy 'C:\myDirectory\myTextFile.txt' 'https://mystorageaccount.blob.core.windows.net/mycontainer/myTextFile.txt'
234
+
235
+ azcopy copy 'https://mystorageaccount.blob.core.windows.net/mycontainer/myTextFile.txt' 'C:\myDirectory\myTextFile.txt'
236
+
237
+ azcopy sync 'C:\myDirectory' 'https://mystorageaccount.blob.core.windows.net/mycontainer' --recursive
238
+ ```
239
+
240
+ ## gsutil
241
+
242
+ [gsutil](https://cloud.google.com/storage/docs/gsutil) is a Python application that lets you access Cloud Storage from the command line.
243
+
244
+ ```shell
245
+ gsutil cp [OPTION]... src_url dst_url
246
+ gsutil cp [OPTION]... src_url... dst_url
247
+ gsutil cp [OPTION]... -I dst_url
248
+
249
+ gsutil mv [-p] src_url dst_url
250
+ gsutil mv [-p] src_url... dst_url
251
+ gsutil mv [-p] -I dst_url
252
+
253
+ gsutil rm [-f] [-r] url...
254
+ gsutil rm [-f] [-r] -I
255
+ ```
256
+
257
+ # Unresolved questions
258
+
259
+ None.
260
+
261
+ # Future possibilities
262
+
263
+ None.
264
+
265
+ [`aws-cli`]: https://github.com/aws/aws-cli
266
+ [`s3cmd`]: https://s3tools.org/s3cmd
267
+ [`azcopy`]: https://github.com/Azure/azure-storage-azcopy
268
+ [`gcloud`]: https://cloud.google.com/sdk/docs/install
@@ -0,0 +1,107 @@
1
+ - Proposal Name: `init_from_iter`
2
+ - Start Date: 2022-07-10
3
+ - RFC PR: [apache/opendal#429](https://github.com/apache/opendal/pull/429)
4
+ - Tracking Issue: [apache/opendal#430](https://github.com/apache/opendal/issues/430)
5
+
6
+ # Summary
7
+
8
+ Allow initializing opendal operators from an iterator.
9
+
10
+ # Motivation
11
+
12
+ To init OpenDAL operators, users have to init an accessor first.
13
+
14
+ ```rust
15
+ let root = &env::var("OPENDAL_S3_ROOT").unwrap_or_else(|_| "/".to_string());
16
+ let root = format!("/{}/{}", root, uuid::Uuid::new_v4());
17
+
18
+ let mut builder = opendal::services::s3::Backend::build();
19
+ builder.root(&root);
20
+ builder.bucket(&env::var("OPENDAL_S3_BUCKET").expect("OPENDAL_S3_BUCKET must set"));
21
+ builder.endpoint(&env::var("OPENDAL_S3_ENDPOINT").unwrap_or_default());
22
+ builder.access_key_id(&env::var("OPENDAL_S3_ACCESS_KEY_ID").unwrap_or_default());
23
+ builder.secret_access_key(&env::var("OPENDAL_S3_SECRET_ACCESS_KEY").unwrap_or_default());
24
+ builder
25
+ .server_side_encryption(&env::var("OPENDAL_S3_SERVER_SIDE_ENCRYPTION").unwrap_or_default());
26
+ builder.server_side_encryption_customer_algorithm(
27
+ &env::var("OPENDAL_S3_SERVER_SIDE_ENCRYPTION_CUSTOMER_ALGORITHM").unwrap_or_default(),
28
+ );
29
+ builder.server_side_encryption_customer_key(
30
+ &env::var("OPENDAL_S3_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY").unwrap_or_default(),
31
+ );
32
+ builder.server_side_encryption_customer_key_md5(
33
+ &env::var("OPENDAL_S3_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY_MD5").unwrap_or_default(),
34
+ );
35
+ builder.server_side_encryption_aws_kms_key_id(
36
+ &env::var("OPENDAL_S3_SERVER_SIDE_ENCRYPTION_AWS_KMS_KEY_ID").unwrap_or_default(),
37
+ );
38
+ if env::var("OPENDAL_S3_ENABLE_VIRTUAL_HOST_STYLE").unwrap_or_default() == "on" {
39
+ builder.enable_virtual_host_style();
40
+ }
41
+ Ok(Some(builder.finish().await?))
42
+ ```
43
+
44
+ We can simplify this logic if opendal has its native `from_iter` support.
45
+
46
+ # Guide-level explanation
47
+
48
+ Users can init an operator like the following:
49
+
50
+ ```rust
51
+ // OPENDAL_S3_BUCKET = <bucket>
52
+ // OPENDAL_S3_ENDPOINT = <endpoint>
53
+ let op = Operator::from_env(Scheme::S3)?;
54
+ ```
55
+
56
+ Or from a prefixed env:
57
+
58
+ ```rust
59
+ // OIL_PROFILE_<name>_S3_BUCKET = <bucket>
60
+ // OIL_PROFILE_<name>_S3_ENDPOINT = <endpoint>
61
+ let op = Operator::from_env(Scheme::S3, "OIL_PROFILE_<name>")?;
62
+ ```
63
+
64
+ Also, we call the underlying function directly:
65
+
66
+ ```rust
67
+ // var it: impl Iterator<Item=(String, String)>
68
+ let op = Operator::from_iter(Scheme::S3, it)?;
69
+ ```
70
+
71
+ # Reference-level explanation
72
+
73
+ Internally, every service's backend will implement the following functions:
74
+
75
+ ```rust
76
+ fn from_iter(it: impl Iterator<Item=(String, String)>) -> Backend {}
77
+ ```
78
+
79
+ Note: it's not a public API of `Accessor`, and it will never be. Instead, we will use this function inside the crate to keep the ability to refactor or even remove it.
80
+
81
+ # Drawbacks
82
+
83
+ None.
84
+
85
+ # Rationale and alternatives
86
+
87
+ None
88
+
89
+ # Prior art
90
+
91
+ None
92
+
93
+ # Unresolved questions
94
+
95
+ None
96
+
97
+ # Future possibilities
98
+
99
+ ## Connection string
100
+
101
+ It sounds a good idea to implement something like:
102
+
103
+ ```rust
104
+ let op = Operator::open("s3://bucket?region=test")?
105
+ ```
106
+
107
+ But there are no valid use cases. Let's implement this in the future if needed.
@@ -0,0 +1,163 @@
1
+ - Proposal Name: `multipart`
2
+ - Start Date: 2022-07-11
3
+ - RFC PR: [apache/opendal#438](https://github.com/apache/opendal/pull/438)
4
+ - Tracking Issue: [apache/opendal#439](https://github.com/apache/opendal/issues/439)
5
+
6
+ # Summary
7
+
8
+ Add multipart support in OpenDAL.
9
+
10
+ # Motivation
11
+
12
+ [Multipart Upload](https://docs.aws.amazon.com/AmazonS3/latest/userguide/mpuoverview.html) APIs are widely used in object storage services to upload large files concurrently and resumable.
13
+
14
+ A successful multipart upload includes the following steps:
15
+
16
+ - `CreateMultipartUpload`: Start a new multipart upload.
17
+ - `UploadPart`: Upload a single part with the previously uploaded id.
18
+ - `CompleteMultipartUpload`: Complete a multipart upload to get a regular object.
19
+
20
+ To cancel a multipart upload, users need to call `AbortMultipartUpload`.
21
+
22
+ Apart from those APIs, most object services also provide a list API to get the current multipart uploads status:
23
+
24
+ - `ListMultipartUploads`: List current ongoing multipart uploads
25
+ - `ListParts`: List already uploaded parts.
26
+
27
+ Before `CompleteMultipartUpload` has been called, users can't read already uploaded parts.
28
+
29
+ After `CompleteMultipartUpload` or `AbortMultipartUpload` has been called, all uploaded parts will be removed.
30
+
31
+ Object storage services commonly allow 10000 parts, and every part will allow up to 5 GiB. This way, users can upload a file up to 48.8 TiB.
32
+
33
+ OpenDAL users can upload objects larger than 5 GiB via supporting multipart uploads.
34
+
35
+ # Guide-level explanation
36
+
37
+ Users can start a multipart upload via:
38
+
39
+ ```rust
40
+ let mp = op.object("path/to/file").create_multipart().await?;
41
+ ```
42
+
43
+ Or build a multipart via already known upload id:
44
+
45
+ ```rust
46
+ let mp = op.object("path/to/file").into_multipart("<upload_id>");
47
+ ```
48
+
49
+ With `Multipart`, we can upload a new part:
50
+
51
+ ```rust
52
+ let part = mp.write(part_number, content).await?;
53
+ ```
54
+
55
+ After all parts have been uploaded, we can finish this upload:
56
+
57
+ ```rust
58
+ let _ = mp.complete(parts).await?;
59
+ ```
60
+
61
+ Or, we can abort already uploaded parts:
62
+
63
+ ```rust
64
+ let _ = mp.abort().await?;
65
+ ```
66
+
67
+ # Reference-level explanation
68
+
69
+ `Accessor` will add the following APIs:
70
+
71
+ ```rust
72
+ pub trait Accessor: Send + Sync + Debug {
73
+ async fn create_multipart(&self, args: &OpCreateMultipart) -> Result<String> {
74
+ let _ = args;
75
+ unimplemented!()
76
+ }
77
+
78
+ async fn write_multipart(&self, args: &OpWriteMultipart) -> Result<PartWriter> {
79
+ let _ = args;
80
+ unimplemented!()
81
+ }
82
+
83
+ async fn complete_multipart(&self, args: &OpCompleteMultipart) -> Result<()> {
84
+ let _ = args;
85
+ unimplemented!()
86
+ }
87
+
88
+ async fn abort_multipart(&self, args: &OpAbortMultipart) -> Result<()> {
89
+ let _ = args;
90
+ unimplemented!()
91
+ }
92
+ }
93
+ ```
94
+
95
+ While closing a `PartWriter`, a `Part` will be generated.
96
+
97
+ `Operator` will build APIs based on `Accessor`:
98
+
99
+ ```rust
100
+ impl Object {
101
+ async fn create_multipart(&self) -> Result<Multipart> {}
102
+ fn into_multipart(&self, upload_id: &str) -> Multipart {}
103
+ }
104
+
105
+ impl Multipart {
106
+ async fn write(&self, part_number: usize, bs: impl AsRef<[u8]>) -> Result<Part> {}
107
+ async fn writer(&self, part_number: usize, size: u64) -> Result<impl PartWrite> {}
108
+ async fn complete(&self, ps: &[Part]) -> Result<()> {}
109
+ async fn abort(&self) -> Result<()> {}
110
+ }
111
+ ```
112
+
113
+ # Drawbacks
114
+
115
+ None.
116
+
117
+ # Rationale and alternatives
118
+
119
+ ## Why not add new object modes?
120
+
121
+ It seems natural to add a new object mode like `multipart`.
122
+
123
+ ```rust
124
+ pub enum ObjectMode {
125
+ FILE,
126
+ DIR,
127
+ MULTIPART,
128
+ Unknown,
129
+ }
130
+ ```
131
+
132
+ However, to make this work, we need big API breaks that introduce `mode` in Object.
133
+
134
+ And we need to change every API call to accept `mode` as args.
135
+
136
+ For example:
137
+
138
+ ```rust
139
+ let _ = op.object("path/to/dir/").list(ObjectMODE::MULTIPART);
140
+ let _ = op.object("path/to/file").stat(ObjectMODE::MULTIPART)
141
+ ```
142
+
143
+ ## Why not split Object into File and Dir?
144
+
145
+ We can split `Object` into `File` and `Dir` to avoid requiring `mode` in API. There is a vast API breakage too.
146
+
147
+ # Prior art
148
+
149
+ None.
150
+
151
+ # Unresolved questions
152
+
153
+ None.
154
+
155
+ # Future possibilities
156
+
157
+ ## Support list multipart uploads
158
+
159
+ We can support listing multipart uploads to list ongoing multipart uploads so we can resume an upload or abort them.
160
+
161
+ ## Support list part
162
+
163
+ We can support listing parts to list already uploaded parts for an upload.
@@ -0,0 +1,73 @@
1
+ - Proposal Name: `gateway`
2
+ - Start Date: 2022-07-18
3
+ - RFC PR: [apache/opendal#443](https://github.com/apache/opendal/pull/443)
4
+ - Tracking Issue: [apache/opendal#444](https://github.com/apache/opendal/issues/444)
5
+
6
+ # Summary
7
+
8
+ Add Gateway for OpenDAL.
9
+
10
+ # Motivation
11
+
12
+ Our users want features like [S3 Proxy](https://github.com/gaul/s3proxy) and [minio Gateway](https://blog.min.io/deprecation-of-the-minio-gateway/) so that they can access all their data in the same way.
13
+
14
+ By providing a native gateway, we can empower users to access different storage in the same API.
15
+
16
+ # Guide-level explanation
17
+
18
+ OpenDAL will provide a new binary called: `oay`. It's a shortcut of `OpenDAL Gateway`.
19
+
20
+ Uses can install this binary via:
21
+
22
+ ```shell
23
+ cargo install oay
24
+ ```
25
+
26
+ Or using they favourite package management:
27
+
28
+ ```shell
29
+ # Archlinux
30
+ pacman -S oay
31
+ # Debian / Ubuntu
32
+ apt install oay
33
+ # Rocky Linux / Fedora
34
+ dnf install oay
35
+ # macOS
36
+ brew install oay
37
+ ```
38
+
39
+ With `oay`, users can:
40
+
41
+ - Serve `fs` backend with S3 compatible API.
42
+ - Serve `s3` backend with Azblob API
43
+ - Serve as a s3 signing services
44
+
45
+ # Reference-level explanation
46
+
47
+ `oay` will be a separate crate apart from `opendal` so we will not pollute the dependencies of `opendal`. But `oay` will be releases at the same time with the same version of `opendal`. That means `oay` will always use the same (latest) version of opendal.
48
+
49
+ Most operations of `oay` should be trivial, we will propose new RFCs if requiring big changes.
50
+
51
+ `oay` won't keep configuration. All config will go through environment.
52
+
53
+ # Drawbacks
54
+
55
+ None
56
+
57
+ # Rationale and alternatives
58
+
59
+ None
60
+
61
+ # Prior art
62
+
63
+ - [S3 Proxy](https://github.com/gaul/s3proxy)
64
+ - [minio Gateway](https://blog.min.io/deprecation-of-the-minio-gateway/)
65
+ - [oxyno-zeta/s3-proxy](https://github.com/oxyno-zeta/s3-proxy)
66
+
67
+ # Unresolved questions
68
+
69
+ None
70
+
71
+ # Future possibilities
72
+
73
+ None