예제 #1
0
파일: put.py 프로젝트: dankilman/vimgolf
def put(challenge_id, keys, diff=False):
    challenge_id = expand_challenge_id(challenge_id)
    logger.info('put(%s)', challenge_id)

    if not validate_challenge_id(challenge_id):
        show_challenge_id_error()
        raise Failure()

    api_key = get_api_key()
    if not validate_api_key(api_key):
        write('An API key has not been configured', fg='red')
        write('Uploading to vimgolf.com is disabled', fg='red')
        show_api_key_help()
        if not confirm('Play without uploads?'):
            raise Failure()

    try:
        compliant = fetch_and_validate_challenge(challenge_id)
    except Failure:
        raise
    except Exception:
        logger.exception('challenge retrieval failed')
        write('The challenge retrieval has failed', err=True, fg='red')
        write('Please check the challenge ID on vimgolf.com',
              err=True,
              fg='red')
        raise Failure()

    challenge = Challenge(id=challenge_id,
                          compliant=compliant,
                          api_key=api_key).load()
    with tempfile.TemporaryDirectory() as d:
        play(challenge, d, keys=keys, diff=diff)
    challenge.update_metadata()
예제 #2
0
def inspect(challenge_id, keys, literal_lt, literal_gt):
    challenge_id = expand_challenge_id(challenge_id)
    logger.info('inspect(%s)', challenge_id)

    if not validate_challenge_id(challenge_id):
        show_challenge_id_error()
        raise Failure()

    try:
        challenge = Challenge(challenge_id)
        challenge.load_or_download()
    except Failure:
        raise
    except Exception:
        logger.exception('challenge retrieval failed')
        write('The challenge retrieval has failed', err=True, fg='red')
        write('Please check the challenge ID on vimgolf.com', err=True, fg='red')
        raise Failure()

    src_in_path = challenge.in_path
    name, ext = os.path.splitext(os.path.basename(src_in_path))

    sequences = build_sequences(
        keys=keys,
        literal_gt=literal_gt,
        literal_lt=literal_lt
    )

    with tempfile.TemporaryDirectory() as workspace:
        zfill = lambda s: str(s).zfill(3)

        def dst_path(index):
            return os.path.join(workspace, '{}{}{}'.format(name, zfill(index), ext))

        def script_path(index):
            return os.path.join(workspace, 'mapping{}.vim'.format(zfill(index)))

        def in_path(index):
            return os.path.join(workspace, 'inspect-{}{}{}'.format(name, zfill(index), ext))

        replay_sequences(
            dst_path=dst_path,
            script_path=script_path,
            sequences=sequences,
            src_in_path=src_in_path
        )
        inspect_sequences(
            workspace=workspace,
            dst_path=dst_path,
            in_path=in_path,
            sequences=sequences
        )
예제 #3
0
def _vim(args, **run_kwargs):
    vim_path = find_executable(GOLF_VIM)
    if not vim_path:
        write('Unable to find "{}"'.format(GOLF_VIM), fg='red')
        write('Please update your PATH to include the directory with "{}"'.
              format(GOLF_VIM),
              fg='red')
        raise Failure()
    vim_name = os.path.basename(os.path.realpath(vim_path))

    if sys.platform == 'win32':
        # Remove executable extension (.exe, .bat, .cmd, etc.) from 'vim_name'
        base, ext = os.path.splitext(vim_name)
        pathexts = os.environ.get('PATHEXT', '.EXE').split(os.pathsep)
        for pathext in pathexts:
            if ext.upper() == pathext.upper():
                vim_name = base
                break

    # As of 2019/3/2, on Windows, nvim-qt doesn't support --nofork.
    # Issue a warning as opposed to failing, since this may change.
    if vim_name == 'nvim-qt' and sys.platform == 'win32':
        write('vimgolf with nvim-qt on Windows may not function properly',
              fg='red')
        write(
            'If there are issues, please try using a different version of vim',
            fg='yellow')
        if not confirm('Continue trying to play?'):
            raise Failure()

    # Configure args used by all vim invocations (for both playing and diffing)
    # 'vim_path' is used instead of GOLF_VIM to handle 'vim.bat' on the PATH.
    # subprocess.run would not launch vim.bat with GOLF_VIM == 'vim', but 'find_executable'
    # will return the full path to vim.bat in that case.
    vim_args = [vim_path]
    # Add --nofork so gvim, mvim, and nvim-qt don't return immediately
    # Add special-case handling since nvim doesn't accept that option.
    if vim_name != 'nvim':
        vim_args.append('--nofork')
    # For nvim-qt, options after '--' are passed to nvim.
    if vim_name == 'nvim-qt':
        vim_args.append('--')
    vim_args.extend(args)
    subprocess.run(vim_args, **run_kwargs)
    # On Windows, vimgolf freezes when reading input after nvim's exit.
    # For an unknown reason, shell'ing out an effective no-op works-around the issue
    if vim_name == 'nvim' and sys.platform == 'win32':
        os.system('')
예제 #4
0
파일: put.py 프로젝트: dankilman/vimgolf
def fetch_and_validate_challenge(challenge_id):
    write('Downloading vimgolf challenge {}'.format(challenge_id), fg='yellow')
    challenge = Challenge(challenge_id)
    challenge.load_or_download()
    challenge_spec = challenge.spec
    compliant = challenge_spec.get('client') == RUBY_CLIENT_VERSION_COMPLIANCE
    if not compliant:
        message = 'vimgolf=={} is not compliant with vimgolf.com'.format(
            __version__)
        write(message, err=True, fg='red')
        write('Uploading to vimgolf.com is disabled', err=True, fg='red')
        write('vimgolf may not function properly', fg='red')
        try:
            from distutils.version import StrictVersion
            client_compliance_version = StrictVersion(
                RUBY_CLIENT_VERSION_COMPLIANCE)
            api_version = StrictVersion(challenge_spec['client'])
            action = 'upgrade' if api_version > client_compliance_version else 'downgrade'
        except Exception:
            action = 'update'
        write('Please {} vimgolf to a compliant version'.format(action),
              fg='yellow')
        if not confirm('Try to play without uploads?'):
            raise Failure()
    return compliant
예제 #5
0
def vim(args, **run_kwargs):
    try:
        _vim(args, **run_kwargs)
    except Failure:
        raise
    except Exception:
        logger.exception('{} execution failed'.format(GOLF_VIM))
        write('The execution of {} has failed'.format(GOLF_VIM),
              err=True,
              fg='red')
        raise Failure()
예제 #6
0
파일: config.py 프로젝트: dankilman/vimgolf
def config(api_key=None):
    logger.info('config(...)')
    if api_key is not None and not validate_api_key(api_key):
        show_api_key_error()
        raise Failure()
    if api_key:
        set_api_key(api_key)
    else:
        api_key = get_api_key()
        if api_key:
            write(api_key)
        else:
            show_api_key_help()
예제 #7
0
def ls(incomplete=False, page=None, limit=LISTING_LIMIT):
    logger.info('list_(%s, %s)', page, limit)
    stored_challenges = get_stored_challenges()
    try:
        url = GOLF_HOST
        if page is not None:
            url = urllib.parse.urljoin(GOLF_HOST, '/?page={}'.format(page))
        response = http_request(url)
        listings = extract_listings_from_page(
            page_html=response.body,
            limit=limit,
            stored_challenges=stored_challenges)
    except Failure:
        raise
    except Exception:
        logger.exception('challenge retrieval failed')
        write('The challenge list retrieval has failed', err=True, fg='red')
        raise Failure()

    table_rows = [['#', 'Name', 'Entries', 'ID', '⬆', 'Score', 'Answers']]
    for idx, listing in enumerate(listings):
        if incomplete and listing.uploaded:
            continue
        table_row = [
            '{}{} '.format(EXPANSION_PREFIX, idx + 1),
            listing.name,
            listing.n_entries,
            style(listing.id, fg='yellow'),
            bool_to_mark(listing.uploaded),
            listing.score if listing.score and listing.score > 0 else '-',
            listing.answers or '-',
        ]
        table_rows.append(table_row)

    write(AsciiTable(table_rows).table)

    id_lookup = {
        str(idx + 1): listing.id
        for idx, listing in enumerate(listings)
    }
    set_id_lookup(id_lookup)
예제 #8
0
 def error(self, message):
     raise Failure()
예제 #9
0
def show(challenge_id):
    challenge_id = expand_challenge_id(challenge_id)
    logger.info('show(%s)', challenge_id)

    if not validate_challenge_id(challenge_id):
        show_challenge_id_error()
        raise Failure()

    try:
        fetched = fetch_challenge_spec_and_page(challenge_id)
        challenge = fetched['challenge']
        page_response = fetched['page']
        page_url = fetched['url']

        data = extract_data_from_page(page_response.body)
        name = data['name']
        description = data['description']
        leaders = data['leaders']

        challenge.update_metadata(name, description)
        metadata = challenge.metadata

        start_file = challenge.in_text
        if not start_file.endswith('\n'):
            start_file += '\n'
        end_file = challenge.out_text
        if not end_file.endswith('\n'):
            end_file += '\n'

        separator = '-' * 50
        write(separator)
        write('{} ('.format(name), nl=False)
        write(challenge_id, fg='yellow', nl=False)
        write(')')
        write(separator)
        write(page_url)
        write(separator)
        write('Leaderboard', fg='green')
        if leaders:
            for leader in leaders[:LEADER_LIMIT]:
                write('{} {}'.format(leader.username.ljust(15), leader.score))
            if len(leaders) > LEADER_LIMIT:
                write('...')
        else:
            write('no entries yet', fg='yellow')
        write(separator)
        write(description)
        write(separator)
        write('Start File', fg='green')
        write(start_file, nl=False)
        write(separator)
        write('End File', fg='green')
        write(end_file, nl=False)
        write(separator)
        write('Stats', fg='green')
        write('Entered Solutions: {}'.format(metadata['answers']))
        write('Uploaded: {}'.format(metadata['uploaded']))
        write('Correct Solutions: {}'.format(metadata['correct']))
        write('Self Best Score: {}'.format(metadata['best_score']))
        answers = challenge.answers
        ignored_answer_suffix = 'ZQ'
        answer_rows = [['Keys', 'Correct', 'Submitted', 'Score', 'Timestamp']]
        for answer in answers:
            keys = ''.join(answer['keys'])
            if keys.endswith(ignored_answer_suffix):
                continue
            answer_row = [
                keys,
                bool_to_mark(answer['correct']),
                bool_to_mark(answer['uploaded']),
                answer['score'],
                answer['timestamp'],
            ]
            answer_rows.append(answer_row)
        if len(answer_rows) > 1:
            write(AsciiTable(answer_rows).table)
    except Failure:
        raise
    except Exception:
        logger.exception('challenge retrieval failed')
        write('The challenge retrieval has failed', err=True, fg='red')
        write('Please check the challenge ID on vimgolf.com', err=True, fg='red')
        raise Failure()