Skip to content

Commit

Permalink
download: Infer track and exercise slug from CWD
Browse files Browse the repository at this point in the history
If I'm in the `exercism/c` directory and invoke:

    exercism download --exercise hello-world

I would like `--track c` to be inferred.

If I'm in the `exercism/c/hello-world` directory and invoke without
arguments:

    exercism download

I would like both `--track c` and `--exercise hello-world` to be
inferred.
  • Loading branch information
petertseng committed Oct 26, 2019
1 parent ba48dcd commit 485a3bf
Show file tree
Hide file tree
Showing 2 changed files with 123 additions and 0 deletions.
50 changes: 50 additions & 0 deletions cmd/download.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,19 @@ func newDownload(flags *pflag.FlagSet, usrCfg *viper.Viper) (*download, error) {
d.apibaseurl = usrCfg.GetString("apibaseurl")
d.workspace = usrCfg.GetString("workspace")

if d.uuid == "" {
if d.slug == "" {
if _, slug, ok := trackAndSlugFromCwd(d.workspace); ok && slug != "" {
d.slug = slug
}
}
if d.track == "" && d.team == "" {
if track, _, ok := trackAndSlugFromCwd(d.workspace); ok {
d.track = track
}
}
}

if err = d.needsSlugXorUUID(); err != nil {
return nil, err
}
Expand Down Expand Up @@ -349,6 +362,43 @@ func (sf solutionFile) relativePath() string {
return filepath.FromSlash(file)
}

func trackAndSlugFromCwd(workspace string) (string, string, bool) {
cwd, err := os.Getwd()
if err != nil {
return "", "", false
}

if !strings.HasPrefix(cwd, workspace) {
return "", "", false
}

remaining := strings.TrimPrefix(cwd, workspace)
remaining = strings.TrimPrefix(remaining, os.PathSeparator)

components := strings.Split(remaining, os.PathSeparator)
if len(components) == 0 {
return "", "", false
}

// We have at least one component, possibly more.
// First is presumably the track, but check whether it actually is one.
track := components[0]
if !isTrack(track) {
return "", "", false
}

slug := ""
if len(components) >= 2 {
slug = components[1]
}

return track, slug, true
}

func isTrack(dir string) bool {
return dir != "users" && dir != "teams"
}

func setupDownloadFlags(flags *pflag.FlagSet) {
flags.StringP("uuid", "u", "", "the solution UUID")
flags.StringP("track", "t", "", "the track ID")
Expand Down
73 changes: 73 additions & 0 deletions cmd/download_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,79 @@ func TestDownloadWithoutFlags(t *testing.T) {
}
}

func TestDownloadInferringFlags(t *testing.T) {
co := newCapturedOutput()
co.override()
defer co.reset()

originalCwd, err := os.Getwd()
defer os.Chdir(originalCwd)
assert.NoError(t, err)

testCases := []struct {
cwd string
flags map[string]string
ok bool
}{
{
cwd: "bogus-track",
flags: map[string]string{"exercise": "bogus-exercise"},
ok: true,
},
{
cwd: "bogus-track/bogus-exercise",
flags: nil,
ok: true,
},
{
cwd: "teams/bogus-team/bogus-track/bogus-exercise",
flags: nil,
ok: false,
},
{
cwd: "users/bogus-user/bogus-track/bogus-exercise",
flags: nil,
ok: false,
},
}

for _, tc := range testCases {
tmpDir, err := ioutil.TempDir("", "download-infer")
defer os.RemoveAll(tmpDir)
assert.NoError(t, err)

subdir := filepath.Join(tmpDir, tc.cwd)
err = os.MkdirAll(subdir, 0755)
assert.NoError(t, err)
os.Chdir(subdir)

ts := fakeDownloadServer(strconv.FormatBool(true), "")
defer ts.Close()

v := viper.New()
v.Set("workspace", tmpDir)
v.Set("apibaseurl", ts.URL)
v.Set("token", "abc123")

cfg := config.Config{
UserViperConfig: v,
}
flags := pflag.NewFlagSet("fake", pflag.PanicOnError)
setupDownloadFlags(flags)
for name, value := range tc.flags {
flags.Set(name, value)
}

err = runDownload(cfg, flags, []string{})
if tc.ok {
assert.NoError(t, err)
assertDownloadedCorrectFiles(t, tmpDir)
} else {
assert.Error(t, err)
}
}
}

func TestSolutionFile(t *testing.T) {
testCases := []struct {
name, file, expectedPath, expectedURL string
Expand Down

0 comments on commit 485a3bf

Please sign in to comment.