megfile 4.2.4__py3-none-any.whl → 5.0.0__py3-none-any.whl
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.
- megfile/__init__.py +16 -291
- megfile/cli.py +37 -20
- megfile/config.py +10 -1
- megfile/errors.py +2 -2
- megfile/fs_path.py +78 -12
- megfile/interfaces.py +44 -0
- megfile/lib/base_memory_handler.py +92 -0
- megfile/lib/glob.py +3 -3
- megfile/lib/http_prefetch_reader.py +22 -22
- megfile/lib/joinpath.py +13 -0
- megfile/lib/s3_buffered_writer.py +13 -0
- megfile/lib/s3_limited_seekable_writer.py +2 -0
- megfile/lib/s3_memory_handler.py +14 -81
- megfile/lib/webdav_memory_handler.py +83 -0
- megfile/lib/webdav_prefetch_reader.py +115 -0
- megfile/pathlike.py +3 -4
- megfile/s3_path.py +44 -33
- megfile/sftp2_path.py +44 -62
- megfile/sftp_path.py +239 -2
- megfile/smart.py +70 -29
- megfile/smart_path.py +181 -85
- megfile/version.py +1 -1
- megfile/webdav_path.py +952 -0
- {megfile-4.2.4.dist-info → megfile-5.0.0.dist-info}/METADATA +30 -39
- megfile-5.0.0.dist-info/RECORD +51 -0
- megfile/fs.py +0 -614
- megfile/hdfs.py +0 -408
- megfile/http.py +0 -114
- megfile/s3.py +0 -540
- megfile/sftp.py +0 -821
- megfile/sftp2.py +0 -827
- megfile/stdio.py +0 -30
- megfile-4.2.4.dist-info/RECORD +0 -54
- {megfile-4.2.4.dist-info → megfile-5.0.0.dist-info}/WHEEL +0 -0
- {megfile-4.2.4.dist-info → megfile-5.0.0.dist-info}/entry_points.txt +0 -0
- {megfile-4.2.4.dist-info → megfile-5.0.0.dist-info}/licenses/LICENSE +0 -0
- {megfile-4.2.4.dist-info → megfile-5.0.0.dist-info}/licenses/LICENSE.pyre +0 -0
- {megfile-4.2.4.dist-info → megfile-5.0.0.dist-info}/top_level.txt +0 -0
megfile/__init__.py
CHANGED
|
@@ -1,164 +1,17 @@
|
|
|
1
|
-
from megfile.
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
fs_expanduser,
|
|
7
|
-
fs_getmd5,
|
|
8
|
-
fs_getmtime,
|
|
9
|
-
fs_getsize,
|
|
10
|
-
fs_glob,
|
|
11
|
-
fs_glob_stat,
|
|
12
|
-
fs_home,
|
|
13
|
-
fs_iglob,
|
|
14
|
-
fs_isabs,
|
|
15
|
-
fs_isdir,
|
|
16
|
-
fs_isfile,
|
|
17
|
-
fs_islink,
|
|
18
|
-
fs_ismount,
|
|
19
|
-
fs_listdir,
|
|
20
|
-
fs_load_from,
|
|
21
|
-
fs_lstat,
|
|
22
|
-
fs_makedirs,
|
|
23
|
-
fs_move,
|
|
24
|
-
fs_readlink,
|
|
25
|
-
fs_realpath,
|
|
26
|
-
fs_relpath,
|
|
27
|
-
fs_remove,
|
|
28
|
-
fs_rename,
|
|
29
|
-
fs_resolve,
|
|
30
|
-
fs_save_as,
|
|
31
|
-
fs_scan,
|
|
32
|
-
fs_scan_stat,
|
|
33
|
-
fs_scandir,
|
|
34
|
-
fs_stat,
|
|
35
|
-
fs_symlink,
|
|
36
|
-
fs_sync,
|
|
37
|
-
fs_unlink,
|
|
38
|
-
fs_walk,
|
|
39
|
-
is_fs,
|
|
40
|
-
)
|
|
41
|
-
from megfile.fs_path import FSPath
|
|
42
|
-
from megfile.hdfs import (
|
|
43
|
-
hdfs_exists,
|
|
44
|
-
hdfs_getmd5,
|
|
45
|
-
hdfs_getmtime,
|
|
46
|
-
hdfs_getsize,
|
|
47
|
-
hdfs_glob,
|
|
48
|
-
hdfs_glob_stat,
|
|
49
|
-
hdfs_iglob,
|
|
50
|
-
hdfs_isdir,
|
|
51
|
-
hdfs_isfile,
|
|
52
|
-
hdfs_listdir,
|
|
53
|
-
hdfs_load_from,
|
|
54
|
-
hdfs_makedirs,
|
|
55
|
-
hdfs_move,
|
|
56
|
-
hdfs_open,
|
|
57
|
-
hdfs_remove,
|
|
58
|
-
hdfs_save_as,
|
|
59
|
-
hdfs_scan,
|
|
60
|
-
hdfs_scan_stat,
|
|
61
|
-
hdfs_scandir,
|
|
62
|
-
hdfs_stat,
|
|
63
|
-
hdfs_unlink,
|
|
64
|
-
hdfs_walk,
|
|
65
|
-
is_hdfs,
|
|
66
|
-
)
|
|
67
|
-
from megfile.hdfs_path import HdfsPath
|
|
68
|
-
from megfile.http import (
|
|
69
|
-
http_exists,
|
|
70
|
-
http_getmtime,
|
|
71
|
-
http_getsize,
|
|
72
|
-
http_open,
|
|
73
|
-
http_stat,
|
|
74
|
-
is_http,
|
|
75
|
-
)
|
|
76
|
-
from megfile.http_path import HttpPath, HttpsPath
|
|
77
|
-
from megfile.s3 import (
|
|
1
|
+
from megfile.fs_path import FSPath, is_fs
|
|
2
|
+
from megfile.hdfs_path import HdfsPath, is_hdfs
|
|
3
|
+
from megfile.http_path import HttpPath, HttpsPath, is_http
|
|
4
|
+
from megfile.s3_path import (
|
|
5
|
+
S3Path,
|
|
78
6
|
is_s3,
|
|
79
|
-
s3_access,
|
|
80
7
|
s3_buffered_open,
|
|
81
8
|
s3_cached_open,
|
|
82
|
-
s3_concat,
|
|
83
|
-
s3_copy,
|
|
84
|
-
s3_download,
|
|
85
|
-
s3_exists,
|
|
86
|
-
s3_getmd5,
|
|
87
|
-
s3_getmtime,
|
|
88
|
-
s3_getsize,
|
|
89
|
-
s3_glob,
|
|
90
|
-
s3_glob_stat,
|
|
91
|
-
s3_hasbucket,
|
|
92
|
-
s3_iglob,
|
|
93
|
-
s3_isdir,
|
|
94
|
-
s3_isfile,
|
|
95
|
-
s3_listdir,
|
|
96
|
-
s3_load_content,
|
|
97
|
-
s3_load_from,
|
|
98
|
-
s3_lstat,
|
|
99
|
-
s3_makedirs,
|
|
100
9
|
s3_memory_open,
|
|
101
|
-
s3_move,
|
|
102
|
-
s3_open,
|
|
103
|
-
s3_path_join,
|
|
104
10
|
s3_pipe_open,
|
|
105
11
|
s3_prefetch_open,
|
|
106
|
-
|
|
107
|
-
s3_remove,
|
|
108
|
-
s3_rename,
|
|
109
|
-
s3_save_as,
|
|
110
|
-
s3_scan,
|
|
111
|
-
s3_scan_stat,
|
|
112
|
-
s3_scandir,
|
|
113
|
-
s3_stat,
|
|
114
|
-
s3_symlink,
|
|
115
|
-
s3_sync,
|
|
116
|
-
s3_unlink,
|
|
117
|
-
s3_upload,
|
|
118
|
-
s3_walk,
|
|
119
|
-
)
|
|
120
|
-
from megfile.s3_path import S3Path
|
|
121
|
-
from megfile.sftp import (
|
|
122
|
-
is_sftp,
|
|
123
|
-
sftp_absolute,
|
|
124
|
-
sftp_add_host_key,
|
|
125
|
-
sftp_chmod,
|
|
126
|
-
sftp_concat,
|
|
127
|
-
sftp_copy,
|
|
128
|
-
sftp_exists,
|
|
129
|
-
sftp_getmd5,
|
|
130
|
-
sftp_getmtime,
|
|
131
|
-
sftp_getsize,
|
|
132
|
-
sftp_glob,
|
|
133
|
-
sftp_glob_stat,
|
|
134
|
-
sftp_iglob,
|
|
135
|
-
sftp_isdir,
|
|
136
|
-
sftp_isfile,
|
|
137
|
-
sftp_islink,
|
|
138
|
-
sftp_listdir,
|
|
139
|
-
sftp_load_from,
|
|
140
|
-
sftp_lstat,
|
|
141
|
-
sftp_makedirs,
|
|
142
|
-
sftp_move,
|
|
143
|
-
sftp_open,
|
|
144
|
-
sftp_path_join,
|
|
145
|
-
sftp_readlink,
|
|
146
|
-
sftp_realpath,
|
|
147
|
-
sftp_remove,
|
|
148
|
-
sftp_rename,
|
|
149
|
-
sftp_resolve,
|
|
150
|
-
sftp_rmdir,
|
|
151
|
-
sftp_save_as,
|
|
152
|
-
sftp_scan,
|
|
153
|
-
sftp_scan_stat,
|
|
154
|
-
sftp_scandir,
|
|
155
|
-
sftp_stat,
|
|
156
|
-
sftp_symlink,
|
|
157
|
-
sftp_sync,
|
|
158
|
-
sftp_unlink,
|
|
159
|
-
sftp_walk,
|
|
12
|
+
s3_share_cache_open,
|
|
160
13
|
)
|
|
161
|
-
from megfile.sftp_path import SftpPath
|
|
14
|
+
from megfile.sftp_path import SftpPath, is_sftp, sftp_add_host_key
|
|
162
15
|
from megfile.smart import (
|
|
163
16
|
smart_access,
|
|
164
17
|
smart_cache,
|
|
@@ -202,8 +55,7 @@ from megfile.smart import (
|
|
|
202
55
|
smart_walk,
|
|
203
56
|
)
|
|
204
57
|
from megfile.smart_path import SmartPath
|
|
205
|
-
from megfile.
|
|
206
|
-
from megfile.stdio_path import StdioPath
|
|
58
|
+
from megfile.stdio_path import StdioPath, is_stdio
|
|
207
59
|
from megfile.version import VERSION as __version__ # noqa: F401
|
|
208
60
|
|
|
209
61
|
try:
|
|
@@ -211,6 +63,11 @@ try:
|
|
|
211
63
|
except ImportError:
|
|
212
64
|
Sftp2Path = None
|
|
213
65
|
|
|
66
|
+
try:
|
|
67
|
+
from megfile.webdav_path import WebdavPath, is_webdav
|
|
68
|
+
except ImportError:
|
|
69
|
+
WebdavPath = is_webdav = None
|
|
70
|
+
|
|
214
71
|
__all__ = [
|
|
215
72
|
"smart_access",
|
|
216
73
|
"smart_cache",
|
|
@@ -254,153 +111,21 @@ __all__ = [
|
|
|
254
111
|
"smart_lstat",
|
|
255
112
|
"smart_concat",
|
|
256
113
|
"is_s3",
|
|
257
|
-
"s3_access",
|
|
258
114
|
"s3_buffered_open",
|
|
259
115
|
"s3_cached_open",
|
|
260
|
-
"s3_copy",
|
|
261
|
-
"s3_download",
|
|
262
|
-
"s3_exists",
|
|
263
|
-
"s3_getmd5",
|
|
264
|
-
"s3_getmtime",
|
|
265
|
-
"s3_getsize",
|
|
266
|
-
"s3_glob_stat",
|
|
267
|
-
"s3_glob",
|
|
268
|
-
"s3_hasbucket",
|
|
269
|
-
"s3_iglob",
|
|
270
|
-
"s3_isdir",
|
|
271
|
-
"s3_isfile",
|
|
272
|
-
"s3_listdir",
|
|
273
|
-
"s3_load_content",
|
|
274
|
-
"s3_load_from",
|
|
275
|
-
"s3_makedirs",
|
|
276
116
|
"s3_memory_open",
|
|
277
|
-
"s3_open",
|
|
278
|
-
"s3_path_join",
|
|
279
117
|
"s3_pipe_open",
|
|
280
118
|
"s3_prefetch_open",
|
|
281
|
-
"
|
|
282
|
-
"s3_rename",
|
|
283
|
-
"s3_move",
|
|
284
|
-
"s3_sync",
|
|
285
|
-
"s3_save_as",
|
|
286
|
-
"s3_scan_stat",
|
|
287
|
-
"s3_scan",
|
|
288
|
-
"s3_scandir",
|
|
289
|
-
"s3_stat",
|
|
290
|
-
"s3_lstat",
|
|
291
|
-
"s3_unlink",
|
|
292
|
-
"s3_upload",
|
|
293
|
-
"s3_walk",
|
|
294
|
-
"s3_symlink",
|
|
295
|
-
"s3_readlink",
|
|
296
|
-
"s3_concat",
|
|
119
|
+
"s3_share_cache_open",
|
|
297
120
|
"is_fs",
|
|
298
|
-
"fs_abspath",
|
|
299
|
-
"fs_access",
|
|
300
|
-
"fs_exists",
|
|
301
|
-
"fs_getmtime",
|
|
302
|
-
"fs_getsize",
|
|
303
|
-
"fs_glob_stat",
|
|
304
|
-
"fs_glob",
|
|
305
|
-
"fs_iglob",
|
|
306
|
-
"fs_isabs",
|
|
307
|
-
"fs_isdir",
|
|
308
|
-
"fs_isfile",
|
|
309
|
-
"fs_islink",
|
|
310
|
-
"fs_ismount",
|
|
311
|
-
"fs_listdir",
|
|
312
|
-
"fs_load_from",
|
|
313
|
-
"fs_makedirs",
|
|
314
|
-
"fs_realpath",
|
|
315
|
-
"fs_relpath",
|
|
316
|
-
"fs_remove",
|
|
317
|
-
"fs_rename",
|
|
318
|
-
"fs_move",
|
|
319
|
-
"fs_sync",
|
|
320
|
-
"fs_save_as",
|
|
321
|
-
"fs_scan_stat",
|
|
322
|
-
"fs_scan",
|
|
323
|
-
"fs_scandir",
|
|
324
|
-
"fs_stat",
|
|
325
|
-
"fs_lstat",
|
|
326
|
-
"fs_unlink",
|
|
327
|
-
"fs_walk",
|
|
328
|
-
"fs_cwd",
|
|
329
|
-
"fs_home",
|
|
330
|
-
"fs_expanduser",
|
|
331
|
-
"fs_resolve",
|
|
332
|
-
"fs_getmd5",
|
|
333
|
-
"fs_symlink",
|
|
334
|
-
"fs_readlink",
|
|
335
121
|
"is_http",
|
|
336
|
-
"http_open",
|
|
337
|
-
"http_stat",
|
|
338
|
-
"http_getsize",
|
|
339
|
-
"http_getmtime",
|
|
340
|
-
"http_exists",
|
|
341
122
|
"is_stdio",
|
|
342
123
|
"stdio_open",
|
|
343
124
|
"is_sftp",
|
|
344
|
-
"sftp_readlink",
|
|
345
|
-
"sftp_absolute",
|
|
346
|
-
"sftp_glob",
|
|
347
|
-
"sftp_iglob",
|
|
348
|
-
"sftp_glob_stat",
|
|
349
|
-
"sftp_resolve",
|
|
350
|
-
"sftp_isdir",
|
|
351
|
-
"sftp_exists",
|
|
352
|
-
"sftp_scandir",
|
|
353
|
-
"sftp_getmtime",
|
|
354
|
-
"sftp_getsize",
|
|
355
|
-
"sftp_isfile",
|
|
356
|
-
"sftp_listdir",
|
|
357
|
-
"sftp_load_from",
|
|
358
|
-
"sftp_makedirs",
|
|
359
|
-
"sftp_realpath",
|
|
360
|
-
"sftp_rename",
|
|
361
|
-
"sftp_move",
|
|
362
|
-
"sftp_remove",
|
|
363
|
-
"sftp_scan",
|
|
364
|
-
"sftp_scan_stat",
|
|
365
|
-
"sftp_stat",
|
|
366
|
-
"sftp_lstat",
|
|
367
|
-
"sftp_unlink",
|
|
368
|
-
"sftp_walk",
|
|
369
|
-
"sftp_path_join",
|
|
370
|
-
"sftp_getmd5",
|
|
371
|
-
"sftp_symlink",
|
|
372
|
-
"sftp_islink",
|
|
373
|
-
"sftp_save_as",
|
|
374
|
-
"sftp_open",
|
|
375
|
-
"sftp_chmod",
|
|
376
|
-
"sftp_rmdir",
|
|
377
|
-
"sftp_copy",
|
|
378
|
-
"sftp_sync",
|
|
379
|
-
"sftp_concat",
|
|
380
125
|
"sftp_add_host_key",
|
|
381
126
|
"is_hdfs",
|
|
382
|
-
"
|
|
383
|
-
"
|
|
384
|
-
"hdfs_getmtime",
|
|
385
|
-
"hdfs_getsize",
|
|
386
|
-
"hdfs_isdir",
|
|
387
|
-
"hdfs_isfile",
|
|
388
|
-
"hdfs_listdir",
|
|
389
|
-
"hdfs_load_from",
|
|
390
|
-
"hdfs_move",
|
|
391
|
-
"hdfs_remove",
|
|
392
|
-
"hdfs_scan",
|
|
393
|
-
"hdfs_scan_stat",
|
|
394
|
-
"hdfs_scandir",
|
|
395
|
-
"hdfs_unlink",
|
|
396
|
-
"hdfs_walk",
|
|
397
|
-
"hdfs_getmd5",
|
|
398
|
-
"hdfs_save_as",
|
|
399
|
-
"hdfs_open",
|
|
400
|
-
"hdfs_glob",
|
|
401
|
-
"hdfs_glob_stat",
|
|
402
|
-
"hdfs_iglob",
|
|
403
|
-
"hdfs_makedirs",
|
|
127
|
+
"is_webdav",
|
|
128
|
+
"WebdavPath",
|
|
404
129
|
"S3Path",
|
|
405
130
|
"FSPath",
|
|
406
131
|
"HttpPath",
|
megfile/cli.py
CHANGED
|
@@ -19,7 +19,7 @@ from megfile.hdfs_path import DEFAULT_HDFS_TIMEOUT
|
|
|
19
19
|
from megfile.interfaces import FileEntry
|
|
20
20
|
from megfile.lib.glob import get_non_glob_dir, has_magic
|
|
21
21
|
from megfile.s3_path import get_s3_session
|
|
22
|
-
from megfile.
|
|
22
|
+
from megfile.sftp_path import sftp_add_host_key
|
|
23
23
|
from megfile.smart import (
|
|
24
24
|
_smart_sync_single_file,
|
|
25
25
|
smart_copy,
|
|
@@ -86,33 +86,33 @@ def safe_cli(): # pragma: no cover
|
|
|
86
86
|
sys.exit(1)
|
|
87
87
|
|
|
88
88
|
|
|
89
|
-
def get_echo_path(file_stat, base_path: str = "",
|
|
89
|
+
def get_echo_path(file_stat, base_path: str = "", full: bool = False):
|
|
90
90
|
if base_path == file_stat.path:
|
|
91
91
|
path = file_stat.name
|
|
92
|
-
elif
|
|
92
|
+
elif full:
|
|
93
93
|
path = file_stat.path
|
|
94
94
|
else:
|
|
95
95
|
path = smart_relpath(file_stat.path, start=base_path)
|
|
96
96
|
return path
|
|
97
97
|
|
|
98
98
|
|
|
99
|
-
def simple_echo(file_stat, base_path: str = "",
|
|
100
|
-
return get_echo_path(file_stat, base_path,
|
|
99
|
+
def simple_echo(file_stat, base_path: str = "", full: bool = False):
|
|
100
|
+
return get_echo_path(file_stat, base_path, full)
|
|
101
101
|
|
|
102
102
|
|
|
103
|
-
def long_echo(file_stat, base_path: str = "",
|
|
103
|
+
def long_echo(file_stat, base_path: str = "", full: bool = False):
|
|
104
104
|
return "%12d %s %s" % (
|
|
105
105
|
file_stat.stat.size,
|
|
106
106
|
time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(file_stat.stat.mtime)),
|
|
107
|
-
get_echo_path(file_stat, base_path,
|
|
107
|
+
get_echo_path(file_stat, base_path, full),
|
|
108
108
|
)
|
|
109
109
|
|
|
110
110
|
|
|
111
|
-
def human_echo(file_stat, base_path: str = "",
|
|
111
|
+
def human_echo(file_stat, base_path: str = "", full: bool = False):
|
|
112
112
|
return "%10s %s %s" % (
|
|
113
113
|
get_human_size(file_stat.stat.size),
|
|
114
114
|
time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(file_stat.stat.mtime)),
|
|
115
|
-
get_echo_path(file_stat, base_path,
|
|
115
|
+
get_echo_path(file_stat, base_path, full),
|
|
116
116
|
)
|
|
117
117
|
|
|
118
118
|
|
|
@@ -143,13 +143,12 @@ def _sftp_prompt_host_key(path):
|
|
|
143
143
|
)
|
|
144
144
|
|
|
145
145
|
|
|
146
|
-
def _ls(path: str, long: bool, recursive: bool, human_readable: bool):
|
|
146
|
+
def _ls(path: str, long: bool, full: bool, recursive: bool, human_readable: bool):
|
|
147
147
|
base_path = path
|
|
148
|
-
full_path = False
|
|
149
148
|
if has_magic(path):
|
|
150
149
|
scan_func = smart_glob_stat
|
|
151
150
|
base_path = get_non_glob_dir(path)
|
|
152
|
-
|
|
151
|
+
full = True
|
|
153
152
|
elif recursive:
|
|
154
153
|
scan_func = smart_scan_stat
|
|
155
154
|
else:
|
|
@@ -170,8 +169,8 @@ def _ls(path: str, long: bool, recursive: bool, human_readable: bool):
|
|
|
170
169
|
for file_stat in scan_func(path):
|
|
171
170
|
total_size += file_stat.stat.size
|
|
172
171
|
total_count += 1
|
|
173
|
-
output = echo_func(file_stat, base_path,
|
|
174
|
-
if file_stat.is_symlink():
|
|
172
|
+
output = echo_func(file_stat, base_path, full=full)
|
|
173
|
+
if long and file_stat.is_symlink():
|
|
175
174
|
output += " -> %s" % smart_readlink(file_stat.path)
|
|
176
175
|
click.echo(output)
|
|
177
176
|
if long:
|
|
@@ -215,6 +214,12 @@ ZshComplete.source_template = ZshComplete.source_template.replace(
|
|
|
215
214
|
is_flag=True,
|
|
216
215
|
help="List all the objects in the path with size, modification time and path.",
|
|
217
216
|
)
|
|
217
|
+
@click.option(
|
|
218
|
+
"-f",
|
|
219
|
+
"--full",
|
|
220
|
+
is_flag=True,
|
|
221
|
+
help="Displays the full path of each file.",
|
|
222
|
+
)
|
|
218
223
|
@click.option(
|
|
219
224
|
"-r",
|
|
220
225
|
"--recursive",
|
|
@@ -228,12 +233,24 @@ ZshComplete.source_template = ZshComplete.source_template.replace(
|
|
|
228
233
|
is_flag=True,
|
|
229
234
|
help="Displays file sizes in human readable format.",
|
|
230
235
|
)
|
|
231
|
-
def ls(path: str, long: bool, recursive: bool, human_readable: bool):
|
|
232
|
-
_ls(
|
|
236
|
+
def ls(path: str, long: bool, full: bool, recursive: bool, human_readable: bool):
|
|
237
|
+
_ls(
|
|
238
|
+
path,
|
|
239
|
+
long=long,
|
|
240
|
+
full=full,
|
|
241
|
+
recursive=recursive,
|
|
242
|
+
human_readable=human_readable,
|
|
243
|
+
)
|
|
233
244
|
|
|
234
245
|
|
|
235
246
|
@cli.command(short_help="List all the objects in the path.")
|
|
236
247
|
@click.argument("path", type=PathType())
|
|
248
|
+
@click.option(
|
|
249
|
+
"-f",
|
|
250
|
+
"--full",
|
|
251
|
+
is_flag=True,
|
|
252
|
+
help="Displays the full path of each file.",
|
|
253
|
+
)
|
|
237
254
|
@click.option(
|
|
238
255
|
"-r",
|
|
239
256
|
"--recursive",
|
|
@@ -241,8 +258,8 @@ def ls(path: str, long: bool, recursive: bool, human_readable: bool):
|
|
|
241
258
|
help="Command is performed on all files or objects under "
|
|
242
259
|
"the specified directory or prefix.",
|
|
243
260
|
)
|
|
244
|
-
def ll(path: str, recursive: bool):
|
|
245
|
-
_ls(path, long=True, recursive=recursive, human_readable=True)
|
|
261
|
+
def ll(path: str, recursive: bool, full: bool):
|
|
262
|
+
_ls(path, long=True, full=full, recursive=recursive, human_readable=True)
|
|
246
263
|
|
|
247
264
|
|
|
248
265
|
@cli.command(short_help="Copy files from source to dest, skipping already copied.")
|
|
@@ -342,8 +359,8 @@ def mv(
|
|
|
342
359
|
_sftp_prompt_host_key(dst_path)
|
|
343
360
|
|
|
344
361
|
if progress_bar:
|
|
345
|
-
src_protocol
|
|
346
|
-
dst_protocol
|
|
362
|
+
src_protocol = SmartPath._extract_protocol(src_path)
|
|
363
|
+
dst_protocol = SmartPath._extract_protocol(dst_path)
|
|
347
364
|
|
|
348
365
|
if recursive:
|
|
349
366
|
if src_protocol == dst_protocol:
|
megfile/config.py
CHANGED
|
@@ -125,10 +125,19 @@ HDFS_MAX_RETRY_TIMES = int(
|
|
|
125
125
|
SFTP_MAX_RETRY_TIMES = int(
|
|
126
126
|
os.getenv("MEGFILE_SFTP_MAX_RETRY_TIMES") or DEFAULT_MAX_RETRY_TIMES
|
|
127
127
|
)
|
|
128
|
+
WEBDAV_MAX_RETRY_TIMES = int(
|
|
129
|
+
os.getenv("MEGFILE_WEBDAV_MAX_RETRY_TIMES") or DEFAULT_MAX_RETRY_TIMES
|
|
130
|
+
)
|
|
128
131
|
|
|
129
132
|
SFTP_HOST_KEY_POLICY = os.getenv("MEGFILE_SFTP_HOST_KEY_POLICY")
|
|
130
133
|
|
|
131
|
-
HTTP_AUTH_HEADERS = (
|
|
134
|
+
HTTP_AUTH_HEADERS = (
|
|
135
|
+
"Authorization",
|
|
136
|
+
"Www-Authenticate",
|
|
137
|
+
"Cookie",
|
|
138
|
+
"Cookie2",
|
|
139
|
+
"X-Amz-Security-Token",
|
|
140
|
+
)
|
|
132
141
|
|
|
133
142
|
if os.getenv("MEGFILE_LOG_LEVEL"):
|
|
134
143
|
set_log_level()
|
megfile/errors.py
CHANGED
|
@@ -50,8 +50,7 @@ _logger = getLogger(__name__)
|
|
|
50
50
|
|
|
51
51
|
|
|
52
52
|
def s3_endpoint_url(path: Optional[PathLike] = None):
|
|
53
|
-
from megfile.
|
|
54
|
-
from megfile.s3_path import S3Path
|
|
53
|
+
from megfile.s3_path import S3Path, get_endpoint_url, get_s3_client
|
|
55
54
|
|
|
56
55
|
profile_name = None
|
|
57
56
|
if path:
|
|
@@ -137,6 +136,7 @@ s3_retry_error_codes = (
|
|
|
137
136
|
"UploadTrafficRateLimitExceeded",
|
|
138
137
|
"MetaOperationQpsLimitExceeded",
|
|
139
138
|
"TotalQpsLimitExceeded",
|
|
139
|
+
"PartitionQpsLimitted",
|
|
140
140
|
"ActiveRequestLimitExceeded",
|
|
141
141
|
"CpuLimitExceeded",
|
|
142
142
|
"QpsLimitExceeded",
|
megfile/fs_path.py
CHANGED
|
@@ -17,6 +17,7 @@ from megfile.interfaces import (
|
|
|
17
17
|
Access,
|
|
18
18
|
ContextIterator,
|
|
19
19
|
FileEntry,
|
|
20
|
+
FileLike,
|
|
20
21
|
PathLike,
|
|
21
22
|
StatResult,
|
|
22
23
|
URIPath,
|
|
@@ -32,7 +33,7 @@ from megfile.utils import calculate_md5, copyfd
|
|
|
32
33
|
__all__ = [
|
|
33
34
|
"FSPath",
|
|
34
35
|
"is_fs",
|
|
35
|
-
"
|
|
36
|
+
"fs_copy",
|
|
36
37
|
]
|
|
37
38
|
|
|
38
39
|
|
|
@@ -60,8 +61,37 @@ def is_fs(path: Union["PathLike", int]) -> bool:
|
|
|
60
61
|
return scheme == "" or scheme == "file"
|
|
61
62
|
|
|
62
63
|
|
|
63
|
-
def
|
|
64
|
-
|
|
64
|
+
def fs_copy(
|
|
65
|
+
src_path: PathLike,
|
|
66
|
+
dst_path: PathLike,
|
|
67
|
+
callback: Optional[Callable[[int], None]] = None,
|
|
68
|
+
followlinks: bool = False,
|
|
69
|
+
overwrite: bool = True,
|
|
70
|
+
):
|
|
71
|
+
"""File copy on file system
|
|
72
|
+
Copy content (excluding meta date) of file on `src_path` to `dst_path`.
|
|
73
|
+
`dst_path` must be a complete file name
|
|
74
|
+
|
|
75
|
+
.. note ::
|
|
76
|
+
|
|
77
|
+
The differences between this function and shutil.copyfile are:
|
|
78
|
+
|
|
79
|
+
1. If parent directory of dst_path doesn't exist, create it
|
|
80
|
+
|
|
81
|
+
2. Allow callback function, None by default.
|
|
82
|
+
callback: Optional[Callable[[int], None]], the int data is means
|
|
83
|
+
the size (in bytes) of the written data that is passed periodically
|
|
84
|
+
|
|
85
|
+
3. This function is thread-unsafe
|
|
86
|
+
|
|
87
|
+
:param src_path: Given path
|
|
88
|
+
:param dst_path: Target file path
|
|
89
|
+
:param callback: Called periodically during copy, and the input parameter is
|
|
90
|
+
the data size (in bytes) of copy since the last call
|
|
91
|
+
:param followlinks: False if regard symlink as file, else True
|
|
92
|
+
:param overwrite: whether or not overwrite file when exists, default is True
|
|
93
|
+
"""
|
|
94
|
+
return FSPath(src_path).copy(dst_path, callback, followlinks, overwrite)
|
|
65
95
|
|
|
66
96
|
|
|
67
97
|
def _fs_rename_file(
|
|
@@ -85,6 +115,36 @@ def _fs_rename_file(
|
|
|
85
115
|
shutil.move(src_path, dst_path)
|
|
86
116
|
|
|
87
117
|
|
|
118
|
+
class WrapAtomic(FileLike):
|
|
119
|
+
__atomic__ = True
|
|
120
|
+
|
|
121
|
+
def __init__(self, fileobj):
|
|
122
|
+
self.fileobj = fileobj
|
|
123
|
+
self.temp_name = f"{self.name}.temp"
|
|
124
|
+
os.rename(self.name, self.temp_name)
|
|
125
|
+
|
|
126
|
+
@property
|
|
127
|
+
def name(self):
|
|
128
|
+
return self.fileobj.name
|
|
129
|
+
|
|
130
|
+
@property
|
|
131
|
+
def mode(self):
|
|
132
|
+
return self.fileobj.mode
|
|
133
|
+
|
|
134
|
+
def _close(self):
|
|
135
|
+
self.fileobj.close()
|
|
136
|
+
os.rename(self.temp_name, self.name)
|
|
137
|
+
|
|
138
|
+
def _abort(self):
|
|
139
|
+
try:
|
|
140
|
+
os.unlink(self.temp_name)
|
|
141
|
+
except FileNotFoundError:
|
|
142
|
+
pass
|
|
143
|
+
|
|
144
|
+
def __getattr__(self, name: str):
|
|
145
|
+
return getattr(self.fileobj, name)
|
|
146
|
+
|
|
147
|
+
|
|
88
148
|
@SmartPath.register
|
|
89
149
|
class FSPath(URIPath):
|
|
90
150
|
"""file protocol
|
|
@@ -627,9 +687,11 @@ class FSPath(URIPath):
|
|
|
627
687
|
"""
|
|
628
688
|
self._check_int_path()
|
|
629
689
|
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
690
|
+
try:
|
|
691
|
+
os.unlink(self.path_without_protocol) # pyre-ignore[6]
|
|
692
|
+
except FileNotFoundError:
|
|
693
|
+
if not missing_ok:
|
|
694
|
+
raise
|
|
633
695
|
|
|
634
696
|
def walk(
|
|
635
697
|
self, followlinks: bool = False
|
|
@@ -917,11 +979,12 @@ class FSPath(URIPath):
|
|
|
917
979
|
def open(
|
|
918
980
|
self,
|
|
919
981
|
mode: str = "r",
|
|
920
|
-
buffering
|
|
921
|
-
encoding=None,
|
|
922
|
-
errors=None,
|
|
923
|
-
newline=None,
|
|
924
|
-
closefd=True,
|
|
982
|
+
buffering: int = -1,
|
|
983
|
+
encoding: Optional[str] = None,
|
|
984
|
+
errors: Optional[str] = None,
|
|
985
|
+
newline: Optional[str] = None,
|
|
986
|
+
closefd: bool = True,
|
|
987
|
+
atomic: bool = False,
|
|
925
988
|
**kwargs,
|
|
926
989
|
) -> IO:
|
|
927
990
|
if not isinstance(self.path_without_protocol, int) and (
|
|
@@ -932,7 +995,7 @@ class FSPath(URIPath):
|
|
|
932
995
|
self.path_without_protocol # pyre-ignore[6]
|
|
933
996
|
)
|
|
934
997
|
).mkdir(parents=True, exist_ok=True)
|
|
935
|
-
|
|
998
|
+
fp = io.open(
|
|
936
999
|
self.path_without_protocol,
|
|
937
1000
|
mode,
|
|
938
1001
|
buffering=buffering,
|
|
@@ -941,6 +1004,9 @@ class FSPath(URIPath):
|
|
|
941
1004
|
newline=newline,
|
|
942
1005
|
closefd=closefd,
|
|
943
1006
|
)
|
|
1007
|
+
if atomic and ("w" in mode or "x" in mode or "a" in mode):
|
|
1008
|
+
return WrapAtomic(fp)
|
|
1009
|
+
return fp
|
|
944
1010
|
|
|
945
1011
|
@cached_property
|
|
946
1012
|
def parts(self) -> Tuple[str, ...]:
|