示例#1
0
def sed(cfg: Dict[str, str], sed_cmd: str) -> NoReturn:
    """
    Runs an in-place "sed" edit against every notebook in the course, using
    "sed -E". Requires a version of "sed" that supports the "-i" (in-place
    edit) option.

    :param cfg:     the loaded configuration
    :param sed_cmd: the "sed" command, which may or may not be quoted.

    :return: Nothing
    """
    check_config(cfg, 'COURSE_NAME', 'COURSE_REPO')
    for nb in bdc.bdc_get_notebook_paths(build_file_path(cfg)):
        # Quote the argument.
        q = sed_cmd[0]
        if q in ('"', "'"):
            # Already quoted, hopefully.
            if sed_cmd[-1] != q:
                raise CourseError(
                    f'Mismatched quotes in sed argument: {sed_cmd}')
            quoted = sed_cmd
        elif ('"' in sed_cmd) and ("'" in sed_cmd):
            raise CourseError(
                '"sed" argument cannot be quoted, since it contains ' +
                f'single AND double quotes: {sed_cmd}')
        elif "'" in sed_cmd:
            quoted = '"' + sed_cmd + '"'
        else:
            quoted = "'" + sed_cmd + "'"

        cmd(f'sed -E -i "" -e {quoted} "{nb}"')
示例#2
0
def grep(cfg: Dict[str, str],
         pattern: str,
         case_blind: bool = False) -> NoReturn:
    """
    Searches for the specified regular expression in every notebook within
    the current course, printing the colorized matches to standard output.
    If PAGER is set, the matches will be piped through the pager.

    Note that this function does NOT use grep(1). It implements the
    regular expression matching and colorization entirely within Python.

    :param cfg:          The config.
    :param pattern:      The regular expression (a string, not a compiled
                         pattern) to find
    :param case_blind:   Whether or not to use case-blind matching

    :return: Nothing
    """
    def grep_one(path: str, r: Pattern, out: TextIO) -> NoReturn:
        home = os.environ['HOME']
        if home:
            printable_path = os.path.join('~', path[len(home) + 1:])
        else:
            printable_path = path

        matches = []
        with open(path) as f:
            for line in f.readlines():
                m = r.search(line)
                if not m:
                    continue

                # If there's a pager, colorize the match.
                if cfg.get('PAGER'):
                    s = m.start()
                    e = m.end()
                    matches.append(line[:s] +
                                   colored(line[s:e], 'red', attrs=['bold']) +
                                   line[e:])
                else:
                    matches.append(line)

        if matches:
            out.write(f'\n\n=== {printable_path}\n\n')
            out.write(''.join(matches))

    r = None
    try:
        flags = 0 if not case_blind else re.IGNORECASE
        r = re.compile(pattern, flags=flags)
    except Exception as e:
        die(f'Cannot compile regular expression "{pattern}": {e}')

    check_config(cfg, 'COURSE_NAME', 'COURSE_REPO')
    with pager(cfg) as out:
        for nb in bdc.bdc_get_notebook_paths(build_file_path(cfg)):
            grep_one(nb, r, out)
示例#3
0
def run_command_on_notebooks(cfg: Dict[str, str], command: str,
                             args: Sequence[str]) -> NoReturn:
    """
    Runs a command on every notebook in the current course.

    :param cfg:      the loaded configuration.
    :param command:  the command to run
    :param args:     any command arguments, as a list

    :return: Nothing
    """
    check_config(cfg, 'COURSE_NAME', 'COURSE_REPO')
    for nb in bdc.bdc_get_notebook_paths(build_file_path(cfg)):
        if args:
            quoted = ' '.join([quote_shell_arg(arg) for arg in args])
            shell_command = f'{command} {quoted} {nb}'
        else:
            shell_command = f'{command} {nb}'

        try:
            cmd(shell_command)
        except CourseError as e:
            warn(str(e))