This repository has been archived on 2025-06-10. You can view files and clone it, but you cannot make any changes to it's state, such as pushing and creating new issues, pull requests or comments.
server/fileexporter/main.go
Pierre-Olivier Mercier ac5982f905
All checks were successful
continuous-integration/drone/push Build is passing
fileexporter: Close opened fd
2025-05-07 14:01:12 +02:00

184 lines
4.7 KiB
Go

package main
import (
"bytes"
"errors"
"flag"
"io"
"log"
"os"
"path"
"strings"
"srs.epita.fr/fic-server/admin/sync"
"srs.epita.fr/fic-server/libfic"
)
var OutputFormats = map[string]func(...string) (func(string) (io.WriteCloser, error), io.Closer, error){}
func exportThemeFiles(tdir string) (errs error) {
theme, exceptions, err := sync.BuildTheme(sync.GlobalImporter, tdir)
errs = errors.Join(errs, err)
err = sync.SyncThemeFiles(sync.GlobalImporter, theme)
if err != nil {
errs = errors.Join(errs, err)
}
exercices, err := sync.GetExercices(sync.GlobalImporter, theme)
if err != nil {
log.Fatalf("Unable to list exercices for theme %q: %s", theme.Name, err)
}
dmap := map[int64]*fic.Exercice{}
for i, edir := range exercices {
log.Printf("In theme %s, doing exercice %d/%d: %s", tdir, i+1, len(exercices), edir)
err = exportExerciceFiles(theme, edir, &dmap, exceptions)
errs = errors.Join(errs, err)
}
return
}
func exportExerciceFiles(theme *fic.Theme, edir string, dmap *map[int64]*fic.Exercice, exceptions *sync.CheckExceptions) (errs error) {
exercice, _, eid, exceptions, _, berrs := sync.BuildExercice(sync.GlobalImporter, theme, path.Join(theme.Path, edir), dmap, nil)
errs = errors.Join(errs, berrs)
if exercice != nil {
paramsFiles, err := sync.GetExerciceFilesParams(sync.GlobalImporter, exercice)
if err != nil {
errs = errors.Join(errs, sync.NewChallengeTxtError(exercice, 0, err))
return
}
_, err = sync.SyncExerciceFiles(sync.GlobalImporter, exercice, paramsFiles, func(fname string, digests map[string][]byte, filePath, origin string) (interface{}, error) {
return nil, nil
})
errs = errors.Join(errs, err)
if dmap != nil {
(*dmap)[int64(eid)] = exercice
}
}
return
}
type nopCloser struct {
w io.Writer
}
func (nc *nopCloser) Close() error {
return nil
}
func (nc *nopCloser) Write(p []byte) (int, error) {
return nc.w.Write(p)
}
func NopCloser(w io.Writer) *nopCloser {
return &nopCloser{w}
}
func writeFileToTar(dest string) (io.WriteCloser, error) {
log.Println("import2Tar", dest)
return NopCloser(bytes.NewBuffer([]byte{})), nil
}
func main() {
cloudDAVBase := ""
cloudUsername := "fic"
cloudPassword := ""
localImporterDirectory := ""
// Read paremeters from environment
if v, exists := os.LookupEnv("FICCLOUD_URL"); exists {
cloudDAVBase = v
}
if v, exists := os.LookupEnv("FICCLOUD_USER"); exists {
cloudUsername = v
}
if v, exists := os.LookupEnv("FICCLOUD_PASS"); exists {
cloudPassword = v
}
// Read parameters from command line
flag.StringVar(&localImporterDirectory, "localimport", localImporterDirectory,
"Base directory where to find challenges files to import, local part")
flag.StringVar(&cloudDAVBase, "clouddav", cloudDAVBase,
"Base directory where to find challenges files to import, cloud part")
flag.StringVar(&cloudUsername, "clouduser", cloudUsername, "Username used to sync")
flag.StringVar(&cloudPassword, "cloudpass", cloudPassword, "Password used to sync")
flag.BoolVar(&fic.OptionalDigest, "optionaldigest", fic.OptionalDigest, "Is the digest required when importing files?")
flag.BoolVar(&fic.StrongDigest, "strongdigest", fic.StrongDigest, "Are BLAKE2b digests required or is SHA-1 good enough?")
flag.Parse()
// Do not display timestamp
log.SetFlags(0)
// Instantiate importer
if localImporterDirectory != "" {
sync.GlobalImporter = sync.LocalImporter{Base: localImporterDirectory, Symlink: false}
} else if cloudDAVBase != "" {
sync.GlobalImporter, _ = sync.NewCloudImporter(cloudDAVBase, cloudUsername, cloudPassword)
}
if sync.GlobalImporter == nil {
log.Fatal("No importer configured!")
}
log.Println("Using", sync.GlobalImporter.Kind())
hasError := doExport()
if hasError {
os.Exit(1)
}
}
func doExport() bool {
// Configure destination
if flag.NArg() < 1 {
var formats []string
for k := range OutputFormats {
formats = append(formats, k)
}
log.Fatal("Please define wanted output format between [" + strings.Join(formats, " ") + "]")
} else if outputFormat, ok := OutputFormats[flag.Arg(0)]; !ok {
var formats []string
for k := range OutputFormats {
formats = append(formats, k)
}
log.Fatal("Please define wanted output format between [" + strings.Join(formats, " ") + "]")
} else {
fw, closer, err := outputFormat(flag.Args()[1:]...)
if closer != nil {
defer closer.Close()
}
if err != nil {
log.Fatal(err)
} else if fw != nil {
sync.SetWriteFileFunc(fw)
}
}
themes, err := sync.GetThemesExtended(sync.GlobalImporter)
if err != nil {
log.Fatal(err)
}
hasError := false
for i, tdir := range themes {
log.Printf("Doing theme %d/%d: %s", i+1, len(themes), tdir)
err = exportThemeFiles(tdir)
if err != nil {
hasError = true
log.Println(err)
}
}
return hasError
}