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

@ -5,29 +5,31 @@ import (
"path"
"strings"
"go.uber.org/multierr"
"srs.epita.fr/fic-server/admin/sync"
"srs.epita.fr/fic-server/libfic"
)
func EPITACheckFile(file *fic.EFile, _ *fic.Exercice, exceptions *sync.CheckExceptions) (errs []error) {
func EPITACheckFile(file *fic.EFile, _ *fic.Exercice, exceptions *sync.CheckExceptions) (errs error) {
// Enforce file format
if path.Ext(file.Name) == ".rar" || path.Ext(file.Name) == ".7z" {
errs = append(errs, fmt.Errorf("this file use a forbidden archive type."))
errs = multierr.Append(errs, fmt.Errorf("this file use a forbidden archive type."))
}
// Check for stange file extension
if strings.HasSuffix(file.Name, ".tar.zip") {
errs = append(errs, fmt.Errorf(".tar.zip is not a valid tar format"))
errs = multierr.Append(errs, fmt.Errorf(".tar.zip is not a valid tar format"))
}
// Check .gz files have a dedicated hash
if path.Ext(file.Name) == ".gz" && !strings.HasSuffix(file.Name, ".tar.gz") && len(file.ChecksumShown) == 0 {
errs = append(errs, fmt.Errorf("digest of original, uncompressed, file missing in DIGESTS.txt"))
errs = multierr.Append(errs, fmt.Errorf("digest of original, uncompressed, file missing in DIGESTS.txt"))
}
// Check for huge file to compress
if file.Size > 4000000 && path.Ext(file.Name) == ".tar" {
errs = append(errs, fmt.Errorf("archive to compress with bzip2"))
errs = multierr.Append(errs, fmt.Errorf("archive to compress with bzip2"))
} else if file.Size > 40000000 && (path.Ext(file.Name) == "" ||
path.Ext(file.Name) == ".csv" ||
path.Ext(file.Name) == ".dump" ||
@ -38,7 +40,7 @@ func EPITACheckFile(file *fic.EFile, _ *fic.Exercice, exceptions *sync.CheckExce
path.Ext(file.Name) == ".pcap" ||
path.Ext(file.Name) == ".pcapng" ||
path.Ext(file.Name) == ".txt") {
errs = append(errs, fmt.Errorf("huge file to compress with gzip"))
errs = multierr.Append(errs, fmt.Errorf("huge file to compress with gzip"))
}
return

View file

@ -6,53 +6,55 @@ import (
"strings"
"unicode"
"go.uber.org/multierr"
"srs.epita.fr/fic-server/admin/sync"
"srs.epita.fr/fic-server/libfic"
)
func EPITACheckKeyFlag(flag *fic.FlagKey, raw string, _ *fic.Exercice, exceptions *sync.CheckExceptions) (errs []error) {
func EPITACheckKeyFlag(flag *fic.FlagKey, raw string, _ *fic.Exercice, exceptions *sync.CheckExceptions) (errs error) {
if (flag.Label[0] == 'Q' || flag.Label[0] == 'q') && (flag.Label[1] == 'U' || flag.Label[1] == 'u') ||
(flag.Label[0] == 'W' || flag.Label[0] == 'w') && (flag.Label[1] == 'H' || flag.Label[1] == 'h') {
errs = append(errs, fmt.Errorf("Label should not begin with %s. This seem to be a question. Reword your label as a description of the expected flag, `:` are automatically appended.", flag.Label[0:2]))
errs = multierr.Append(errs, fmt.Errorf("Label should not begin with %s. This seem to be a question. Reword your label as a description of the expected flag, `:` are automatically appended.", flag.Label[0:2]))
flag.Label = flag.Label[1:]
}
if flag.Label[len(flag.Label)-1] != ')' && flag.Label[len(flag.Label)-1] != '©' && !unicode.IsLetter(rune(flag.Label[len(flag.Label)-1])) && !unicode.IsDigit(rune(flag.Label[len(flag.Label)-1])) {
errs = append(errs, fmt.Errorf("Label should not end with punct (%q). Reword your label as a description of the expected flag, `:` are automatically appended.", flag.Label[len(flag.Label)-1]))
errs = multierr.Append(errs, fmt.Errorf("Label should not end with punct (%q). Reword your label as a description of the expected flag, `:` are automatically appended.", flag.Label[len(flag.Label)-1]))
}
if strings.HasPrefix(strings.ToLower(raw), "cve-") && flag.Type != "ucq" {
errs = append(errs, fmt.Errorf("CVE numbers are required to be UCQ with choice_cost"))
errs = multierr.Append(errs, fmt.Errorf("CVE numbers are required to be UCQ with choice_cost"))
}
if _, err := strconv.ParseInt(raw, 10, 64); flag.Type == "key" && err == nil && !exceptions.HasException(":not-number-flag") {
errs = append(errs, fmt.Errorf("shouldn't be this flag a number type? (:not-number-flag)"))
errs = multierr.Append(errs, fmt.Errorf("shouldn't be this flag a number type? (:not-number-flag)"))
}
if flag.Placeholder == "" && (strings.HasPrefix(flag.Type, "number") || flag.Type == "key" || flag.Type == "text" || (flag.Type == "ucq" && flag.ChoicesCost > 0)) {
errs = append(errs, fmt.Errorf("no placeholder defined"))
errs = multierr.Append(errs, fmt.Errorf("no placeholder defined"))
}
if strings.HasPrefix(flag.Type, "number") {
min, max, step, err := fic.AnalyzeNumberFlag(flag.Type)
if err != nil {
errs = append(errs, err)
errs = multierr.Append(errs, err)
} else if min == nil || max == nil || step == nil {
errs = append(errs, fmt.Errorf("please define min and max for your number flag"))
errs = multierr.Append(errs, fmt.Errorf("please define min and max for your number flag"))
} else if (*max-*min) / *step <= 10 {
errs = append(errs, fmt.Errorf("to avoid bruteforce, define more than 10 possibilities"))
errs = multierr.Append(errs, fmt.Errorf("to avoid bruteforce, define more than 10 possibilities"))
}
}
return
}
func EPITACheckKeyFlagWithChoices(flag *fic.FlagKey, raw string, choices []*fic.FlagChoice, _ *fic.Exercice, exceptions *sync.CheckExceptions) (errs []error) {
func EPITACheckKeyFlagWithChoices(flag *fic.FlagKey, raw string, choices []*fic.FlagChoice, _ *fic.Exercice, exceptions *sync.CheckExceptions) (errs error) {
if !exceptions.HasException(":bruteforcable-choices") {
if len(choices) < 10 && flag.ChoicesCost == 0 {
errs = append(errs, fmt.Errorf("requires at least 10 choices to avoid brute-force"))
errs = multierr.Append(errs, fmt.Errorf("requires at least 10 choices to avoid brute-force"))
} else if len(choices) < 6 && flag.ChoicesCost > 0 {
errs = append(errs, fmt.Errorf("requires at least 10 choices to avoid brute-force"))
errs = multierr.Append(errs, fmt.Errorf("requires at least 10 choices to avoid brute-force"))
}
}

View file

@ -4,17 +4,19 @@ import (
"path/filepath"
"strings"
"go.uber.org/multierr"
"srs.epita.fr/fic-server/admin/sync"
"srs.epita.fr/fic-server/libfic"
)
func InspectFile(file *fic.EFile, _ *fic.Exercice, exceptions *sync.CheckExceptions) (errs []error) {
func InspectFile(file *fic.EFile, _ *fic.Exercice, exceptions *sync.CheckExceptions) (errs error) {
if filepath.Ext(file.Name) == ".tar" || strings.HasSuffix(file.Name, ".tar.gz") || strings.HasSuffix(file.Name, ".tar.bz2") {
// Check there is more than 1 file in tarball
errs = append(errs, checkTarball(file, exceptions)...)
errs = multierr.Append(errs, checkTarball(file, exceptions))
} else if filepath.Ext(file.Name) == ".zip" {
// Check there is more than 1 file in zip
errs = append(errs, checkZip(file, exceptions)...)
errs = multierr.Append(errs, checkZip(file, exceptions))
}
return

View file

@ -9,11 +9,13 @@ import (
"log"
"strings"
"go.uber.org/multierr"
"srs.epita.fr/fic-server/admin/sync"
"srs.epita.fr/fic-server/libfic"
)
func checkTarball(file *fic.EFile, exceptions *sync.CheckExceptions) (errs []error) {
func checkTarball(file *fic.EFile, exceptions *sync.CheckExceptions) (errs error) {
fd, closer, err := sync.GetFile(sync.GlobalImporter, file.GetOrigin())
if err != nil {
log.Printf("Unable to open %q: %s", file.GetOrigin(), err.Error())
@ -56,11 +58,11 @@ func checkTarball(file *fic.EFile, exceptions *sync.CheckExceptions) (errs []err
if nbFile < 2 {
if !exceptions.HasException(":one-file-tarball") {
errs = append(errs, fmt.Errorf("don't make a tarball for one file"))
errs = multierr.Append(errs, fmt.Errorf("don't make a tarball for one file"))
}
} else if nbFile < 5 && false {
if !exceptions.HasException(":few-files-tarball") {
errs = append(errs, fmt.Errorf("don't make a tarball for so little files (:few-files-tarball)"))
errs = multierr.Append(errs, fmt.Errorf("don't make a tarball for so little files (:few-files-tarball)"))
}
} else {
log.Printf("%d files found in %q", nbFile, file.Name)

View file

@ -7,11 +7,13 @@ import (
"log"
"strings"
"go.uber.org/multierr"
"srs.epita.fr/fic-server/admin/sync"
"srs.epita.fr/fic-server/libfic"
)
func checkZip(file *fic.EFile, exceptions *sync.CheckExceptions) (errs []error) {
func checkZip(file *fic.EFile, exceptions *sync.CheckExceptions) (errs error) {
fd, closer, err := sync.GetFile(sync.GlobalImporter, file.GetOrigin())
if err != nil {
log.Printf("Unable to open %q: %s", file.GetOrigin(), err.Error())
@ -39,11 +41,11 @@ func checkZip(file *fic.EFile, exceptions *sync.CheckExceptions) (errs []error)
if len(r.File) < 2 {
if !exceptions.HasException(":one-file-tarball") {
errs = append(errs, fmt.Errorf("don't make a ZIP archive for one file, use gzip instead"))
errs = multierr.Append(errs, fmt.Errorf("don't make a ZIP archive for one file, use gzip instead"))
}
} else if len(r.File) < 5 && false {
if !exceptions.HasException(":few-files-tarball") {
errs = append(errs, fmt.Errorf("don't make a ZIP archive for so little files (:few-files-tarball)"))
errs = multierr.Append(errs, fmt.Errorf("don't make a ZIP archive for so little files (:few-files-tarball)"))
}
} else {
log.Printf("%d files found in %q", len(r.File), file.Name)
@ -83,7 +85,7 @@ func checkZip(file *fic.EFile, exceptions *sync.CheckExceptions) (errs []error)
}
if nbLinuxDirFound > 2 && !exceptions.HasException(":not-a-linux-rootfs") {
errs = append(errs, fmt.Errorf("don't use a ZIP archive to store an Unix file system, prefer a tarball (:not-a-linux-rootfs)"))
errs = multierr.Append(errs, fmt.Errorf("don't use a ZIP archive to store an Unix file system, prefer a tarball (:not-a-linux-rootfs)"))
}
return

View file

@ -6,51 +6,53 @@ import (
"log"
"unicode"
"go.uber.org/multierr"
"srs.epita.fr/fic-server/admin/sync"
"srs.epita.fr/fic-server/libfic"
lib "srs.epita.fr/fic-server/repochecker/grammalecte/lib"
)
func GrammalecteCheckKeyFlag(flag *fic.FlagKey, raw string, exercice *fic.Exercice, exceptions *sync.CheckExceptions) (errs []error) {
func GrammalecteCheckKeyFlag(flag *fic.FlagKey, raw string, exercice *fic.Exercice, exceptions *sync.CheckExceptions) (errs error) {
if !isRecognizedLanguage(exercice.Language) {
return
}
label, _, _, _ := flag.AnalyzeFlagLabel()
for _, err := range grammalecte("label ", label, -1, exceptions, &CommonOpts) {
for _, err := range multierr.Errors(grammalecte("label ", label, -1, exceptions, &CommonOpts)) {
if e, ok := err.(lib.GrammarError); ok && e.RuleId == "poncfin_règle1" {
continue
}
errs = append(errs, err)
errs = multierr.Append(errs, err)
}
if len(flag.Help) > 0 {
errs = append(errs, grammalecte("help ", flag.Help, -1, exceptions, &CommonOpts)...)
errs = multierr.Append(errs, grammalecte("help ", flag.Help, -1, exceptions, &CommonOpts))
}
return
}
func GrammalecteCheckFlagChoice(choice *fic.FlagChoice, exercice *fic.Exercice, exceptions *sync.CheckExceptions) (errs []error) {
func GrammalecteCheckFlagChoice(choice *fic.FlagChoice, exercice *fic.Exercice, exceptions *sync.CheckExceptions) (errs error) {
if isRecognizedLanguage(exercice.Language) {
errs = append(errs, grammalecte("label ", choice.Label, -1, exceptions, &CommonOpts)...)
errs = multierr.Append(errs, grammalecte("label ", choice.Label, -1, exceptions, &CommonOpts))
}
if len(errs) == 0 && !unicode.IsUpper(bytes.Runes([]byte(choice.Label))[0]) && !exceptions.HasException(":label_majuscule") {
errs = append(errs, fmt.Errorf("%q nécessite une majuscule (:label_majuscule)", choice.Label))
if len(multierr.Errors(errs)) == 0 && !unicode.IsUpper(bytes.Runes([]byte(choice.Label))[0]) && !exceptions.HasException(":label_majuscule") {
errs = multierr.Append(errs, fmt.Errorf("%q nécessite une majuscule (:label_majuscule)", choice.Label))
}
return
}
func GrammalecteCheckHint(hint *fic.EHint, exercice *fic.Exercice, exceptions *sync.CheckExceptions) (errs []error) {
func GrammalecteCheckHint(hint *fic.EHint, exercice *fic.Exercice, exceptions *sync.CheckExceptions) (errs error) {
if len(hint.Title) > 0 {
if isRecognizedLanguage(exercice.Language) {
errs = append(errs, grammalecte("title ", hint.Title, -1, exceptions, &CommonOpts)...)
errs = multierr.Append(errs, grammalecte("title ", hint.Title, -1, exceptions, &CommonOpts))
}
if len(errs) == 0 && !unicode.IsUpper(bytes.Runes([]byte(hint.Title))[0]) && !exceptions.HasException(":title_majuscule") {
errs = append(errs, fmt.Errorf("%q nécessite une majuscule (:title_majuscule)", hint.Title))
if len(multierr.Errors(errs)) == 0 && !unicode.IsUpper(bytes.Runes([]byte(hint.Title))[0]) && !exceptions.HasException(":title_majuscule") {
errs = multierr.Append(errs, fmt.Errorf("%q nécessite une majuscule (:title_majuscule)", hint.Title))
}
}
@ -59,7 +61,7 @@ func GrammalecteCheckHint(hint *fic.EHint, exercice *fic.Exercice, exceptions *s
return
}
func GrammalecteCheckGrammar(data interface{}, exceptions *sync.CheckExceptions) []error {
func GrammalecteCheckGrammar(data interface{}, exceptions *sync.CheckExceptions) error {
if s, ok := data.(struct {
Str string
Language string

View file

@ -9,6 +9,8 @@ import (
"regexp"
"strings"
"go.uber.org/multierr"
"srs.epita.fr/fic-server/admin/sync"
lib "srs.epita.fr/fic-server/repochecker/grammalecte/lib"
)
@ -119,7 +121,7 @@ var (
mdimg = regexp.MustCompile(`!\[([^\]]+)\]\([^)]+\)`)
)
func grammalecte(name string, text string, paragraph int, exceptions *sync.CheckExceptions, options *GrammalecteOptions) (errs []error) {
func grammalecte(name string, text string, paragraph int, exceptions *sync.CheckExceptions, options *GrammalecteOptions) (errs error) {
// Remove Markdown elements
text = mdimg.ReplaceAllString(text, "Image : ${1}")
@ -173,7 +175,7 @@ func grammalecte(name string, text string, paragraph int, exceptions *sync.Check
}
suggestions, _ := suggest(serror.Value)
errs = append(errs, lib.SpellingError{
errs = multierr.Append(errs, lib.SpellingError{
Prefix: name,
Source: data.Text,
NSource: data.Paragraph,
@ -207,7 +209,7 @@ func grammalecte(name string, text string, paragraph int, exceptions *sync.Check
continue
}
errs = append(errs, err)
errs = multierr.Append(errs, err)
}
}

View file

@ -15,9 +15,10 @@ import (
"github.com/yuin/goldmark/renderer"
"github.com/yuin/goldmark/text"
"github.com/yuin/goldmark/util"
"go.uber.org/multierr"
)
func GrammalecteCheckMDText(str string, lang string, exceptions *sync.CheckExceptions, forbiddenStrings ...string) (errs []error) {
func GrammalecteCheckMDText(str string, lang string, exceptions *sync.CheckExceptions, forbiddenStrings ...string) (errs error) {
if !isRecognizedLanguage(lang) {
return
}
@ -34,7 +35,7 @@ func GrammalecteCheckMDText(str string, lang string, exceptions *sync.CheckExcep
for _, s := range forbiddenStrings {
if strings.Contains(str, s) {
if !exceptions.HasException(":not-forbidden-string:" + s) {
errs = append(errs, fmt.Errorf("Forbidden raw string %q included in file content, don't write it (:not-forbidden-string:%s)", s, s))
errs = multierr.Append(errs, fmt.Errorf("Forbidden raw string %q included in file content, don't write it (:not-forbidden-string:%s)", s, s))
}
}
}
@ -62,13 +63,13 @@ func GrammalecteCheckMDText(str string, lang string, exceptions *sync.CheckExcep
var buf bytes.Buffer
if err := markdown.Convert([]byte(str), &buf); err != nil {
errs = append(errs, err)
errs = multierr.Append(errs, err)
}
errs = append(errs, checker.errs...)
errs = append(errs, voidRenderer.Errors()...)
errs = multierr.Append(errs, checker.errs)
errs = multierr.Append(errs, voidRenderer.Errors())
for _, err := range grammalecte("", buf.String(), 0, exceptions, &CommonOpts) {
for _, err := range multierr.Errors(grammalecte("", buf.String(), 0, exceptions, &CommonOpts)) {
if gerror, ok := err.(lib.GrammarError); ok {
if (gerror.RuleId == "redondances_paragraphe" || gerror.RuleId == "redondances_phrase") && gerror.GetPassage() == "SubstitutDeCode" {
continue
@ -79,7 +80,7 @@ func GrammalecteCheckMDText(str string, lang string, exceptions *sync.CheckExcep
}
}
errs = append(errs, err)
errs = multierr.Append(errs, err)
}
return
@ -87,7 +88,7 @@ func GrammalecteCheckMDText(str string, lang string, exceptions *sync.CheckExcep
type grammarChecker struct {
exceptions *sync.CheckExceptions
errs []error
errs error
}
func (t *grammarChecker) Transform(doc *ast.Document, reader text.Reader, pc parser.Context) {
@ -99,11 +100,11 @@ func (t *grammarChecker) Transform(doc *ast.Document, reader text.Reader, pc par
switch child := node.(type) {
case *ast.Image:
if len(child.Title) > 0 {
t.errs = append(t.errs, grammalecte("", string(child.Title), 0, t.exceptions, &CommonOpts)...)
t.errs = multierr.Append(t.errs, grammalecte("", string(child.Title), 0, t.exceptions, &CommonOpts))
}
case *ast.Link:
if len(child.Title) > 0 {
t.errs = append(t.errs, grammalecte("", string(child.Title), 0, t.exceptions, &CommonOpts)...)
t.errs = multierr.Append(t.errs, grammalecte("", string(child.Title), 0, t.exceptions, &CommonOpts))
}
}

View file

@ -7,10 +7,11 @@ import (
"github.com/yuin/goldmark/ast"
goldrender "github.com/yuin/goldmark/renderer"
"github.com/yuin/goldmark/util"
"go.uber.org/multierr"
)
type VoidRenderer struct {
errs []error
errs error
}
func NewVoidRenderer() *VoidRenderer {
@ -28,7 +29,7 @@ func (r *VoidRenderer) RegisterFuncs(reg goldrender.NodeRendererFuncRegisterer)
reg.Register(ast.KindString, r.renderString)
}
func (r *VoidRenderer) Errors() []error {
func (r *VoidRenderer) Errors() error {
return r.errs
}
@ -77,7 +78,7 @@ func (r *VoidRenderer) renderImage(w util.BufWriter, source []byte, node ast.Nod
// Check there is a correct image alt
alt := nodeToText(n, source)
if len(bytes.Fields(alt)) <= 1 {
r.errs = append(r.errs, fmt.Errorf("No valid image alternative defined for %q", n.Destination))
r.errs = multierr.Append(r.errs, fmt.Errorf("No valid image alternative defined for %q", n.Destination))
return ast.WalkContinue, nil
}

View file

@ -15,6 +15,8 @@ import (
"strconv"
"strings"
"go.uber.org/multierr"
"srs.epita.fr/fic-server/admin/sync"
"srs.epita.fr/fic-server/libfic"
)
@ -108,14 +110,14 @@ func searchBinaryInGit(edir string) (ret []string) {
return
}
func checkExercice(theme *fic.Theme, edir string, dmap *map[int64]*fic.Exercice, exceptions *sync.CheckExceptions) (errs []error) {
func checkExercice(theme *fic.Theme, edir string, dmap *map[int64]*fic.Exercice, exceptions *sync.CheckExceptions) (errs error) {
e, _, eid, exceptions, _, berrs := sync.BuildExercice(sync.GlobalImporter, theme, path.Join(theme.Path, edir), dmap, nil)
errs = append(errs, berrs...)
errs = multierr.Append(errs, berrs)
if e != nil {
// Files
var files []string
var cerrs []error
var cerrs error
if !skipFileChecks {
files, cerrs = sync.CheckExerciceFiles(sync.GlobalImporter, e, exceptions)
log.Printf("%d files checked.\n", len(files))
@ -123,16 +125,16 @@ func checkExercice(theme *fic.Theme, edir string, dmap *map[int64]*fic.Exercice,
files, cerrs = sync.CheckExerciceFilesPresence(sync.GlobalImporter, e)
log.Printf("%d files presents but not checked (please check digest yourself).\n", len(files))
}
errs = append(errs, cerrs...)
errs = multierr.Append(errs, cerrs)
// Flags
flags, cerrs := sync.CheckExerciceFlags(sync.GlobalImporter, e, files, exceptions)
errs = append(errs, cerrs...)
errs = multierr.Append(errs, cerrs)
log.Printf("%d flags checked.\n", len(flags))
// Hints
hints, cerrs := sync.CheckExerciceHints(sync.GlobalImporter, e, exceptions)
errs = append(errs, cerrs...)
errs = multierr.Append(errs, cerrs)
log.Printf("%d hints checked.\n", len(hints))
if dmap != nil {
@ -247,8 +249,9 @@ func main() {
theme, exceptions, errs := sync.BuildTheme(sync.GlobalImporter, p)
if theme != nil && !sync.GlobalImporter.Exists(path.Join(p, "challenge.txt")) && !sync.GlobalImporter.Exists(path.Join(p, "challenge.toml")) {
nberr += len(errs)
for _, err := range errs {
thiserrors := multierr.Errors(errs)
nberr += len(thiserrors)
for _, err := range thiserrors {
log.Println(err)
}
@ -264,7 +267,7 @@ func main() {
for _, edir := range exercices {
ex_exceptions := exceptions.GetFileExceptions(edir)
for _, err := range checkExercice(theme, edir, &dmap, ex_exceptions) {
for _, err := range multierr.Errors(checkExercice(theme, edir, &dmap, ex_exceptions)) {
log.Println(err.Error())
if logMissingResolution {
@ -294,7 +297,7 @@ func main() {
} else {
log.Printf("This is not a theme directory, run checks for exercice.\n\n")
for _, err := range checkExercice(&fic.Theme{}, p, &map[int64]*fic.Exercice{}, nil) {
for _, err := range multierr.Errors(checkExercice(&fic.Theme{}, p, &map[int64]*fic.Exercice{}, nil)) {
nberr += 1
log.Println(err)
}

View file

@ -42,7 +42,7 @@ func (pcapNGReader *PcapNgReader) ReadPacketData() (data []byte, ci gopacket.Cap
// Iterate thought each packet to find potentialy unwanted packets
// TODO: Allow custom rules to specify what is a unwanted packet
func CheckPcap(pcapReader PcapPacketDataReader, pcapName string) (errs []error) {
func CheckPcap(pcapReader PcapPacketDataReader, pcapName string) (errs error) {
warningFlows := make(map[gopacket.Flow]([]time.Time))
//
@ -105,11 +105,11 @@ func CheckPcap(pcapReader PcapPacketDataReader, pcapName string) (errs []error)
return
}
func CheckTextFile(fd *os.File) (errs []error) {
func CheckTextFile(fd *os.File) (errs error) {
return
}
func InspectFileForIPAddr(file *fic.EFile, _ *fic.Exercice, exceptions *sync.CheckExceptions) (errs []error) {
func InspectFileForIPAddr(file *fic.EFile, _ *fic.Exercice, exceptions *sync.CheckExceptions) (errs error) {
fd, closer, err := sync.GetFile(sync.GlobalImporter, file.GetOrigin())
if err != nil {
log.Printf("Unable to open %q: %s", file.GetOrigin(), err.Error())

View file

@ -3,6 +3,8 @@ package main
import (
"fmt"
"go.uber.org/multierr"
"srs.epita.fr/fic-server/admin/sync"
"srs.epita.fr/fic-server/libfic"
)
@ -15,9 +17,9 @@ func RegisterChecksHooks(h *sync.CheckHooks) {
h.RegisterExerciceHook(CheckResolutionVideo)
}
func CheckResolutionVideo(e *fic.Exercice, exceptions *sync.CheckExceptions) (errs []error) {
for _, err := range checkResolutionVideo(e, exceptions) {
errs = append(errs, fmt.Errorf("resolution.mp4: %w", err))
func CheckResolutionVideo(e *fic.Exercice, exceptions *sync.CheckExceptions) (errs error) {
for _, err := range multierr.Errors(checkResolutionVideo(e, exceptions)) {
errs = multierr.Append(errs, fmt.Errorf("resolution.mp4: %w", err))
}
return

View file

@ -9,14 +9,15 @@ import (
"github.com/asticode/go-astisub"
ffmpeg "github.com/u2takey/ffmpeg-go"
"go.uber.org/multierr"
"srs.epita.fr/fic-server/admin/sync"
)
func CheckGrammarSubtitleTrack(path string, index uint, lang string, exceptions *sync.CheckExceptions) (errs []error) {
func CheckGrammarSubtitleTrack(path string, index uint, lang string, exceptions *sync.CheckExceptions) (errs error) {
tmpfile, err := ioutil.TempFile("", "resolution-*.srt")
if err != nil {
errs = append(errs, fmt.Errorf("unable to create a temporary file: %w", err))
errs = multierr.Append(errs, fmt.Errorf("unable to create a temporary file: %w", err))
return
}
defer os.Remove(tmpfile.Name())
@ -26,7 +27,7 @@ func CheckGrammarSubtitleTrack(path string, index uint, lang string, exceptions
Output(tmpfile.Name(), ffmpeg.KwArgs{"map": fmt.Sprintf("0:%d", index)}).
OverWriteOutput().Run()
if err != nil {
errs = append(errs, fmt.Errorf("ffmpeg returns an error when extracting subtitles track: %w", err))
errs = multierr.Append(errs, fmt.Errorf("ffmpeg returns an error when extracting subtitles track: %w", err))
}
subtitles, err := astisub.OpenFile(tmpfile.Name())
@ -39,11 +40,11 @@ func CheckGrammarSubtitleTrack(path string, index uint, lang string, exceptions
for _, item := range subtitles.Items {
lines = append(lines, item.String())
}
for _, e := range hooks.CallCustomHook("CheckGrammar", struct {
for _, e := range multierr.Errors(hooks.CallCustomHook("CheckGrammar", struct {
Str string
Language string
}{Str: strings.Join(lines, "\n"), Language: lang[:2]}, exceptions) {
errs = append(errs, fmt.Errorf("subtitle-track: %w", e))
}{Str: strings.Join(lines, "\n"), Language: lang[:2]}, exceptions)) {
errs = multierr.Append(errs, fmt.Errorf("subtitle-track: %w", e))
}
return

View file

@ -8,6 +8,7 @@ import (
"strconv"
ffmpeg "github.com/u2takey/ffmpeg-go"
"go.uber.org/multierr"
"srs.epita.fr/fic-server/admin/sync"
"srs.epita.fr/fic-server/libfic"
@ -49,7 +50,7 @@ func gcd(a, b int) int {
return bgcd(a, b, 1)
}
func checkResolutionVideo(e *fic.Exercice, exceptions *sync.CheckExceptions) (errs []error) {
func checkResolutionVideo(e *fic.Exercice, exceptions *sync.CheckExceptions) (errs error) {
i, ok := sync.GlobalImporter.(sync.LocalImporter)
if !ok {
log.Printf("Unable to load `videos-rules.so` as the current Importer is not a LocalImporter (%T).", sync.GlobalImporter)
@ -71,7 +72,7 @@ func checkResolutionVideo(e *fic.Exercice, exceptions *sync.CheckExceptions) (er
data, err := ffmpeg.Probe(path)
if err != nil {
errs = append(errs, fmt.Errorf("unable to open %q: %w", path, err))
errs = multierr.Append(errs, fmt.Errorf("unable to open %q: %w", path, err))
return
}
@ -87,79 +88,79 @@ func checkResolutionVideo(e *fic.Exercice, exceptions *sync.CheckExceptions) (er
if s.CodecType == "video" {
video_seen = append(video_seen, idx)
if (s.Width > 1920 || s.Height > 1080) && !exceptions.HasException(":size:above_maximum") {
errs = append(errs, fmt.Errorf("video track is too wide: %dx%d (maximum allowed: 1920x1080)", s.Width, s.Height))
errs = multierr.Append(errs, fmt.Errorf("video track is too wide: %dx%d (maximum allowed: 1920x1080)", s.Width, s.Height))
}
ratio := s.Width * 10 / s.Height
if ratio < 13 || ratio > 19 && !exceptions.HasException(":size:strange_ratio") {
m := gcd(s.Width, s.Height)
errs = append(errs, fmt.Errorf("video track has a strange ratio: %d:%d. Is this really expected?", s.Width/m, s.Height/m))
errs = multierr.Append(errs, fmt.Errorf("video track has a strange ratio: %d:%d. Is this really expected?", s.Width/m, s.Height/m))
}
if s.CodecName != "h264" {
errs = append(errs, fmt.Errorf("video codec has to be H264 (currently: %s)", s.CodecLongName))
errs = multierr.Append(errs, fmt.Errorf("video codec has to be H264 (currently: %s)", s.CodecLongName))
}
duration, err := strconv.ParseFloat(s.Duration, 64)
if err == nil {
if duration < 45 && !exceptions.HasException(":duration:too_short") {
errs = append(errs, fmt.Errorf("video is too short"))
errs = multierr.Append(errs, fmt.Errorf("video is too short"))
}
if duration > 450 && !exceptions.HasException(":duration:too_long") {
errs = append(errs, fmt.Errorf("video is too long"))
errs = multierr.Append(errs, fmt.Errorf("video is too long"))
}
} else {
errs = append(errs, fmt.Errorf("invalid track duration: %q", s.Duration))
errs = multierr.Append(errs, fmt.Errorf("invalid track duration: %q", s.Duration))
}
} else if s.CodecType == "subtitle" {
subtitles_seen = append(subtitles_seen, idx)
if s.CodecName != "mov_text" {
errs = append(errs, fmt.Errorf("subtitle format has to be MOV text/3GPP Timed Text (currently: %s)", s.CodecLongName))
errs = multierr.Append(errs, fmt.Errorf("subtitle format has to be MOV text/3GPP Timed Text (currently: %s)", s.CodecLongName))
}
nbframes, err := strconv.ParseInt(s.NbFrames, 10, 64)
if err == nil {
if nbframes < 5 && !exceptions.HasException(":subtitle:tiny") {
errs = append(errs, fmt.Errorf("too few subtitles"))
errs = multierr.Append(errs, fmt.Errorf("too few subtitles"))
}
} else {
errs = append(errs, fmt.Errorf("invalid number of frame: %q", s.NbFrames))
errs = multierr.Append(errs, fmt.Errorf("invalid number of frame: %q", s.NbFrames))
}
} else if s.CodecType == "audio" {
if !exceptions.HasException(":audio:allowed") {
errs = append(errs, fmt.Errorf("an audio track is present, use subtitle for explainations"))
errs = multierr.Append(errs, fmt.Errorf("an audio track is present, use subtitle for explainations"))
}
if s.CodecName != "aac" {
errs = append(errs, fmt.Errorf("audio codec has to be AAC (Advanced Audio Coding) (currently: %s)", s.CodecLongName))
errs = multierr.Append(errs, fmt.Errorf("audio codec has to be AAC (Advanced Audio Coding) (currently: %s)", s.CodecLongName))
}
} else {
errs = append(errs, fmt.Errorf("unknown track found of type %q", s.CodecType))
errs = multierr.Append(errs, fmt.Errorf("unknown track found of type %q", s.CodecType))
}
}
if len(video_seen) == 0 {
errs = append(errs, fmt.Errorf("no video track found"))
errs = multierr.Append(errs, fmt.Errorf("no video track found"))
} else if len(video_seen) > 1 {
errs = append(errs, fmt.Errorf("%d video tracks found, is it expected?", len(video_seen)))
errs = multierr.Append(errs, fmt.Errorf("%d video tracks found, is it expected?", len(video_seen)))
}
if len(subtitles_seen) == 0 && !exceptions.HasException(":subtitle:no_track") {
errs = append(errs, fmt.Errorf("no subtitles track found"))
errs = multierr.Append(errs, fmt.Errorf("no subtitles track found"))
} else if len(subtitles_seen) > 0 {
for _, idx := range subtitles_seen {
language := e.Language
if lang, ok := vInfo.Streams[idx].Tags["language"]; e.Language != "" && (!ok || lang == "" || lang == "und") {
errs = append(errs, fmt.Errorf("subtitles track %d with no language defined", vInfo.Streams[idx].Index))
errs = multierr.Append(errs, fmt.Errorf("subtitles track %d with no language defined", vInfo.Streams[idx].Index))
} else {
language = lang
}
errs = append(errs, CheckGrammarSubtitleTrack(path, vInfo.Streams[idx].Index, language, exceptions)...)
errs = multierr.Append(errs, CheckGrammarSubtitleTrack(path, vInfo.Streams[idx].Index, language, exceptions))
}
if e.Language != "" && len(subtitles_seen) < 2 {
errs = append(errs, fmt.Errorf("subtitle tracks must exist in original language and translated, only one subtitle track found"))
errs = multierr.Append(errs, fmt.Errorf("subtitle tracks must exist in original language and translated, only one subtitle track found"))
}
}