9 import cephfs
as libcephfs
20 from cmd2
import with_argparser
22 def with_argparser(argparser
):
25 def argparser_decorator(func
):
26 @functools.wraps(func
)
27 def wrapper(thiz
, cmdline
):
28 if isinstance(cmdline
, list):
31 # do not split if it's already a list
32 arglist
= shlex
.split(cmdline
, posix
=False)
33 # in case user quotes the command args
34 arglist
= [arg
.strip('\'""') for arg
in arglist
]
36 args
= argparser
.parse_args(arglist
)
38 # argparse exits at seeing bad arguments
41 return func(thiz
, args
)
42 argparser
.prog
= func
.__name
__[3:]
43 if argparser
.description
is None and func
.__doc
__:
44 argparser
.description
= func
.__doc
__
48 return argparser_decorator
54 def setup_cephfs(config_file
):
59 cephfs
= libcephfs
.LibCephFS(conffile
=config_file
)
63 def mode_notation(mode
):
66 permission_bits
= {'0': '---',
79 notation
+= permission_bits
[i
]
83 def get_chunks(file_size
):
85 chunk_size
= 0x20000 # 131072 bytes, default max ssl buffer size
86 while chunk_start
+ chunk_size
< file_size
:
87 yield(chunk_start
, chunk_size
)
88 chunk_start
+= chunk_size
89 final_chunk_size
= file_size
- chunk_start
90 yield(chunk_start
, final_chunk_size
)
94 return bytes(string
, encoding
='utf-8')
97 def list_items(dir_name
=''):
98 if not isinstance(dir_name
, bytes
):
99 dir_name
= to_bytes(dir_name
)
101 d
= cephfs
.opendir(cephfs
.getcwd())
103 d
= cephfs
.opendir(dir_name
)
104 dent
= cephfs
.readdir(d
)
108 dent
= cephfs
.readdir(d
)
113 def glob(dir_name
, pattern
):
114 if isinstance(dir_name
, bytes
):
115 dir_name
= dir_name
.decode('utf-8')
117 parent_dir
= os
.path
.dirname(dir_name
)
120 if dir_name
== '/' or is_dir_exists(os
.path
.basename(dir_name
), parent_dir
):
121 for i
in list_items(dir_name
)[2:]:
122 if fnmatch
.fnmatch(i
.d_name
.decode('utf-8'), pattern
):
123 paths
.append(os
.path
.join(dir_name
, i
.d_name
.decode('utf-8')))
127 def locate_file(name
, case_sensitive
=True):
128 if not case_sensitive
:
129 return [i
for i
in sorted(set(dirwalk(cephfs
.getcwd().decode('utf-8')))) if name
.lower() in i
.lower()]
131 return [i
for i
in sorted(set(dirwalk(cephfs
.getcwd().decode('utf-8')))) if name
in i
]
134 def get_all_possible_paths(pattern
):
135 complete_pattern
= pattern
[:]
137 is_rel_path
= not os
.path
.isabs(pattern
)
139 dir_
= cephfs
.getcwd()
142 pattern
= pattern
[1:]
143 patterns
= pattern
.split('/')
144 paths
.extend(glob(dir_
, patterns
[0]))
146 for pattern
in patterns
:
148 paths
.extend(glob(path
, pattern
))
149 return [path
for path
in paths
if fnmatch
.fnmatch(path
, os
.path
.join(cephfs
.getcwd().decode('utf-8'), complete_pattern
))]
152 suffixes
= ['B', 'K', 'M', 'G', 'T', 'P']
155 def humansize(nbytes
):
157 while nbytes
>= 1024 and i
< len(suffixes
)-1:
160 nbytes
= math
.ceil(nbytes
)
161 f
= ('%d' % nbytes
).rstrip('.')
162 return '%s%s' % (f
, suffixes
[i
])
165 def print_long(shell
, file_name
, is_dir
, human_readable
):
166 if not isinstance(file_name
, bytes
):
167 file_name
= to_bytes(file_name
)
168 info
= cephfs
.stat(file_name
)
169 file_name
= os
.path
.basename(file_name
.decode('utf-8'))
171 file_name
= shell
.colorize(file_name
+'/', 'blue')
173 shell
.poutput('{}\t{:10s} {} {} {} {}'.format(
174 mode_notation(info
.st_mode
),
175 humansize(info
.st_size
), info
.st_uid
,
176 info
.st_gid
, info
.st_mtime
, file_name
, sep
='\t'))
178 shell
.poutput('{} {:12d} {} {} {} {}'.format(
179 mode_notation(info
.st_mode
), info
.st_size
, info
.st_uid
,
180 info
.st_gid
, info
.st_mtime
, file_name
, sep
='\t'))
185 Returns the word length, minus any color codes.
187 if word
[0] == '\x1b':
192 def is_dir_exists(dir_name
, dir_
=''):
194 dir_
= cephfs
.getcwd()
195 elif not isinstance(dir_
, bytes
):
196 dir_
= to_bytes(dir_
)
197 if not isinstance(dir_name
, bytes
):
198 dir_name
= to_bytes(dir_name
)
199 return len([i
for i
in set(list_items(dir_
)) if i
.d_name
== dir_name
and i
.is_dir()]) > 0
202 def is_file_exists(file_name
, dir_
=''):
204 dir_
= cephfs
.getcwd()
205 elif not isinstance(dir_
, bytes
):
206 dir_
= to_bytes(dir_
)
207 if not isinstance(file_name
, bytes
):
208 if file_name
.count('/') > 0:
209 file_name
= to_bytes(os
.path
.basename(file_name
))
211 file_name
= to_bytes(file_name
)
212 return len([i
for i
in set(list_items(dir_
)) if i
.d_name
== file_name
and not i
.is_dir()]) > 0
215 def print_list(shell
, words
, termwidth
=79):
218 width
= max([word_len(word
) for word
in words
]) + 2
220 ncols
= max(1, (termwidth
+ 1) // (width
+ 1))
221 nrows
= (nwords
+ ncols
- 1) // ncols
222 for row
in range(nrows
):
223 for i
in range(row
, nwords
, nrows
):
225 if word
[0] == '\x1b':
227 '%-*s' % (width
+ 10, words
[i
]), end
='\n' if i
+ nrows
>= nwords
else '')
230 '%-*s' % (width
, words
[i
]), end
='\n' if i
+ nrows
>= nwords
else '')
233 def copy_from_local(shell
, local_path
, remote_path
):
235 if local_path
== '-':
236 data
= ''.join([line
for line
in sys
.stdin
])
237 file_size
= len(data
)
239 file_
= open(local_path
, 'rb')
241 file_size
= os
.path
.getsize(local_path
)
242 fd
= cephfs
.open(to_bytes(remote_path
), 'w', 0o666)
247 data
= file_
.read(65536)
250 wrote
= cephfs
.write(fd
, data
, progress
)
260 def copy_to_local(shell
, remote_path
, local_path
):
262 if local_path
!= '-':
263 local_dir
= os
.path
.dirname(local_path
)
264 if not os
.path
.exists(local_dir
):
265 os
.makedirs(local_dir
)
266 if len(remote_path
.rsplit('/', 1)) > 2 and remote_path
.rsplit('/', 1)[1] == '':
268 fd
= open(local_path
, 'wb+')
269 file_
= cephfs
.open(to_bytes(remote_path
), 'r')
270 file_size
= cephfs
.stat(remote_path
).st_size
274 for chunk_start
, chunk_size
in get_chunks(file_size
):
275 file_chunk
= cephfs
.read(file_
, chunk_start
, chunk_size
)
276 progress
+= len(file_chunk
)
280 shell
.poutput(file_chunk
.decode('utf-8'))
286 def dirwalk(dir_name
):
288 walk a directory tree, using a generator
290 dir_name
= os
.path
.normpath(dir_name
)
291 for item
in list_items(dir_name
)[2:]:
292 fullpath
= os
.path
.join(dir_name
, item
.d_name
.decode('utf-8'))
293 yield fullpath
.rsplit('/', 1)[0] + '/'
294 if is_dir_exists(item
.d_name
, fullpath
.rsplit('/', 1)[0]):
295 if not len(list_items(fullpath
)[2:]):
296 yield os
.path
.normpath(fullpath
)
298 for x
in dirwalk(fullpath
):
301 yield os
.path
.normpath(fullpath
)
304 class CephFSShell(Cmd
):
307 super().__init
__(use_ipython
=False)
308 self
.working_dir
= cephfs
.getcwd().decode('utf-8')
310 self
.interactive
= False
313 def default(self
, line
):
314 self
.poutput('Unrecognized command:', line
)
316 def set_prompt(self
):
317 self
.prompt
= ('\033[01;33mCephFS:~' + colorama
.Fore
.LIGHTCYAN_EX
+
318 self
.working_dir
+ colorama
.Style
.RESET_ALL
+ '\033[01;33m>>>\033[00m ')
320 def create_argparser(self
, command
):
322 argparse_args
= getattr(self
, 'argparse_' + command
)
323 except AttributeError:
326 self
, 'do_' + command
).__doc
__.expandtabs().splitlines()
328 blank_idx
= doc_lines
.index('')
329 usage
= doc_lines
[:blank_idx
]
330 description
= doc_lines
[blank_idx
+ 1:]
334 parser
= argparse
.ArgumentParser(
336 usage
='\n'.join(usage
),
337 description
='\n'.join(description
),
338 formatter_class
=argparse
.ArgumentDefaultsHelpFormatter
340 for args
, kwargs
in argparse_args
:
341 parser
.add_argument(*args
, **kwargs
)
344 def complete_filenames(self
, text
, line
, begidx
, endidx
):
346 completions
= [x
.d_name
.decode(
347 'utf-8') + '/' * int(x
.is_dir()) for x
in list_items(cephfs
.getcwd())[2:]]
349 if text
.count('/') > 0:
350 completions
= [text
.rsplit('/', 1)[0] + '/' + x
.d_name
.decode('utf-8') + '/'*int(x
.is_dir()) for x
in list_items(
351 '/' + text
.rsplit('/', 1)[0])[2:] if x
.d_name
.decode('utf-8').startswith(text
.rsplit('/', 1)[1])]
353 completions
= [x
.d_name
.decode('utf-8') + '/' * int(x
.is_dir()) for x
in list_items()[
354 2:] if x
.d_name
.decode('utf-8').startswith(text
)]
355 if len(completions
) == 1 and completions
[0][-1] == '/':
356 dir_
, file_
= completions
[0].rsplit('/', 1)
357 completions
.extend([dir_
+ '/' + x
.d_name
.decode('utf-8') + '/' * int(x
.is_dir())
358 for x
in list_items('/' + dir_
)[2:] if x
.d_name
.decode('utf-8').startswith(file_
)])
359 return self
.delimiter_complete(text
, line
, begidx
, endidx
, completions
, '/')
362 def onecmd(self
, line
):
367 res
= Cmd
.onecmd(self
, line
)
371 except ConnectionError
as e
:
372 self
.poutput('***', e
)
373 except KeyboardInterrupt:
374 self
.poutput('Command aborted')
375 except Exception as e
:
377 traceback
.print_exc(file=sys
.stdout
)
379 def complete_mkdir(self
, text
, line
, begidx
, endidx
):
381 auto complete of file name.
383 return self
.complete_filenames(text
, line
, begidx
, endidx
)
385 mkdir_parser
= argparse
.ArgumentParser(
386 description
='Create the directory(ies), if they do not already exist.')
387 mkdir_parser
.add_argument('dirs', type=str,
389 help='Name of new_directory.',
391 mkdir_parser
.add_argument('-m', '--mode', type=str,
393 help='Sets the access mode for the new directory.')
394 mkdir_parser
.add_argument('-p', '--parent', action
='store_true',
395 help='Create parent directories as necessary. \
396 When this option is specified, no error is reported if a directory already \
399 @with_argparser(mkdir_parser
)
400 def do_mkdir(self
, args
):
404 for dir_name
in args
.dirs
:
405 path
= to_bytes('/' + dir_name
)
407 permission
= int(args
.mode
, 8)
411 cephfs
.mkdirs(path
, permission
)
413 cephfs
.mkdir(path
, permission
)
415 def complete_put(self
, text
, line
, begidx
, endidx
):
417 auto complete of file name.
419 index_dict
= {1: self
.path_complete
}
420 return self
.index_based_complete(text
, line
, begidx
, endidx
, index_dict
)
422 put_parser
= argparse
.ArgumentParser(
423 description
='Copy a file/directory to Ceph File System from Local File System.')
424 put_parser
.add_argument('local_path', type=str,
425 help='Path of the file in the local system')
426 put_parser
.add_argument(
427 'remote_path', type=str, help='Path of the file in the remote system.', nargs
='?', default
='.')
428 put_parser
.add_argument('-f', '--force', action
='store_true',
429 help='Overwrites the destination if it already exists.')
431 @with_argparser(put_parser
)
432 def do_put(self
, args
):
434 Copy a file to Ceph File System from Local Directory.
436 root_src_dir
= args
.local_path
437 root_dst_dir
= args
.remote_path
438 if args
.local_path
== '.':
439 root_src_dir
= os
.getcwd()
440 if root_dst_dir
== '.':
441 root_dst_dir
= root_src_dir
.rsplit('/', 1)[1]
442 elif root_dst_dir
[-1] != '/':
444 if args
.local_path
== '-' or os
.path
.isfile(root_src_dir
):
445 copy_from_local(self
, root_src_dir
, root_dst_dir
)
447 for src_dir
, dirs
, files
in os
.walk(root_src_dir
):
448 dst_dir
= src_dir
.replace(root_src_dir
, root_dst_dir
, 1)
449 dst_dir
= re
.sub('\/+', '/', cephfs
.getcwd().decode('utf-8') + dst_dir
)
450 if args
.force
and dst_dir
!= '/' and not is_dir_exists(dst_dir
[:-1]) and len(locate_file(dst_dir
)) == 0:
451 cephfs
.mkdirs(to_bytes(dst_dir
), 0o777)
452 if not args
.force
and dst_dir
!= '/' and not is_dir_exists(dst_dir
) and not os
.path
.isfile(root_src_dir
):
454 cephfs
.mkdirs(to_bytes(dst_dir
), 0o777)
456 if not is_dir_exists(os
.path
.join(dst_dir
, dir_
)):
458 to_bytes(os
.path
.join(dst_dir
, dir_
)), 0o777)
460 src_file
= os
.path
.join(src_dir
, file_
)
461 dst_file
= re
.sub('\/+', '/', '/' + dst_dir
+ '/' + file_
)
462 if (not args
.force
) and is_file_exists(dst_file
):
464 copy_from_local(self
, src_file
, os
.path
.join(
465 cephfs
.getcwd().decode('utf-8'), dst_file
))
467 def complete_get(self
, text
, line
, begidx
, endidx
):
469 auto complete of file name.
471 return self
.complete_filenames(text
, line
, begidx
, endidx
)
473 get_parser
= argparse
.ArgumentParser(
474 description
='Copy a file from Ceph File System from Local Directory.')
475 get_parser
.add_argument('remote_path', type=str,
476 help='Path of the file in the remote system')
477 get_parser
.add_argument(
478 'local_path', type=str, help='Path of the file in the local system', nargs
='?', default
='.')
480 @with_argparser(get_parser
)
481 def do_get(self
, args
):
483 Copy a file/directory from Ceph File System to Local Directory.
485 root_src_dir
= args
.remote_path
486 root_dst_dir
= args
.local_path
487 if args
.local_path
== '.':
488 root_dst_dir
= os
.getcwd()
489 if args
.remote_path
== '.':
490 root_src_dir
= cephfs
.getcwd().decode('utf-8')
491 if args
.local_path
== '-':
492 copy_to_local(self
, root_src_dir
, '-')
493 elif is_file_exists(args
.remote_path
):
494 copy_to_local(self
, root_src_dir
,
495 root_dst_dir
+ '/' + root_src_dir
)
496 elif '/'in root_src_dir
and is_file_exists(root_src_dir
.rsplit('/', 1)[1], root_src_dir
.rsplit('/', 1)[0]):
497 copy_to_local(self
, root_src_dir
, root_dst_dir
)
499 files
= list(reversed(sorted(dirwalk(root_src_dir
))))
501 os
.makedirs(root_dst_dir
+ '/' + root_src_dir
)
503 dst_dirpath
, dst_file
= file_
.rsplit('/', 1)
504 if dst_dirpath
in files
:
505 files
.remove(dst_dirpath
)
506 dst_path
= os
.path
.join(root_dst_dir
, dst_dirpath
, dst_file
)
507 dst_path
= os
.path
.normpath(dst_path
)
508 if os
.path
.exists(dst_path
):
510 if is_dir_exists(file_
):
511 os
.makedirs(dst_path
)
513 copy_to_local(self
, file_
, dst_path
)
516 def complete_ls(self
, text
, line
, begidx
, endidx
):
518 auto complete of file name.
520 return self
.complete_filenames(text
, line
, begidx
, endidx
)
522 ls_parser
= argparse
.ArgumentParser(
523 description
='Copy a file from Ceph File System from Local Directory.')
524 ls_parser
.add_argument('-l', '--long', action
='store_true',
525 help='Detailed list of items in the directory.')
526 ls_parser
.add_argument('-r', '--reverse', action
='store_true',
527 help='Reverse order of listing items in the directory.')
528 ls_parser
.add_argument('-H', action
='store_true', help='Human Readable')
529 ls_parser
.add_argument('-a', '--all', action
='store_true',
530 help='Do not Ignore entries starting with .')
531 ls_parser
.add_argument('-S', action
='store_true', help='Sort by file_size')
532 ls_parser
.add_argument(
533 'dir_names', help='Name of Directories', nargs
='*', default
=[''])
535 @with_argparser(ls_parser
)
536 def do_ls(self
, args
):
538 List all the files and directories in the current working directory
540 directories
= args
.dir_names
541 for dir_name
in directories
:
544 if dir_name
.count('*') > 0:
545 all_items
= get_all_possible_paths(dir_name
)
546 if len(all_items
) == 0:
548 dir_name
= all_items
[0].rsplit('/', 1)[0]
553 for item
in list_items(dir_name
):
554 d_name
= item
.d_name
.decode('utf-8')
555 if os
.path
.basename(i
) == d_name
:
557 dirs
.append(os
.path
.join(dir_name
, d_name
))
561 directories
.extend(dirs
)
563 self
.poutput(dir_name
, ':\n')
564 items
= sorted(items
, key
=lambda item
: item
.d_name
)
566 if dir_name
!= '' and dir_name
!= cephfs
.getcwd().decode('utf-8') and len(directories
) > 1:
567 self
.poutput(dir_name
, ':\n')
568 items
= sorted(list_items(dir_name
),
569 key
=lambda item
: item
.d_name
)
570 if not args
.all
and len(items
) >= 2:
571 items
= [i
for i
in items
if not i
.d_name
.decode('utf-8').startswith('.')]
574 items
= sorted(items
, key
=lambda item
: cephfs
.stat(
575 to_bytes(dir_name
+ '/' + item
.d_name
.decode('utf-8'))).st_size
)
577 items
= reversed(items
)
580 if not isinstance(item
, str):
581 path
= item
.d_name
.decode('utf-8')
586 if args
.long and args
.H
:
587 print_long(self
, cephfs
.getcwd().decode(
588 'utf-8') + dir_name
+ '/' + path
, is_dir
, True)
590 print_long(self
, cephfs
.getcwd().decode(
591 'utf-8') + dir_name
+ '/' + path
, is_dir
, False)
593 values
.append(self
.colorize(path
+ '/', 'blue'))
597 print_list(self
, values
, shutil
.get_terminal_size().columns
)
598 if dir_name
!= directories
[-1]:
601 def complete_rmdir(self
, text
, line
, begidx
, endidx
):
603 auto complete of file name.
605 return self
.complete_filenames(text
, line
, begidx
, endidx
)
607 rmdir_parser
= argparse
.ArgumentParser(description
='Remove Directory.')
608 rmdir_parser
.add_argument('dir_paths', help='Directory Path.', nargs
='+')
609 rmdir_parser
.add_argument('-p', '--parent', action
='store_true',
610 help='Remove parent directories as necessary. \
611 When this option is specified, no error is reported if a directory has any \
612 sub-directories, files')
614 @with_argparser(rmdir_parser
)
615 def do_rmdir(self
, args
):
617 Remove a specific Directory
620 directories
= args
.dir_paths
621 for dir_path
in directories
:
622 if dir_path
.count('*') > 0:
624 all_items
= get_all_possible_paths(dir_path
)
625 if len(all_items
) > 0:
626 dir_path
= all_items
[0].rsplit('/', 1)[0]
631 for item
in list_items(dir_path
):
632 d_name
= item
.d_name
.decode('utf-8')
633 if os
.path
.basename(i
) == d_name
:
635 dirs
.append(os
.path
.join(dir_path
, d_name
))
636 directories
.extend(dirs
)
641 dir_path
= os
.path
.normpath(os
.path
.join(
642 cephfs
.getcwd().decode('utf-8'), dir_path
))
645 sorted(set(dirwalk(dir_path
))))
647 path
= os
.path
.normpath(path
)
648 if path
[1:] != dir_path
:
650 cephfs
.rmdir(to_bytes(path
))
651 except libcephfs
.Error
:
652 cephfs
.unlink(to_bytes(path
))
653 if not is_pattern
and dir_path
!= os
.path
.normpath(path
):
654 cephfs
.rmdir(to_bytes(dir_path
))
656 def complete_rm(self
, text
, line
, begidx
, endidx
):
658 auto complete of file name.
660 return self
.complete_filenames(text
, line
, begidx
, endidx
)
662 rm_parser
= argparse
.ArgumentParser(description
='Remove File.')
663 rm_parser
.add_argument('file_paths', help='File Path.', nargs
='+')
665 @with_argparser(rm_parser
)
666 def do_rm(self
, args
):
668 Remove a specific file
670 files
= args
.file_paths
671 for file_path
in files
:
672 if file_path
.count('*') > 0:
673 files
.extend([i
for i
in get_all_possible_paths(
674 file_path
) if is_file_exists(i
)])
676 cephfs
.unlink(to_bytes(file_path
))
678 def complete_mv(self
, text
, line
, begidx
, endidx
):
680 auto complete of file name.
682 return self
.complete_filenames(text
, line
, begidx
, endidx
)
684 mv_parser
= argparse
.ArgumentParser(description
='Move File.')
685 mv_parser
.add_argument('src_path', type=str, help='Source File Path.')
686 mv_parser
.add_argument('dest_path', type=str,
687 help='Destination File Path.')
689 @with_argparser(mv_parser
)
690 def do_mv(self
, args
):
692 Rename a file or Move a file from source path to the destination
694 cephfs
.rename(to_bytes(args
.src_path
), to_bytes(args
.dest_path
))
696 def complete_cd(self
, text
, line
, begidx
, endidx
):
698 auto complete of file name.
700 return self
.complete_filenames(text
, line
, begidx
, endidx
)
702 cd_parser
= argparse
.ArgumentParser(description
='Change working directory')
703 cd_parser
.add_argument('dir_name', type=str,
704 help='Name of the directory.', default
='')
706 @with_argparser(cd_parser
)
707 def do_cd(self
, args
):
709 Change working directory
711 if args
.dir_name
== '':
713 if args
.dir_name
== '..':
714 dir_name
= cephfs
.getcwd().decode('utf-8').rsplit('/', 1)[0]
716 cephfs
.chdir(to_bytes(dir_name
))
720 cephfs
.chdir(to_bytes(args
.dir_name
))
721 self
.working_dir
= cephfs
.getcwd().decode('utf-8')
724 def do_cwd(self
, arglist
):
726 Get current working directory.
728 self
.poutput(cephfs
.getcwd().decode('utf-8'))
730 def complete_chmod(self
, text
, line
, begidx
, endidx
):
732 auto complete of file name.
734 return self
.complete_filenames(text
, line
, begidx
, endidx
)
736 chmod_parser
= argparse
.ArgumentParser(description
='Create Directory.')
737 chmod_parser
.add_argument('mode', type=int, help='Mode')
738 chmod_parser
.add_argument('file_name', type=str, help='Name of the file')
740 @with_argparser(chmod_parser
)
741 def do_chmod(self
, args
):
743 Change permission of a file
745 cephfs
.chmod(args
.file_name
, args
.mode
)
747 def complete_cat(self
, text
, line
, begidx
, endidx
):
749 auto complete of file name.
751 return self
.complete_filenames(text
, line
, begidx
, endidx
)
753 cat_parser
= argparse
.ArgumentParser(description
='')
754 cat_parser
.add_argument('file_names', help='Name of Files', nargs
='+')
756 @with_argparser(cat_parser
)
757 def do_cat(self
, args
):
759 Print contents of a file
761 for file_name
in args
.file_names
:
762 self
.poutput(file_name
)
763 copy_to_local(self
, file_name
, '-')
765 umask_parser
= argparse
.ArgumentParser(description
='Set umask value.')
766 umask_parser
.add_argument(
767 'mode', help='Mode', action
='store', nargs
='?', default
='')
769 @with_argparser(umask_parser
)
770 def do_umask(self
, args
):
775 self
.poutput(self
.umask
.zfill(4))
777 mode
= int(args
.mode
, 8)
778 self
.umask
= str(oct(cephfs
.umask(mode
))[2:])
780 def complete_write(self
, text
, line
, begidx
, endidx
):
782 auto complete of file name.
784 return self
.complete_filenames(text
, line
, begidx
, endidx
)
786 write_parser
= argparse
.ArgumentParser(description
='')
787 write_parser
.add_argument('file_name', type=str, help='Name of File')
789 @with_argparser(write_parser
)
790 def do_write(self
, args
):
792 Write data into a file.
795 copy_from_local(self
, '-', args
.file_name
)
797 def complete_lcd(self
, text
, line
, begidx
, endidx
):
799 auto complete of file name.
801 index_dict
= {1: self
.path_complete
}
802 return self
.index_based_complete(text
, line
, begidx
, endidx
, index_dict
)
804 lcd_parser
= argparse
.ArgumentParser(description
='')
805 lcd_parser
.add_argument('path', type=str, help='Path')
807 @with_argparser(lcd_parser
)
808 def do_lcd(self
, args
):
810 Moves into the given local directory
813 path
= os
.path
.expanduser(args
.path
)
814 if os
.path
.isdir(path
):
816 # self.poutput(get_all_possible_paths(args.path))
818 def complete_lls(self
, text
, line
, begidx
, endidx
):
820 auto complete of file name.
822 index_dict
= {1: self
.path_complete
}
823 return self
.index_based_complete(text
, line
, begidx
, endidx
, index_dict
)
825 lls_parser
= argparse
.ArgumentParser(
826 description
='List files in local system.')
827 lls_parser
.add_argument('paths', help='Paths', nargs
='*', default
=[''])
829 @with_argparser(lls_parser
)
830 def do_lls(self
, args
):
832 Lists all files and folders in the current local directory
835 if len(args
.paths
) == 1 and args
.paths
[0] == '':
837 args
.paths
.append(os
.getcwd())
838 for path
in args
.paths
:
839 if os
.path
.isabs(path
):
840 path
= os
.path
.relpath(os
.getcwd(), '/' + path
)
841 items
= os
.listdir(path
)
842 print_list(self
, items
)
844 def do_lpwd(self
, arglist
):
846 Prints the absolute path of the current local directory
848 self
.poutput(os
.getcwd())
850 def do_df(self
, arglist
):
852 Display the amount of available disk space for file systems
854 for index
, i
in enumerate(list_items(cephfs
.getcwd())[2:]):
856 self
.poutput('{:25s}\t{:5s}\t{:15s}{:10s}{}'.format(
857 "1K-blocks", "Used", "Available", "Use%", "Stored on"))
858 if not is_dir_exists(i
.d_name
):
859 statfs
= cephfs
.statfs(i
.d_name
)
860 stat
= cephfs
.stat(i
.d_name
)
861 block_size
= statfs
['f_blocks']*statfs
['f_bsize'] // 1024
862 available
= block_size
- stat
.st_size
865 use
= (stat
.st_size
*100 // block_size
)
866 self
.poutput('{:25d}\t{:5d}\t{:10d}\t{:5s} {}'.format(
867 statfs
['f_fsid'], stat
.st_size
, available
,
868 str(int(use
)) + '%', i
.d_name
.decode('utf-8')))
870 locate_parser
= argparse
.ArgumentParser(
871 description
='Find file within file system')
872 locate_parser
.add_argument('name', help='name', type=str)
873 locate_parser
.add_argument(
874 '-c', '--count', action
='store_true', help='Count list of items located.')
875 locate_parser
.add_argument(
876 '-i', '--ignorecase', action
='store_true', help='Ignore case')
878 @with_argparser(locate_parser
)
879 def do_locate(self
, args
):
881 Find a file within the File System
883 if args
.name
.count('*') == 1:
884 if args
.name
[0] == '*':
886 elif args
.name
[-1] == '*':
887 args
.name
= '/' + args
.name
888 args
.name
= args
.name
.replace('*', '')
890 locations
= locate_file(args
.name
, False)
892 locations
= locate_file(args
.name
)
894 self
.poutput(len(locations
))
896 self
.poutput('\n'.join(locations
))
898 def complete_du(self
, text
, line
, begidx
, endidx
):
900 auto complete of file name.
902 return self
.complete_filenames(text
, line
, begidx
, endidx
)
904 du_parser
= argparse
.ArgumentParser(
905 description
='Disk Usage of a Directory')
906 du_parser
.add_argument(
907 'dirs', type=str, help='Name of the directory.', nargs
='?', default
='')
908 du_parser
.add_argument('-r', action
='store_true',
909 help='Recursive Disk usage of all directories.')
911 @with_argparser(du_parser
)
912 def do_du(self
, args
):
914 Disk Usage of a Directory
917 args
.dirs
= cephfs
.getcwd().decode('utf-8')
918 for dir_
in args
.dirs
:
920 for i
in reversed(sorted(set(dirwalk(dir_
)))):
921 i
= os
.path
.normpath(i
)
923 xattr
= cephfs
.getxattr(to_bytes(i
), 'ceph.dir.rbytes')
924 self
.poutput('{:10s} {}'.format(
925 humansize(int(xattr
.decode('utf-8'))), '.' + i
))
926 except libcephfs
.Error
:
929 dir_
= os
.path
.normpath(dir_
)
930 self
.poutput('{:10s} {}'.format(humansize(int(cephfs
.getxattr(to_bytes(
931 dir_
), 'ceph.dir.rbytes').decode('utf-8'))), '.' + dir_
))
933 def do_help(self
, line
):
935 Get details about a command.
936 Usage: help <cmd> - for a specific command
937 help all - for all the commands
941 if k
.startswith('do_'):
943 super().do_help(k
[3:])
945 parser
= self
.create_argparser(line
)
949 super().do_help(line
)
952 if __name__
== '__main__':
955 main_parser
= argparse
.ArgumentParser(description
='')
956 main_parser
.add_argument(
957 '-c', '--config', action
='store', help='Configuration file_path', type=str)
958 main_parser
.add_argument(
959 '-b', '--batch', action
='store', help='Batch File path.', type=str)
960 main_parser
.add_argument('-t', '--test', action
='store',
961 help='Test against transcript(s) in FILE', nargs
='+')
962 main_parser
.add_argument('commands', nargs
='*',
963 help='comma delimited commands', default
=[])
964 args
= main_parser
.parse_args()
966 config_file
= args
.config
968 args
.commands
= ['load ' + args
.batch
, ',quit']
970 args
.commands
.extend(['-t,'] + [arg
+',' for arg
in args
.test
])
973 sys
.argv
.extend([i
.strip() for i
in ' '.join(args
.commands
).split(',')])
974 setup_cephfs(config_file
)