sync: Replace []error by go.uber.org/multierr

This commit is contained in:
nemunaire 2023-11-22 12:16:53 +01:00
commit b6966d47ce
25 changed files with 380 additions and 348 deletions

View file

@ -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)
}
}