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