cli
cli copied to clipboard
Download all items for given track
Did some quick searching and I see that the ability to download all items for a given track isn't currently in the CLI.
I'd really find this item useful, as it's great to have access to items to work on during a long flight etc.
In the mean time (because I've been searching for it in the issues here) I made a tiny script to be able to download all items for a given track: https://github.com/Jarvvski/exercism-downloader
I think this would be a nice addition.
A few notes:
- It would have to be "all unlocked", not "all"
- In "independent mode", "all unlocked" would be equivalent to "all"
We would need some design/implementation on the backend API in https://github.com/exercism/website before we can start addressing this
Before this task is completed, we can use this shell command to pull the list of go:
curl -LS https://exercism.io/tracks/go/exercises | grep "/tracks/go/exercises/" | awk '{print $3}' | cut -d/ -f5 | cut -d\" -f1
@raymondchen625 awesome 1 liner!
curl -LS https://exercism.io/tracks/rust/exercises | grep "/tracks/rust/exercises/" | awk '{print $3}' | cut -d/ -f5 | cut -d\" -f1 > exercises.txt
while read in; do exercism download --exercise="$in" --track=rust; done < exercises.txt
Change track as needed
I also would massively appreciate a way to download full tracks. EDIT: I just realized I have to have exercises unlocked. @tsoernes script works beautifully though.
If you're doing multiple tracks in parallel this might be helpful:
# "exercism download all" for specific tracks
function eda() {
for trackname in "$@"; do
echo https://exercism.io/tracks/$trackname/exercises
curl -LS https://exercism.io/tracks/$trackname/exercises | grep "/tracks/$trackname/exercises/" | awk '{print $3}' | cut -d/ -f5 | cut -d\" -f1 > exercises.txt
while read in; do exercism download --exercise="$in" --track=$trackname; done < exercises.txt
rm exercises.txt
done
}
# example usage:
# ❯ eda typescript reasonml ocaml racket nim
Thank you @tsoernes for doing the hard part. This is just a for loop around his code.
I'm having issues using that @tsoernes code from a computer using WSL2 and redid some part of it:
TRACK=<TRACK-TO-BE-DOWNLOADED> && curl -LS https://exercism.io/tracks/$TRACK/exercises | grep "/tracks/$TRACK/exercises/" | awk '{print $3}' | cut -d/ -f5 | cut -d\" -f1 > exercises.txt
for word in `sed '/^$/d' exercises.txt`; do exercism download --exercise="$word" --track=$TRACK; done
Be careful when your home excercism workspace path has spaces.
Hope you all enjoy it! ;)
If you're doing multiple tracks in parallel this might be helpful:
# "exercism download all" for specific tracks function eda() { for trackname in "$@"; do echo https://exercism.io/tracks/$trackname/exercises curl -LS https://exercism.io/tracks/$trackname/exercises | grep "/tracks/$trackname/exercises/" | awk '{print $3}' | cut -d/ -f5 | cut -d\" -f1 > exercises.txt while read in; do exercism download --exercise="$in" --track=$trackname; done < exercises.txt rm exercises.txt done } # example usage: # ❯ eda typescript reasonml ocaml racket nim
Thank you @tsoernes for doing the hard part. This is just a for loop around his code.
Note that it will overwrite all already downloaded folders
The previous scripts don't work on the new website anymore.
This works for me:
#!/usr/bin/env bash
# You have to have `pup` and `jq` in your $PATH.
# Does `mkfifo` work on MacOS?
# example usage:
# ❯ eda typescript reasonml ocaml racket nim
arrow="\e[31;1m=>\e[0m"
pipe="/tmp/pipe-$$"
for trackname in "$@"; do
mkfifo "$pipe"
echo -e "$arrow Downloading ${trackname^} track..."
curl -LSs https://exercism.org/tracks/"$trackname"/exercises |
pup -p 'section[class=exercises] div attr{data-react-data}' |
jq -r '.request.options.initial_data.exercises | .[].slug' >"$pipe" &
while read in; do
exercism download --exercise="$in" --track="$trackname"
done <"$pipe"
rm "$pipe"
done
This is a python script I just used.
import requests
import re
import os
# Replace this with your language
LANGUAGE = "java"
# Get the html from the exercism page
pageURL = 'https://exercism.org/tracks/' + LANGUAGE + '/exercises'
request = requests.get(pageURL)
pageHTML = request.content.decode('utf-8')
# Each exercise is in the form "/tracks/java/"exerciseName&
regexString = r'tracks/' + LANGUAGE + '/exercises/(.*?)&'
allMatches = re.findall(regexString, pageHTML)
numDownloads = 0
for exercise in allMatches:
downloadCommand = 'exercism download --exercise=' + exercise + ' --track=' + LANGUAGE
os.system(downloadCommand)
numDownloads += 1
print("Total downloads: ", numDownloads)
To add to this pageant of download scripts, here's a bash version of @robertpkoenig's Python script that doesn't need anything you don't already have (the exercism
CLI, curl
, and pretty standard *NIX/Posix stuff). Just change TRACK
to whatever floats your boat.
(TRACK=rust; set -euo pipefail; trackdir="$(exercism workspace)/$TRACK"; mkdir -p "$trackdir"; curl --silent --fail "https://exercism.org/tracks/$TRACK/exercises" | grep -Eo 'tracks/'"$TRACK"'/exercises/[^&]+' | cut -d/ -f4 | tee "$trackdir/exercise-order.txt" | while read ex; do if test -d "$trackdir/$ex" ; then echo "$ex already downloaded"; else (set -x && exercism download --track "$TRACK" --exercise "$ex"); fi; done)
Works On My Machine™️
Edit: Now also works on other machines (Mac/bash and Alpine/ash at least)
Here's a python script that asynchronously downloads a track from it's config.json:
import asyncio
import json
import requests
async def download_exercise(exercise: str, track: str, overwrite):
cmd = f"exercism download --exercise={exercise} --track={track}"
if overwrite:
cmd += " --force"
proc = await asyncio.create_subprocess_shell(
cmd,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE)
stdout, stderr = await proc.communicate()
print(f'[{cmd!r} exited with {proc.returncode}]')
if stdout:
print(f'[stdout]\n{stdout.decode()}')
if stderr:
print(f'[stderr]\n{stderr.decode()}')
async def download_track(track: str, overwrite=false):
url = f"https://github.com/exercism/{track}/raw/main/config.json"
content = json.loads(requests.get(url).content)
await asyncio.gather(*(download_exercise(exercise['slug'], track, overwrite) for exercise in content["exercises"]["practice"]))
asyncio.run(download_track("dart"))
Another Bash script, but using Exercism's API:
#!/usr/bin/env bash
set -e
set -u
export track="$1"
curl \
--silent --fail \
"https://exercism.org/api/v2/tracks/$track/exercises" \
| sed 's/"slug":"/\n/g' \
| sed 's/",.*$//' \
| grep -v '"exercises":' \
| while read -r slug; do
exercism download --track="$track" --exercise="$slug"
done
So, my PR got automatically closed because of the pause of community contributions, which I wasn't aware of, but that doesn't mean you can't use the feature I've developed to list, filter, and download exercises. Just read the PR, it has all the examples. Until the pause gets lifted, happy coding!
PR - https://github.com/exercism/cli/pull/1113
A shorter command than what I have seen here before. Uses jq
as dependency which is pretty common.
- downloads only exercises you don't already have (doesn't overwrite. But still can if you add
--force
) - only downloads unlocked exercises
track=go; curl "https://exercism.org/api/v2/tracks/$track/exercises" | \
jq -r '.exercises[].slug' | \
xargs -I {} -n1 sh -c "exercism download --track=$track --exercise {} || true"
In case somone wants an out of the box solution: exer-h
It's a small wrapper for the official exercism cli. Hope it helps.