Skip to content

Commit

Permalink
Also return the updated files when calling omegaup-update-problem
Browse files Browse the repository at this point in the history
This change now also returns a tiny diff of the files that were changed,
so that the frontend does not need to do ugly `git diff` commands just
after updating the contents of a problem.
  • Loading branch information
lhchavez committed Dec 28, 2018
1 parent a1c7980 commit f176851
Show file tree
Hide file tree
Showing 2 changed files with 243 additions and 14 deletions.
194 changes: 187 additions & 7 deletions cmd/omegaup-update-problem/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"os"
"path"
"path/filepath"
"sort"
"time"
)

Expand All @@ -40,11 +41,25 @@ var (
blobUpdateJSON = flag.String("blob-update", "", "Update a subset of the blobs")
)

// UpdatedFile represents an updated file. Type is either "added", "deleted",
// or "modified".
type UpdatedFile struct {
Path string `json:"path"`
Type string `json:"type"`
}

type byPath []UpdatedFile

func (p byPath) Len() int { return len(p) }
func (p byPath) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
func (p byPath) Less(i, j int) bool { return p[i].Path < p[j].Path }

// UpdateResult represents the result of running this command.
type UpdateResult struct {
Status string `json:"status"`
Error string `json:"error,omitempty"`
UpdatedRefs []githttp.UpdatedRef `json:"updated_refs,omitempty"`
Status string `json:"status"`
Error string `json:"error,omitempty"`
UpdatedRefs []githttp.UpdatedRef `json:"updated_refs,omitempty"`
UpdatedFiles []UpdatedFile `json:"updated_files"`
}

// BlobUpdate represents updating a single blob in the repository.
Expand All @@ -53,6 +68,161 @@ type BlobUpdate struct {
ContentsPath string `json:"contents_path"`
}

func getAllFilesForCommit(
repo *git.Repository,
commitID *git.Oid,
) (map[string]*git.Oid, error) {
if commitID.IsZero() {
return map[string]*git.Oid{}, nil
}

commit, err := repo.LookupCommit(commitID)
if err != nil {
return nil, base.ErrorWithCategory(
gitserver.ErrInternalGit,
errors.Wrapf(
err,
"failed to lookup commit %s",
commitID.String(),
),
)
}
defer commit.Free()

tree, err := commit.Tree()
if err != nil {
return nil, base.ErrorWithCategory(
gitserver.ErrInternalGit,
errors.Wrapf(
err,
"failed to lookup commit %s",
commitID.String(),
),
)
}
defer tree.Free()

commitFiles := make(map[string]*git.Oid)
if err := tree.Walk(func(name string, entry *git.TreeEntry) int {
if entry.Type != git.ObjectBlob {
return 0
}
filename := path.Join(name, entry.Name)
commitFiles[filename] = entry.Id
return 0
}); err != nil {
return nil, base.ErrorWithCategory(
gitserver.ErrInternalGit,
errors.Wrapf(
err,
"failed to traverse tree for commit %s",
commitID.String(),
),
)
}

return commitFiles, nil
}

func getUpdatedFiles(
repo *git.Repository,
updatedRefs []githttp.UpdatedRef,
) ([]UpdatedFile, error) {
var masterUpdatedRef *githttp.UpdatedRef
for _, updatedRef := range updatedRefs {
if updatedRef.Name != "refs/heads/master" {
continue
}
masterUpdatedRef = &updatedRef
break
}

if masterUpdatedRef == nil {
return nil, base.ErrorWithCategory(
gitserver.ErrInternalGit,
errors.New("failed to find the updated master ref"),
)
}

fromCommitID, err := git.NewOid(masterUpdatedRef.From)
if err != nil {
return nil, base.ErrorWithCategory(
gitserver.ErrInternalGit,
errors.Wrapf(
err,
"failed to parse the old OID '%s'",
masterUpdatedRef.From,
),
)
}

toCommitID, err := git.NewOid(masterUpdatedRef.To)
if err != nil {
return nil, base.ErrorWithCategory(
gitserver.ErrInternalGit,
errors.Wrapf(
err,
"failed to parse the new OID '%s'",
masterUpdatedRef.To,
),
)
}

fromIDs, err := getAllFilesForCommit(repo, fromCommitID)
if err != nil {
return nil, base.ErrorWithCategory(
gitserver.ErrInternalGit,
errors.Wrapf(
err,
"failed to get the old files for commit %s",
fromCommitID.String(),
),
)
}
toIDs, err := getAllFilesForCommit(repo, toCommitID)
if err != nil {
return nil, base.ErrorWithCategory(
gitserver.ErrInternalGit,
errors.Wrapf(
err,
"failed to get the new files for commit %s",
toCommitID.String(),
),
)
}

var updatedFiles []UpdatedFile
// Deleted files.
for filename := range fromIDs {
if _, ok := toIDs[filename]; !ok {
updatedFiles = append(updatedFiles, UpdatedFile{
Path: filename,
Type: "deleted",
})
}
}

// Added / modified files.
for filename, toID := range toIDs {
if fromID, ok := fromIDs[filename]; ok {
if !fromID.Equal(toID) {
updatedFiles = append(updatedFiles, UpdatedFile{
Path: filename,
Type: "modified",
})
}
} else {
updatedFiles = append(updatedFiles, UpdatedFile{
Path: filename,
Type: "added",
})
}
}

sort.Sort(byPath(updatedFiles))
return updatedFiles, nil
}

func commitZipFile(
zipPath string,
repo *git.Repository,
Expand Down Expand Up @@ -148,9 +318,14 @@ func commitZipFile(
return nil, err
}

updatedFiles, err := getUpdatedFiles(repo, updatedRefs)
if err != nil {
log.Error("failed to get updated files", "err", err)
}
return &UpdateResult{
Status: "ok",
UpdatedRefs: updatedRefs,
Status: "ok",
UpdatedRefs: updatedRefs,
UpdatedFiles: updatedFiles,
}, nil
}

Expand Down Expand Up @@ -381,9 +556,14 @@ func commitBlobs(
return nil, err
}

updatedFiles, err := getUpdatedFiles(repo, updatedRefs)
if err != nil {
log.Error("failed to get updated files", "err", err)
}
return &UpdateResult{
Status: "ok",
UpdatedRefs: updatedRefs,
Status: "ok",
UpdatedRefs: updatedRefs,
UpdatedFiles: updatedFiles,
}, nil
}

Expand Down
63 changes: 56 additions & 7 deletions cmd/omegaup-update-problem/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"io"
"io/ioutil"
"os"
"reflect"
"strings"
"testing"
)
Expand Down Expand Up @@ -57,7 +58,7 @@ func getTreeOid(t *testing.T, extraFileContents map[string]io.Reader, log log15.
}
defer lockfile.Unlock()

if _, err = commitZipFile(
if _, err := commitZipFile(
tmpfile.Name(),
repo,
lockfile,
Expand Down Expand Up @@ -240,7 +241,7 @@ func TestProblemUpdateZip(t *testing.T) {
if _, err = tmpfile.Write(zipContents); err != nil {
t.Fatalf("Failed to write zip: %v", err)
}
if _, err = commitZipFile(
updateResult, err := commitZipFile(
tmpfile.Name(),
repo,
lockfile,
Expand All @@ -250,7 +251,8 @@ func TestProblemUpdateZip(t *testing.T) {
gitserver.ConvertZipUpdateAll,
true,
log,
); err != nil {
)
if err != nil {
t.Fatalf("Failed to commit zip: %v", err)
}
if err := lockfile.Unlock(); err != nil {
Expand All @@ -260,6 +262,23 @@ func TestProblemUpdateZip(t *testing.T) {
t.Fatalf("Failed to acquire the lockfile: %v", err)
}

expectedUpdatedFiles := []UpdatedFile{
{".gitattributes", "added"},
{".gitignore", "added"},
{"cases/0.in", "added"},
{"cases/0.out", "added"},
{"settings.distrib.json", "added"},
{"settings.json", "added"},
{"statements/es.markdown", "added"},
}
if !reflect.DeepEqual(expectedUpdatedFiles, updateResult.UpdatedFiles) {
t.Errorf(
"updated files. expected %v, got %v",
expectedUpdatedFiles,
updateResult.UpdatedFiles,
)
}

oldReferences = discoverReferences(t, repo)
}
{
Expand All @@ -281,7 +300,7 @@ func TestProblemUpdateZip(t *testing.T) {
if _, err = tmpfile.Write(zipContents); err != nil {
t.Fatalf("Failed to write zip: %v", err)
}
if _, err = commitZipFile(
updateResult, err := commitZipFile(
tmpfile.Name(),
repo,
lockfile,
Expand All @@ -291,7 +310,8 @@ func TestProblemUpdateZip(t *testing.T) {
gitserver.ConvertZipUpdateAll,
true,
log,
); err != nil {
)
if err != nil {
t.Fatalf("Failed to commit zip: %v", err)
}
if err := lockfile.Unlock(); err != nil {
Expand All @@ -301,6 +321,17 @@ func TestProblemUpdateZip(t *testing.T) {
t.Fatalf("Failed to acquire the lockfile: %v", err)
}

expectedUpdatedFiles := []UpdatedFile{
{"statements/es.markdown", "modified"},
}
if !reflect.DeepEqual(expectedUpdatedFiles, updateResult.UpdatedFiles) {
t.Errorf(
"updated files. expected %v, got %v",
expectedUpdatedFiles,
updateResult.UpdatedFiles,
)
}

newReferences = discoverReferences(t, repo)
}

Expand Down Expand Up @@ -355,7 +386,7 @@ func TestProblemUpdateBlobs(t *testing.T) {
if _, err = tmpfile.Write(zipContents); err != nil {
t.Fatalf("Failed to write zip: %v", err)
}
if _, err = commitZipFile(
updateResult, err := commitZipFile(
tmpfile.Name(),
repo,
lockfile,
Expand All @@ -365,7 +396,8 @@ func TestProblemUpdateBlobs(t *testing.T) {
gitserver.ConvertZipUpdateAll,
true,
log,
); err != nil {
)
if err != nil {
t.Fatalf("Failed to commit zip: %v", err)
}
if err := lockfile.Unlock(); err != nil {
Expand All @@ -375,6 +407,23 @@ func TestProblemUpdateBlobs(t *testing.T) {
t.Fatalf("Failed to acquire the lockfile: %v", err)
}

expectedUpdatedFiles := []UpdatedFile{
{".gitattributes", "added"},
{".gitignore", "added"},
{"cases/0.in", "added"},
{"cases/0.out", "added"},
{"settings.distrib.json", "added"},
{"settings.json", "added"},
{"statements/es.markdown", "added"},
}
if !reflect.DeepEqual(expectedUpdatedFiles, updateResult.UpdatedFiles) {
t.Errorf(
"updated files. expected %v, got %v",
expectedUpdatedFiles,
updateResult.UpdatedFiles,
)
}

oldReferences = discoverReferences(t, repo)
}
{
Expand Down

0 comments on commit f176851

Please sign in to comment.