Skip to content

Commit 78cbd41

Browse files
author
Katrina Owen
authored
Merge pull request #705 from exercism/path-vs-filepath
Distinguish between path and filepath
2 parents 02810c4 + 60b6ed7 commit 78cbd41

6 files changed

Lines changed: 113 additions & 16 deletions

File tree

cmd/submit.go

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import (
88
"mime/multipart"
99
"os"
1010
"path/filepath"
11-
"strings"
1211

1312
"github.com/exercism/cli/api"
1413
"github.com/exercism/cli/config"
@@ -125,6 +124,8 @@ func runSubmit(cfg config.Config, flags *pflag.FlagSet, args []string) error {
125124
exerciseDir = dir
126125
}
127126

127+
exercise := workspace.NewExerciseFromDir(exerciseDir)
128+
128129
solution, err := workspace.NewSolution(exerciseDir)
129130
if err != nil {
130131
return err
@@ -143,7 +144,7 @@ func runSubmit(cfg config.Config, flags *pflag.FlagSet, args []string) error {
143144
return fmt.Errorf(msg, BinaryName, solution.Exercise, solution.Track)
144145
}
145146

146-
paths := make([]string, 0, len(args))
147+
exercise.Documents = make([]workspace.Document, 0, len(args))
147148
for _, file := range args {
148149
// Don't submit empty files
149150
info, err := os.Stat(file)
@@ -161,10 +162,14 @@ func runSubmit(cfg config.Config, flags *pflag.FlagSet, args []string) error {
161162
fmt.Fprintf(Err, msg, file)
162163
continue
163164
}
164-
paths = append(paths, file)
165+
doc, err := workspace.NewDocument(exercise.Filepath(), file)
166+
if err != nil {
167+
return err
168+
}
169+
exercise.Documents = append(exercise.Documents, doc)
165170
}
166171

167-
if len(paths) == 0 {
172+
if len(exercise.Documents) == 0 {
168173
msg := `
169174
170175
No files found to submit.
@@ -176,18 +181,14 @@ func runSubmit(cfg config.Config, flags *pflag.FlagSet, args []string) error {
176181
body := &bytes.Buffer{}
177182
writer := multipart.NewWriter(body)
178183

179-
for _, path := range paths {
180-
file, err := os.Open(path)
184+
for _, doc := range exercise.Documents {
185+
file, err := os.Open(doc.Filepath())
181186
if err != nil {
182187
return err
183188
}
184189
defer file.Close()
185190

186-
dirname := fmt.Sprintf("%s%s%s", string(os.PathSeparator), solution.Exercise, string(os.PathSeparator))
187-
pieces := strings.Split(path, dirname)
188-
filename := pieces[len(pieces)-1]
189-
190-
part, err := writer.CreateFormFile("files[]", filename)
191+
part, err := writer.CreateFormFile("files[]", doc.Path())
191192
if err != nil {
192193
return err
193194
}

cmd/submit_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ func TestSubmitFiles(t *testing.T) {
180180
assert.Equal(t, 3, len(submittedFiles))
181181

182182
assert.Equal(t, "This is file 1.", submittedFiles["file-1.txt"])
183-
assert.Equal(t, "This is file 2.", submittedFiles[filepath.Join("subdir", "file-2.txt")])
183+
assert.Equal(t, "This is file 2.", submittedFiles["subdir/file-2.txt"])
184184
assert.Equal(t, "This is the readme.", submittedFiles["README.md"])
185185
}
186186

@@ -278,7 +278,7 @@ func TestSubmitFilesForTeamExercise(t *testing.T) {
278278
assert.Equal(t, 2, len(submittedFiles))
279279

280280
assert.Equal(t, "This is file 1.", submittedFiles["file-1.txt"])
281-
assert.Equal(t, "This is file 2.", submittedFiles[filepath.Join("subdir", "file-2.txt")])
281+
assert.Equal(t, "This is file 2.", submittedFiles["subdir/file-2.txt"])
282282
}
283283

284284
func TestSubmitOnlyEmptyFile(t *testing.T) {

workspace/document.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package workspace
2+
3+
import "path/filepath"
4+
5+
// Document is a file in a directory.
6+
type Document struct {
7+
Root string
8+
RelativePath string
9+
}
10+
11+
// NewDocument creates a document from the filepath.
12+
// The root is typically the root of the exercise, and
13+
// path is the absolute path to the file.
14+
func NewDocument(root, path string) (Document, error) {
15+
path, err := filepath.Rel(root, path)
16+
if err != nil {
17+
return Document{}, err
18+
}
19+
return Document{
20+
Root: root,
21+
RelativePath: path,
22+
}, nil
23+
}
24+
25+
// Filepath is the absolute path to the document on the filesystem.
26+
func (doc Document) Filepath() string {
27+
return filepath.Join(doc.Root, doc.RelativePath)
28+
}
29+
30+
// Path is the normalized path.
31+
// It uses forward slashes regardless of the operating system.
32+
func (doc Document) Path() string {
33+
return filepath.ToSlash(doc.RelativePath)
34+
}

workspace/document_test.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package workspace
2+
3+
import (
4+
"io/ioutil"
5+
"os"
6+
"path/filepath"
7+
"testing"
8+
9+
"github.com/stretchr/testify/assert"
10+
)
11+
12+
func TestNormalizedDocumentPath(t *testing.T) {
13+
root, err := ioutil.TempDir("", "docpath")
14+
assert.NoError(t, err)
15+
defer os.RemoveAll(root)
16+
17+
err = os.MkdirAll(filepath.Join(root, "subdirectory"), os.FileMode(0755))
18+
assert.NoError(t, err)
19+
20+
testCases := []struct {
21+
filepath string
22+
path string
23+
}{
24+
{
25+
filepath: filepath.Join(root, "file.txt"),
26+
path: "file.txt",
27+
},
28+
{
29+
filepath: filepath.Join(root, "subdirectory", "file.txt"),
30+
path: "subdirectory/file.txt",
31+
},
32+
}
33+
34+
for _, tc := range testCases {
35+
err = ioutil.WriteFile(tc.filepath, []byte("a file"), os.FileMode(0600))
36+
assert.NoError(t, err)
37+
38+
doc, err := NewDocument(root, tc.filepath)
39+
assert.NoError(t, err)
40+
41+
assert.Equal(t, doc.Path(), tc.path)
42+
}
43+
}

workspace/exercise.go

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,19 @@ import (
88

99
// Exercise is an implementation of a problem in a track.
1010
type Exercise struct {
11-
Root string
12-
Track string
13-
Slug string
11+
Root string
12+
Track string
13+
Slug string
14+
Documents []Document
15+
}
16+
17+
// NewExerciseFromDir constructs an exercise given the exercise directory.
18+
func NewExerciseFromDir(dir string) Exercise {
19+
slug := filepath.Base(dir)
20+
dir = filepath.Dir(dir)
21+
track := filepath.Base(dir)
22+
root := filepath.Dir(dir)
23+
return Exercise{Root: root, Track: track, Slug: slug}
1424
}
1525

1626
// Path is the normalized relative path.

workspace/exercise_test.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,12 @@ func TestHasMetadata(t *testing.T) {
3333
assert.NoError(t, err)
3434
assert.False(t, ok)
3535
}
36+
37+
func TestNewFromDir(t *testing.T) {
38+
dir := filepath.Join("something", "another", "whatever", "the-track", "the-exercise")
39+
40+
exercise := NewExerciseFromDir(dir)
41+
assert.Equal(t, filepath.Join("something", "another", "whatever"), exercise.Root)
42+
assert.Equal(t, "the-track", exercise.Track)
43+
assert.Equal(t, "the-exercise", exercise.Slug)
44+
}

0 commit comments

Comments
 (0)