sync: Replace []error by go.uber.org/multierr
This commit is contained in:
parent
9f49a689fd
commit
b6966d47ce
25 changed files with 380 additions and 348 deletions
|
|
@ -13,6 +13,7 @@ import (
|
|||
"github.com/BurntSushi/toml"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/yuin/goldmark"
|
||||
"go.uber.org/multierr"
|
||||
|
||||
"srs.epita.fr/fic-server/libfic"
|
||||
)
|
||||
|
|
@ -93,7 +94,7 @@ func parseExerciceDirname(edir string) (eid int, ename string, err error) {
|
|||
}
|
||||
|
||||
// BuildExercice creates an Exercice from a given importer.
|
||||
func BuildExercice(i Importer, theme *fic.Theme, epath string, dmap *map[int64]*fic.Exercice, exceptions_in *CheckExceptions) (e *fic.Exercice, p ExerciceParams, eid int, exceptions *CheckExceptions, edir string, errs []error) {
|
||||
func BuildExercice(i Importer, theme *fic.Theme, epath string, dmap *map[int64]*fic.Exercice, exceptions_in *CheckExceptions) (e *fic.Exercice, p ExerciceParams, eid int, exceptions *CheckExceptions, edir string, errs error) {
|
||||
e = &fic.Exercice{}
|
||||
|
||||
e.Path = epath
|
||||
|
|
@ -104,7 +105,7 @@ func BuildExercice(i Importer, theme *fic.Theme, epath string, dmap *map[int64]*
|
|||
if err != nil {
|
||||
// Ignore eid if we are certain this is an exercice directory, eid will be 0
|
||||
if !i.Exists(path.Join(epath, "title.txt")) {
|
||||
errs = append(errs, NewExerciceError(e, fmt.Errorf("unable to parse exercice directory: %w", err), theme))
|
||||
errs = multierr.Append(errs, NewExerciceError(e, fmt.Errorf("unable to parse exercice directory: %w", err), theme))
|
||||
return nil, p, eid, exceptions_in, edir, errs
|
||||
}
|
||||
}
|
||||
|
|
@ -118,7 +119,7 @@ func BuildExercice(i Importer, theme *fic.Theme, epath string, dmap *map[int64]*
|
|||
if language, err := GetFileContent(i, path.Join(epath, "language.txt")); err == nil {
|
||||
language = strings.TrimSpace(language)
|
||||
if strings.Contains(language, "\n") {
|
||||
errs = append(errs, NewExerciceError(e, fmt.Errorf("language.txt: Language can't contain new lines"), theme))
|
||||
errs = multierr.Append(errs, NewExerciceError(e, fmt.Errorf("language.txt: Language can't contain new lines"), theme))
|
||||
} else {
|
||||
e.Language = language
|
||||
}
|
||||
|
|
@ -128,7 +129,7 @@ func BuildExercice(i Importer, theme *fic.Theme, epath string, dmap *map[int64]*
|
|||
if myTitle, err := GetFileContent(i, path.Join(epath, "title.txt")); err == nil {
|
||||
myTitle = strings.TrimSpace(myTitle)
|
||||
if strings.Contains(myTitle, "\n") {
|
||||
errs = append(errs, NewExerciceError(e, fmt.Errorf("title.txt: Title can't contain new lines"), theme))
|
||||
errs = multierr.Append(errs, NewExerciceError(e, fmt.Errorf("title.txt: Title can't contain new lines"), theme))
|
||||
} else {
|
||||
e.Title = myTitle
|
||||
}
|
||||
|
|
@ -136,7 +137,7 @@ func BuildExercice(i Importer, theme *fic.Theme, epath string, dmap *map[int64]*
|
|||
|
||||
// Character reserved for WIP exercices
|
||||
if len(e.Title) > 0 && e.Title[0] == '%' {
|
||||
errs = append(errs, NewExerciceError(e, fmt.Errorf("title can't contain start by '%%'"), theme))
|
||||
errs = multierr.Append(errs, NewExerciceError(e, fmt.Errorf("title can't contain start by '%%'"), theme))
|
||||
}
|
||||
|
||||
e.URLId = fic.ToURLid(e.Title)
|
||||
|
|
@ -144,7 +145,7 @@ func BuildExercice(i Importer, theme *fic.Theme, epath string, dmap *map[int64]*
|
|||
|
||||
if i.Exists(path.Join(epath, "AUTHORS.txt")) {
|
||||
if authors, err := getAuthors(i, epath); err != nil {
|
||||
errs = append(errs, NewExerciceError(e, fmt.Errorf("unable to get AUTHORS.txt: %w", err)))
|
||||
errs = multierr.Append(errs, NewExerciceError(e, fmt.Errorf("unable to get AUTHORS.txt: %w", err)))
|
||||
} else {
|
||||
// Format authors
|
||||
e.Authors = strings.Join(authors, ", ")
|
||||
|
|
@ -158,13 +159,13 @@ func BuildExercice(i Importer, theme *fic.Theme, epath string, dmap *map[int64]*
|
|||
e.Headline, err = GetFileContent(i, path.Join(epath, "headline.md"))
|
||||
}
|
||||
if err != nil {
|
||||
errs = append(errs, NewExerciceError(e, fmt.Errorf("unable to get exercice's headline: %w", err)))
|
||||
errs = multierr.Append(errs, NewExerciceError(e, fmt.Errorf("unable to get exercice's headline: %w", err)))
|
||||
}
|
||||
if e.Headline != "" {
|
||||
// Call checks hooks
|
||||
for _, h := range hooks.mdTextHooks {
|
||||
for _, err := range h(e.Headline, e.Language, exceptions.GetFileExceptions("headline.md", "headline.txt")) {
|
||||
errs = append(errs, NewExerciceError(e, fmt.Errorf("headline.md: %w", err)))
|
||||
for _, err := range multierr.Errors(h(e.Headline, e.Language, exceptions.GetFileExceptions("headline.md", "headline.txt"))) {
|
||||
errs = multierr.Append(errs, NewExerciceError(e, fmt.Errorf("headline.md: %w", err)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -178,14 +179,14 @@ func BuildExercice(i Importer, theme *fic.Theme, epath string, dmap *map[int64]*
|
|||
err = fmt.Errorf("Unable to find overview.txt nor overview.md")
|
||||
}
|
||||
if err != nil {
|
||||
errs = append(errs, NewExerciceError(e, fmt.Errorf("overview.txt: %s", err), theme))
|
||||
errs = multierr.Append(errs, NewExerciceError(e, fmt.Errorf("overview.txt: %s", err), theme))
|
||||
} else {
|
||||
e.Overview = fixnbsp(e.Overview)
|
||||
|
||||
// Call checks hooks
|
||||
for _, h := range hooks.mdTextHooks {
|
||||
for _, err := range h(e.Overview, e.Language, exceptions.GetFileExceptions("overview.md", "overview.txt")) {
|
||||
errs = append(errs, NewExerciceError(e, fmt.Errorf("overview.md: %w", err)))
|
||||
for _, err := range multierr.Errors(h(e.Overview, e.Language, exceptions.GetFileExceptions("overview.md", "overview.txt"))) {
|
||||
errs = multierr.Append(errs, NewExerciceError(e, fmt.Errorf("overview.md: %w", err)))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -193,14 +194,14 @@ func BuildExercice(i Importer, theme *fic.Theme, epath string, dmap *map[int64]*
|
|||
if e.Headline == "" {
|
||||
err := goldmark.Convert([]byte(strings.Split(e.Overview, "\n")[0]), &buf)
|
||||
if err != nil {
|
||||
errs = append(errs, NewExerciceError(e, fmt.Errorf("overview.md: an error occurs during markdown formating of the headline: %w", err), theme))
|
||||
errs = multierr.Append(errs, NewExerciceError(e, fmt.Errorf("overview.md: an error occurs during markdown formating of the headline: %w", err), theme))
|
||||
} else {
|
||||
e.Headline = string(buf.Bytes())
|
||||
}
|
||||
}
|
||||
|
||||
if e.Overview, err = ProcessMarkdown(i, e.Overview, epath); err != nil {
|
||||
errs = append(errs, NewExerciceError(e, fmt.Errorf("overview.md: an error occurs during markdown formating: %w", err), theme))
|
||||
errs = multierr.Append(errs, NewExerciceError(e, fmt.Errorf("overview.md: an error occurs during markdown formating: %w", err), theme))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -212,17 +213,17 @@ func BuildExercice(i Importer, theme *fic.Theme, epath string, dmap *map[int64]*
|
|||
err = fmt.Errorf("Unable to find statement.txt nor statement.md")
|
||||
}
|
||||
if err != nil {
|
||||
errs = append(errs, NewExerciceError(e, fmt.Errorf("statement.md: %w", err), theme))
|
||||
errs = multierr.Append(errs, NewExerciceError(e, fmt.Errorf("statement.md: %w", err), theme))
|
||||
} else {
|
||||
// Call checks hooks
|
||||
for _, h := range hooks.mdTextHooks {
|
||||
for _, err := range h(e.Statement, e.Language, exceptions.GetFileExceptions("statement.md", "statement.txt")) {
|
||||
errs = append(errs, NewExerciceError(e, fmt.Errorf("statement.md: %w", err)))
|
||||
for _, err := range multierr.Errors(h(e.Statement, e.Language, exceptions.GetFileExceptions("statement.md", "statement.txt"))) {
|
||||
errs = multierr.Append(errs, NewExerciceError(e, fmt.Errorf("statement.md: %w", err)))
|
||||
}
|
||||
}
|
||||
|
||||
if e.Statement, err = ProcessMarkdown(i, fixnbsp(e.Statement), epath); err != nil {
|
||||
errs = append(errs, NewExerciceError(e, fmt.Errorf("statement.md: an error occurs during markdown formating: %w", err), theme))
|
||||
errs = multierr.Append(errs, NewExerciceError(e, fmt.Errorf("statement.md: an error occurs during markdown formating: %w", err), theme))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -232,17 +233,17 @@ func BuildExercice(i Importer, theme *fic.Theme, epath string, dmap *map[int64]*
|
|||
e.Finished, err = GetFileContent(i, path.Join(epath, "finished.md"))
|
||||
}
|
||||
if err != nil {
|
||||
errs = append(errs, NewExerciceError(e, fmt.Errorf("finished.md: %w", err), theme))
|
||||
errs = multierr.Append(errs, NewExerciceError(e, fmt.Errorf("finished.md: %w", err), theme))
|
||||
} else if len(e.Finished) > 0 {
|
||||
// Call checks hooks
|
||||
for _, h := range hooks.mdTextHooks {
|
||||
for _, err := range h(e.Finished, e.Language, exceptions.GetFileExceptions("finished.md", "finished.txt")) {
|
||||
errs = append(errs, NewExerciceError(e, fmt.Errorf("finished.md: %w", err)))
|
||||
for _, err := range multierr.Errors(h(e.Finished, e.Language, exceptions.GetFileExceptions("finished.md", "finished.txt"))) {
|
||||
errs = multierr.Append(errs, NewExerciceError(e, fmt.Errorf("finished.md: %w", err)))
|
||||
}
|
||||
}
|
||||
|
||||
if e.Finished, err = ProcessMarkdown(i, e.Finished, epath); err != nil {
|
||||
errs = append(errs, NewExerciceError(e, fmt.Errorf("finished.md: an error occurs during markdown formating: %w", err), theme))
|
||||
errs = multierr.Append(errs, NewExerciceError(e, fmt.Errorf("finished.md: an error occurs during markdown formating: %w", err), theme))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -251,31 +252,31 @@ func BuildExercice(i Importer, theme *fic.Theme, epath string, dmap *map[int64]*
|
|||
} else if i.Exists(path.Join(epath, "heading.png")) {
|
||||
e.Image = path.Join(epath, "heading.png")
|
||||
} else if theme.Image == "" {
|
||||
errs = append(errs, NewExerciceError(e, fmt.Errorf("heading.jpg: No such file")))
|
||||
errs = multierr.Append(errs, NewExerciceError(e, fmt.Errorf("heading.jpg: No such file")))
|
||||
}
|
||||
|
||||
// Parse challenge.txt
|
||||
var md toml.MetaData
|
||||
p, md, err = parseExerciceParams(i, epath)
|
||||
if err != nil {
|
||||
errs = append(errs, NewChallengeTxtError(e, 0, err, theme))
|
||||
errs = multierr.Append(errs, NewChallengeTxtError(e, 0, err, theme))
|
||||
return
|
||||
}
|
||||
|
||||
// Alert about unknown keys in challenge.txt
|
||||
if len(md.Undecoded()) > 0 {
|
||||
for _, k := range md.Undecoded() {
|
||||
errs = append(errs, NewChallengeTxtError(e, 0, fmt.Errorf("unknown key %q found, check https://fic.srs.epita.fr/doc/files/challenge/", k), theme))
|
||||
errs = multierr.Append(errs, NewChallengeTxtError(e, 0, fmt.Errorf("unknown key %q found, check https://fic.srs.epita.fr/doc/files/challenge/", k), theme))
|
||||
}
|
||||
}
|
||||
|
||||
e.WIP = p.WIP
|
||||
if p.WIP && !AllowWIPExercice {
|
||||
errs = append(errs, NewExerciceError(e, fmt.Errorf("exercice declared Work In Progress in challenge.txt"), theme))
|
||||
errs = multierr.Append(errs, NewExerciceError(e, fmt.Errorf("exercice declared Work In Progress in challenge.txt"), theme))
|
||||
}
|
||||
|
||||
if p.Gain == 0 {
|
||||
errs = append(errs, NewChallengeTxtError(e, 0, fmt.Errorf("Undefined gain for challenge"), theme))
|
||||
errs = multierr.Append(errs, NewChallengeTxtError(e, 0, fmt.Errorf("Undefined gain for challenge"), theme))
|
||||
} else {
|
||||
e.Gain = p.Gain
|
||||
}
|
||||
|
|
@ -283,11 +284,11 @@ func BuildExercice(i Importer, theme *fic.Theme, epath string, dmap *map[int64]*
|
|||
// Handle dependency
|
||||
if len(p.Dependencies) > 0 {
|
||||
if len(p.Dependencies[0].Theme) > 0 && p.Dependencies[0].Theme != theme.Name {
|
||||
errs = append(errs, NewExerciceError(e, fmt.Errorf("unable to treat dependency to another theme (%q): not implemented.", p.Dependencies[0].Theme), theme))
|
||||
errs = multierr.Append(errs, NewExerciceError(e, fmt.Errorf("unable to treat dependency to another theme (%q): not implemented.", p.Dependencies[0].Theme), theme))
|
||||
} else {
|
||||
if dmap == nil {
|
||||
if dmap2, err := buildDependancyMap(i, theme); err != nil {
|
||||
errs = append(errs, NewExerciceError(e, fmt.Errorf("unable to build dependency map: %w", err), theme))
|
||||
errs = multierr.Append(errs, NewExerciceError(e, fmt.Errorf("unable to build dependency map: %w", err), theme))
|
||||
} else {
|
||||
dmap = &dmap2
|
||||
}
|
||||
|
|
@ -305,7 +306,7 @@ func BuildExercice(i Importer, theme *fic.Theme, epath string, dmap *map[int64]*
|
|||
for k, _ := range *dmap {
|
||||
dmap_keys = append(dmap_keys, fmt.Sprintf("%d", k))
|
||||
}
|
||||
errs = append(errs, NewExerciceError(e, fmt.Errorf("Unable to find required exercice dependancy %d (available at time of processing: %s)", p.Dependencies[0].Id, strings.Join(dmap_keys, ",")), theme))
|
||||
errs = multierr.Append(errs, NewExerciceError(e, fmt.Errorf("Unable to find required exercice dependancy %d (available at time of processing: %s)", p.Dependencies[0].Id, strings.Join(dmap_keys, ",")), theme))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -318,10 +319,10 @@ func BuildExercice(i Importer, theme *fic.Theme, epath string, dmap *map[int64]*
|
|||
if !i.Exists(e.VideoURI) {
|
||||
e.VideoURI = ""
|
||||
} else if size, err := GetFileSize(i, e.VideoURI); err != nil {
|
||||
errs = append(errs, NewExerciceError(e, fmt.Errorf("resolution.mp4: %w", err), theme))
|
||||
errs = multierr.Append(errs, NewExerciceError(e, fmt.Errorf("resolution.mp4: %w", err), theme))
|
||||
e.VideoURI = ""
|
||||
} else if size == 0 {
|
||||
errs = append(errs, NewExerciceError(e, fmt.Errorf("resolution.mp4: The file is empty!"), theme))
|
||||
errs = multierr.Append(errs, NewExerciceError(e, fmt.Errorf("resolution.mp4: The file is empty!"), theme))
|
||||
e.VideoURI = ""
|
||||
} else {
|
||||
e.VideoURI = strings.Replace(url.PathEscape(path.Join("$RFILES$", e.VideoURI)), "%2F", "/", -1)
|
||||
|
|
@ -335,21 +336,21 @@ func BuildExercice(i Importer, theme *fic.Theme, epath string, dmap *map[int64]*
|
|||
|
||||
if i.Exists(writeup) {
|
||||
if size, err := GetFileSize(i, writeup); err != nil {
|
||||
errs = append(errs, NewExerciceError(e, fmt.Errorf("resolution.md: %w", err), theme))
|
||||
errs = multierr.Append(errs, NewExerciceError(e, fmt.Errorf("resolution.md: %w", err), theme))
|
||||
} else if size == 0 {
|
||||
errs = append(errs, NewExerciceError(e, fmt.Errorf("resolution.md: The file is empty!"), theme))
|
||||
errs = multierr.Append(errs, NewExerciceError(e, fmt.Errorf("resolution.md: The file is empty!"), theme))
|
||||
} else if e.Resolution, err = GetFileContent(i, writeup); err != nil {
|
||||
errs = append(errs, NewExerciceError(e, fmt.Errorf("resolution.md: %w", err), theme))
|
||||
errs = multierr.Append(errs, NewExerciceError(e, fmt.Errorf("resolution.md: %w", err), theme))
|
||||
} else {
|
||||
// Call checks hooks
|
||||
for _, h := range hooks.mdTextHooks {
|
||||
for _, err := range h(e.Resolution, e.Language, exceptions.GetFileExceptions("resolution.md"), p.GetRawFlags()...) {
|
||||
errs = append(errs, NewExerciceError(e, fmt.Errorf("resolution.md: %w", err)))
|
||||
for _, err := range multierr.Errors(h(e.Resolution, e.Language, exceptions.GetFileExceptions("resolution.md"), p.GetRawFlags()...)) {
|
||||
errs = multierr.Append(errs, NewExerciceError(e, fmt.Errorf("resolution.md: %w", err)))
|
||||
}
|
||||
}
|
||||
|
||||
if e.Resolution, err = ProcessMarkdown(i, e.Resolution, epath); err != nil {
|
||||
errs = append(errs, NewExerciceError(e, fmt.Errorf("resolution.md: error during markdown processing: %w", err), theme))
|
||||
errs = multierr.Append(errs, NewExerciceError(e, fmt.Errorf("resolution.md: error during markdown processing: %w", err), theme))
|
||||
} else {
|
||||
resolutionFound = true
|
||||
}
|
||||
|
|
@ -357,28 +358,26 @@ func BuildExercice(i Importer, theme *fic.Theme, epath string, dmap *map[int64]*
|
|||
}
|
||||
|
||||
if !resolutionFound {
|
||||
errs = append(errs, NewExerciceError(e, ErrResolutionNotFound, theme))
|
||||
errs = multierr.Append(errs, NewExerciceError(e, ErrResolutionNotFound, theme))
|
||||
}
|
||||
|
||||
// Call checks hooks
|
||||
for _, h := range hooks.exerciceHooks {
|
||||
for _, err := range h(e, exceptions) {
|
||||
errs = append(errs, NewExerciceError(e, err))
|
||||
for _, err := range multierr.Errors(h(e, exceptions)) {
|
||||
errs = multierr.Append(errs, NewExerciceError(e, err))
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// SyncExercice imports new or updates existing given exercice.
|
||||
func SyncExercice(i Importer, theme *fic.Theme, epath string, dmap *map[int64]*fic.Exercice, exceptions_in *CheckExceptions) (e *fic.Exercice, eid int, exceptions *CheckExceptions, errs []error) {
|
||||
func SyncExercice(i Importer, theme *fic.Theme, epath string, dmap *map[int64]*fic.Exercice, exceptions_in *CheckExceptions) (e *fic.Exercice, eid int, exceptions *CheckExceptions, errs error) {
|
||||
var err error
|
||||
var p ExerciceParams
|
||||
var berrors []error
|
||||
var berrors error
|
||||
|
||||
e, p, eid, exceptions, _, berrors = BuildExercice(i, theme, epath, dmap, exceptions_in)
|
||||
for _, e := range berrors {
|
||||
errs = append(errs, e)
|
||||
}
|
||||
errs = multierr.Append(errs, berrors)
|
||||
|
||||
if e != nil {
|
||||
if len(e.Image) > 0 {
|
||||
|
|
@ -396,24 +395,24 @@ func SyncExercice(i Importer, theme *fic.Theme, epath string, dmap *map[int64]*f
|
|||
|
||||
return nil, err
|
||||
}); err != nil {
|
||||
errs = append(errs, NewExerciceError(e, fmt.Errorf("unable to import heading image: %w", err)))
|
||||
errs = multierr.Append(errs, NewExerciceError(e, fmt.Errorf("unable to import heading image: %w", err)))
|
||||
}
|
||||
}
|
||||
|
||||
// Create or update the exercice
|
||||
err = theme.SaveNamedExercice(e)
|
||||
if err != nil {
|
||||
errs = append(errs, NewExerciceError(e, fmt.Errorf("error on exercice save: %w", err), theme))
|
||||
errs = multierr.Append(errs, NewExerciceError(e, fmt.Errorf("error on exercice save: %w", err), theme))
|
||||
return
|
||||
}
|
||||
|
||||
// Import eercice tags
|
||||
if _, err := e.WipeTags(); err != nil {
|
||||
errs = append(errs, NewExerciceError(e, fmt.Errorf("unable to wipe tags: %w", err), theme))
|
||||
errs = multierr.Append(errs, NewExerciceError(e, fmt.Errorf("unable to wipe tags: %w", err), theme))
|
||||
}
|
||||
for _, tag := range p.Tags {
|
||||
if _, err := e.AddTag(tag); err != nil {
|
||||
errs = append(errs, NewExerciceError(e, fmt.Errorf("unable to add tag: %w", err), theme))
|
||||
errs = multierr.Append(errs, NewExerciceError(e, fmt.Errorf("unable to add tag: %w", err), theme))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
|
@ -423,9 +422,9 @@ func SyncExercice(i Importer, theme *fic.Theme, epath string, dmap *map[int64]*f
|
|||
}
|
||||
|
||||
// SyncExercices imports new or updates existing exercices, in a given theme.
|
||||
func SyncExercices(i Importer, theme *fic.Theme, exceptions *CheckExceptions) (exceptions_out map[int]*CheckExceptions, errs []error) {
|
||||
func SyncExercices(i Importer, theme *fic.Theme, exceptions *CheckExceptions) (exceptions_out map[int]*CheckExceptions, errs error) {
|
||||
if exercices, err := GetExercices(i, theme); err != nil {
|
||||
errs = append(errs, err)
|
||||
errs = multierr.Append(errs, err)
|
||||
} else {
|
||||
exceptions_out = make(map[int]*CheckExceptions)
|
||||
emap := map[string]int{}
|
||||
|
|
@ -438,7 +437,7 @@ func SyncExercices(i Importer, theme *fic.Theme, exceptions *CheckExceptions) (e
|
|||
emap[e.Title] = eid
|
||||
dmap[int64(eid)] = e
|
||||
exceptions_out[eid] = ex_exceptions
|
||||
errs = append(errs, cur_errs...)
|
||||
errs = multierr.Append(errs, cur_errs)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Reference in a new issue