Example #1
0
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)
Example #2
0
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)
Example #3
0
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)
Example #4
0
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)
Example #5
0
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
Example #6
0
    def real_filename_complete(self, text, line, begidx, endidx):
        """Figure out what filenames match the completion."""

        # line contains the full command line that's been entered so far.
        # text contains the portion of the line that readline is trying to complete
        # text should correspond to line[begidx:endidx]
        #
        # The way the completer works text will start after one of the characters
        # in DELIMS. So if the filename entered so far was "embedded\ sp" and
        # then text will point to the s in sp.
        #
        # The following bit of logic backs up to find the real beginning of the
        # filename.

        for before_match in range(begidx, 0, -1):
            if line[before_match] in self.DELIMS and before_match >= 1 and line[
                    before_match - 1] != '\\':
                break

        # We set fixed to be the portion of the filename which is before text
        # and match is the full portion of the filename that's been entered so
        # far (that's that part we use for matching files).
        #
        # When we return a list of completions, the bit that we return should
        # just be the portion that we replace 'text' with.

        # fixed portion of the match
        fixed = unescape(line[before_match + 1:begidx])
        # portion to match filenames against
        match = unescape(line[before_match + 1:endidx])

        # We do the following to cover the case that the current directory
        # is / and the path being entered is relative.
        if match[0] == '/':
            abs_match = match
        elif self.cur_dir == '/':
            abs_match = self.cur_dir + match
        else:
            abs_match = self.cur_dir + '/' + match

        completions = []
        prepend = ''
        if abs_match.rfind('/') == 0:  # match is in the root directory
            # This means that we're looking for matches in the root directory
            # (i.e. abs_match is /foo and the user hit TAB).
            # So we'll supply the matching board names as possible completions.
            # Since they're all treated as directories we leave the trailing slash.
            if match[0] == '/':
                completions += [
                    dev.name_path for dev in self.boards.boards()
                    if dev.name_path.startswith(abs_match)
                ]
            else:
                completions += [
                    dev.name_path[1:] for dev in self.boards.boards()
                    if dev.name_path.startswith(abs_match)
                ]
            try:
                # Add root directories of the default device
                def_dev = self.boards.default
                if match[0] == '/':
                    completions += [
                        root_dir for root_dir in def_dev.root_dirs
                        if root_dir.startswith(match)
                    ]
                else:
                    completions += [
                        root_dir[1:] for root_dir in def_dev.root_dirs
                        if root_dir[1:].startswith(match)
                    ]
            except BoardError:
                pass
        else:
            # This means that there are at least 2 slashes in abs_match. If one
            # of them matches a board name then we need to remove the board
            # name from fixed. Since the results from listdir_matches won't
            # contain the board name, we need to prepend each of the completions.
            for dev in self.boards.boards():
                if abs_match.startswith(dev.name_path):
                    prepend = dev.name_path[:-1]

        paths = sorted(auto(self.boards, listdir_matches, match))
        for path in paths:
            path = prepend + path
            completions.append(escape(path.replace(fixed, '', 1)))
        return completions