Skip to content

Commit

Permalink
Merge pull request exercism#830 from exercism/solution-file-abstraction
Browse files Browse the repository at this point in the history
Isolate file logic from http and filesystem logic in download
  • Loading branch information
Katrina Owen authored Mar 8, 2019
2 parents 89e80c4 + 8cd67be commit d6ea6a5
Showing 1 changed file with 51 additions and 24 deletions.
75 changes: 51 additions & 24 deletions cmd/download.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,16 +75,12 @@ func runDownload(cfg config.Config, flags *pflag.FlagSet, args []string) error {
return err
}

for _, file := range download.payload.Solution.Files {
unparsedURL := fmt.Sprintf("%s%s", download.payload.Solution.FileDownloadBaseURL, file)
parsedURL, err := netURL.ParseRequestURI(unparsedURL)

for _, sf := range download.payload.files() {
url, err := sf.url()
if err != nil {
return err
}

url := parsedURL.String()

req, err := client.NewRequest("GET", url, nil)
if err != nil {
return err
Expand All @@ -105,26 +101,12 @@ func runDownload(cfg config.Config, flags *pflag.FlagSet, args []string) error {
continue
}

// TODO: if there's a collision, interactively resolve (show diff, ask if overwrite).
// TODO: handle --force flag to overwrite without asking.

// Work around a path bug due to an early design decision (later reversed) to
// allow numeric suffixes for exercise directories, allowing people to have
// multiple parallel versions of an exercise.
pattern := fmt.Sprintf(`\A.*[/\\]%s-\d*/`, metadata.ExerciseSlug)
rgxNumericSuffix := regexp.MustCompile(pattern)
if rgxNumericSuffix.MatchString(file) {
file = string(rgxNumericSuffix.ReplaceAll([]byte(file), []byte("")))
}

// Rewrite paths submitted with an older, buggy client where the Windows path is being treated as part of the filename.
file = strings.Replace(file, "\\", "/", -1)

relativePath := filepath.FromSlash(file)
dir := filepath.Join(metadata.Dir, filepath.Dir(relativePath))
// TODO: handle collisions
path := sf.relativePath()
dir := filepath.Join(metadata.Dir, filepath.Dir(path))
os.MkdirAll(dir, os.FileMode(0755))

f, err := os.Create(filepath.Join(metadata.Dir, relativePath))
f, err := os.Create(filepath.Join(metadata.Dir, path))
if err != nil {
return err
}
Expand Down Expand Up @@ -311,6 +293,51 @@ func (dp downloadPayload) metadata() workspace.ExerciseMetadata {
}
}

func (dp downloadPayload) files() []solutionFile {
fx := make([]solutionFile, 0, len(dp.Solution.Files))
for _, file := range dp.Solution.Files {
f := solutionFile{
path: file,
baseURL: dp.Solution.FileDownloadBaseURL,
slug: dp.Solution.Exercise.ID,
}
fx = append(fx, f)
}
return fx
}

type solutionFile struct {
path, baseURL, slug string
}

func (sf solutionFile) url() (string, error) {
url, err := netURL.ParseRequestURI(fmt.Sprintf("%s%s", sf.baseURL, sf.path))

if err != nil {
return "", err
}

return url.String(), nil
}

func (sf solutionFile) relativePath() string {
file := sf.path

// Work around a path bug due to an early design decision (later reversed) to
// allow numeric suffixes for exercise directories, letting people have
// multiple parallel versions of an exercise.
pattern := fmt.Sprintf(`\A.*[/\\]%s-\d*/`, sf.slug)
rgxNumericSuffix := regexp.MustCompile(pattern)
if rgxNumericSuffix.MatchString(sf.path) {
file = string(rgxNumericSuffix.ReplaceAll([]byte(sf.path), []byte("")))
}

// Rewrite paths submitted with an older, buggy client where the Windows path is being treated as part of the filename.
file = strings.Replace(file, "\\", "/", -1)

return filepath.FromSlash(file)
}

func setupDownloadFlags(flags *pflag.FlagSet) {
flags.StringP("uuid", "u", "", "the solution UUID")
flags.StringP("track", "t", "", "the track ID")
Expand Down

0 comments on commit d6ea6a5

Please sign in to comment.