From 8cd67be5deab64a6d27b49cd0ef4dbb0ab6ede27 Mon Sep 17 00:00:00 2001 From: Katrina Owen Date: Sun, 3 Mar 2019 09:13:57 -0700 Subject: [PATCH] Isolate file logic from http and filesystem logic in download --- cmd/download.go | 75 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 51 insertions(+), 24 deletions(-) diff --git a/cmd/download.go b/cmd/download.go index c6c3cf628..9deeb0aa0 100644 --- a/cmd/download.go +++ b/cmd/download.go @@ -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 @@ -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 } @@ -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")