def do_rm(self, line): """rm [-f|--force] FILE... Remove one or more files rm [-f|--force] PATTERN Remove multiple files rm -r [-f|--force] [FILE|DIRECTORY]... Files and/or directories rm -r [-f|--force] PATTERN Multiple files and/or directories Removes files or directories. To remove directories (and any contents) -r must be specified. """ args = self.line_to_args(line) filenames = args.filename # Process PATTERN sfn = filenames[0] if is_pattern(sfn): if len(filenames) > 1: eprint("Usage: rm [-r] [-f] PATTERN") return filenames = process_pattern(self.boards, self.cur_dir, sfn) if filenames is None: return for filename in filenames: filename = resolve_path(self.cur_dir, filename) if not rm( self.boards, filename, recursive=args.recursive, force=args.force): if not args.force: eprint( "Unable to remove '{}' (try -rf if you are sure)".format( filename)) break
def do_mkdir(self, line): """mkdir DIRECTORY... Creates one or more directories. """ args = self.line_to_args(line) for filename in args: filename = resolve_path(self.cur_dir, filename) if not mkdir(self.boards, filename): eprint('Unable to create %s' % filename)
def do_rsync(self, line): """rsync [-m|--mirror] [-n|--dry-run] [SRC_DIR [DST_DIR]] Synchronize destination directory tree to source directory tree. """ db = self.boards.default args = self.line_to_args(line) sd = args.src_dst_dir if len(sd) > 2: eprint("*** More than one destination directory given") return src_dir = sd[0] if len(sd) > 0 else db.get_config('host_dir', '~/iot49') dst_dir = sd[1] if len(sd) > 1 else db.get_config('remote_dir', '/flash') src_dir = resolve_path(self.cur_dir, src_dir) dst_dir = resolve_path(self.cur_dir, dst_dir) if len(sd) < 2: qprint("synchronizing {} --> {}".format(src_dir, dst_dir)) rsync(self.boards, src_dir, dst_dir, mirror=not args.mirror, dry_run=args.dry_run, recursed=True)
def do_ls(self, line): """ls [-a] [-l] [FILE|DIRECTORY|PATTERN]... PATTERN supports * ? [seq] [!seq] Unix filename matching List directory contents. """ args = self.line_to_args(line) if len(args.filenames) == 0: args.filenames = ['.'] for idx, fn in enumerate(args.filenames): if not is_pattern(fn): filename = resolve_path(self.cur_dir, fn) stat = auto(self.boards, get_stat, filename) mode = stat_mode(stat) if not mode_exists(mode): err = "Cannot access '{}': No such file or directory" eprint(err.format(filename)) continue if not mode_isdir(mode): if args.long: print_long(filename, stat, oprint) else: oprint(filename) continue if len(args.filenames) > 1: if idx > 0: oprint('') oprint("%s:" % filename) pattern = '*' else: # A pattern was specified filename, pattern = validate_pattern(self.boards, self.cur_dir, fn) if filename is None: # An error was printed continue files = [] ldir_stat = auto(self.boards, listdir_stat, filename) if ldir_stat is None: err = "Cannot access '{}': No such file or directory" eprint(err.format(filename)) else: for filename, stat in sorted(ldir_stat, key=lambda entry: entry[0]): if is_visible(filename) or args.all: if fnmatch(filename, pattern): if args.long: print_long(filename, stat, oprint) else: files.append(decorated_filename(filename, stat)) if len(files) > 0: print_cols(sorted(files), oprint, shutil.get_terminal_size().columns)
def do_cat(self, line): """cat FILENAME... Concatenates files and sends to stdout. """ # note: when we get around to supporting cat from stdin, we'll need # to write stdin to a temp file, and then copy the file # since we need to know the filesize when copying to the pyboard. args = self.line_to_args(line) for filename in args: filename = resolve_path(self.cur_dir, filename) mode = auto(self.boards, get_mode, filename) if not mode_exists(mode): eprint("Cannot access '%s': No such file" % filename) continue if not mode_isfile(mode): eprint("'%s': is not a file" % filename) continue cat(self.boards, filename, self.stdout)
def do_cd(self, line): """cd DIRECTORY Changes the current directory. ~ expansion is supported, and cd - goes to the previous directory. """ args = self.line_to_args(line) if len(args) == 0: dirname = '~' else: if args[0] == '-': dirname = self.prev_dir else: dirname = args[0] dirname = resolve_path(self.cur_dir, dirname) mode = auto(self.boards, get_mode, dirname) if mode_isdir(mode): self.prev_dir = self.cur_dir self.cur_dir = dirname auto(self.boards, chdir, dirname) else: eprint("Directory '%s' does not exist" % dirname)
def do_edit(self, line): """edit FILE Copies the file locally, launches an editor to edit the file. When the editor exits, if the file was modified then its copied back. You can specify the editor used with the --editor command line option when you start shell49, or by using the SHELL49_EDITOR or VISUAL or EDITOR environment variable. If none of those are set, then vi will be used. """ if len(line) == 0: eprint("Must provide a filename") return filename = resolve_path(self.cur_dir, line) dev, dev_filename = self.boards.get_dev_and_path(filename) mode = auto(self.boards, get_mode, filename) if mode_exists(mode) and mode_isdir(mode): eprint("Unable to edit directory '{}'".format(filename)) return if dev is None: # File is local os.system("{} '{}'".format(self.editor, filename)) else: # File is remote with tempfile.TemporaryDirectory() as temp_dir: local_filename = os.path.join(temp_dir, os.path.basename(filename)) if mode_exists(mode): print('Retrieving {} ...'.format(filename)) cp(filename, local_filename) old_stat = get_stat(local_filename) os.system("{} '{}'".format(self.editor, local_filename)) new_stat = get_stat(local_filename) if old_stat != new_stat: print('Updating {} ...'.format(filename)) cp(local_filename, filename)
def do_cp(self, line): """cp SOURCE DEST Copy a single SOURCE file to DEST file. cp SOURCE... DIRECTORY Copy multiple SOURCE files to a directory. cp [-r] PATTERN DIRECTORY Copy matching files to DIRECTORY. cp [-r|--recursive] [SOURCE|SOURCE_DIR]... DIRECTORY The destination must be a directory except in the case of copying a single file. To copy directories -r must be specified. This will cause directories and their contents to be recursively copied. """ args = self.line_to_args(line) if len(args.filenames) < 2: eprint('Missing destination file') return dst_dirname = resolve_path(self.cur_dir, args.filenames[-1]) dst_mode = auto(self.boards, get_mode, dst_dirname) d_dst = {} # Destination directory: lookup stat by basename if args.recursive: dst_files = auto(self.boards, listdir_stat, dst_dirname) if dst_files is None: err = "cp: target {} is not a directory" eprint(err.format(dst_dirname)) return for name, stat in dst_files: d_dst[name] = stat src_filenames = args.filenames[:-1] # Process PATTERN sfn = src_filenames[0] if is_pattern(sfn): if len(src_filenames) > 1: eprint("Usage: cp [-r] PATTERN DIRECTORY") return src_filenames = process_pattern(self.boards, self.cur_dir, sfn) if src_filenames is None: return for src_filename in src_filenames: if is_pattern(src_filename): eprint("Only one pattern permitted.") return src_filename = resolve_path(self.cur_dir, src_filename) src_mode = auto(self.boards, get_mode, src_filename) if not mode_exists(src_mode): eprint("File '{}' doesn't exist".format(src_filename)) return if mode_isdir(src_mode): if args.recursive: # Copying a directory src_basename = os.path.basename(src_filename) dst_filename = os.path.join(dst_dirname, src_basename) if src_basename in d_dst: dst_stat = d_dst[src_basename] dst_mode = stat_mode(dst_stat) if not mode_isdir(dst_mode): err = "Destination {} is not a directory" eprint(err.format(dst_filename)) return else: if not mkdir(dst_filename): err = "Unable to create directory {}" eprint(err.format(dst_filename)) return rsync(src_filename, dst_filename, mirror=False, dry_run=False, print_func=lambda *args: None, recursed=False) else: eprint("Omitting directory {}".format(src_filename)) continue if mode_isdir(dst_mode): dst_filename = os.path.join( dst_dirname, os.path.basename(src_filename)) else: dst_filename = dst_dirname if not cp(self.boards, src_filename, dst_filename): err = "Unable to copy '{}' to '{}'" eprint(err.format(src_filename, dst_filename)) break