Introducing fileexporter to create archive from git or other importer
This commit is contained in:
parent
c2996b9f0a
commit
7f38911bbb
4 changed files with 241 additions and 0 deletions
1
fileexporter/.gitignore
vendored
Normal file
1
fileexporter/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
fileexporter
|
42
fileexporter/archive.go
Normal file
42
fileexporter/archive.go
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"archive/zip"
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
)
|
||||||
|
|
||||||
|
type archiveFileCreator interface {
|
||||||
|
Create(name string) (io.Writer, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
OutputFormats["archive"] = func(args ...string) (func(string) (io.WriteCloser, error), error) {
|
||||||
|
if len(args) != 1 {
|
||||||
|
return nil, errors.New("archive has 1 required argument: [destination-file]")
|
||||||
|
}
|
||||||
|
|
||||||
|
fd, err := os.Create(args[0])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var w archiveFileCreator
|
||||||
|
if path.Ext(args[0]) == ".zip" {
|
||||||
|
w = zip.NewWriter(fd)
|
||||||
|
} else {
|
||||||
|
return nil, errors.New("destination file has to have .zip extension")
|
||||||
|
}
|
||||||
|
|
||||||
|
return func(dest string) (io.WriteCloser, error) {
|
||||||
|
fw, err := w.Create(dest)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return NopCloser(fw), nil
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
}
|
22
fileexporter/copy.go
Normal file
22
fileexporter/copy.go
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"srs.epita.fr/fic-server/libfic"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
OutputFormats["copy"] = func(args ...string) (func(string) (io.WriteCloser, error), error) {
|
||||||
|
if len(args) > 1 {
|
||||||
|
return nil, errors.New("copy can only take 1 argument: [destination-folder]")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(args) == 1 {
|
||||||
|
fic.FilesDir = args[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
}
|
176
fileexporter/main.go
Normal file
176
fileexporter/main.go
Normal file
|
@ -0,0 +1,176 @@
|
||||||
|
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), 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, len(exercices), tdir)
|
||||||
|
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())
|
||||||
|
|
||||||
|
// 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, err := outputFormat(flag.Args()[1:]...)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
} else if fw != nil {
|
||||||
|
sync.SetWriteFileFunc(fw)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
themes, err := sync.GetThemes(sync.GlobalImporter)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
hasError := false
|
||||||
|
for i, tdir := range themes {
|
||||||
|
log.Printf("Doing theme %d/%d: %s", i, len(themes), tdir)
|
||||||
|
err = exportThemeFiles(tdir)
|
||||||
|
if err != nil {
|
||||||
|
hasError = true
|
||||||
|
log.Println(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if hasError {
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue