Skip to content

Commit

Permalink
fix: wooda regexp to glob; minor fixes (#22)
Browse files Browse the repository at this point in the history
* fix: wooda minor fixes

* chore: replace regexp with glob

* chore: readme
  • Loading branch information
Gornak40 authored Feb 27, 2024
1 parent 9af44d9 commit 6cfe91a
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 88 deletions.
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,3 @@
# Go workspace file
go.work
/bin
/scoring.tex
26 changes: 11 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
| [ripper](#ripper) | change runs status | 🦍 | ||
| [scalp](#scalp) | incremental scoring | | 🦍 ||
| [valeria](#valeria) | valuer.cfg + tex scoring | | 🦍 ||
| [wooda](#wooda) | regexp problem upload | | 🦍 | 🧑‍💻 |
| [wooda](#wooda) | glob problem files upload | | 🦍 | 🧑‍💻 |
| ⚙️ | move json config to ini | | | 🧑‍💻 |
| 👻 | list/commit problems | | 🦍 | 🤔 |
| 👻 | download/upload package | | 🦍 | 🤔 |
Expand Down Expand Up @@ -50,13 +50,7 @@ Put your config file in `~/.config/algolymp/config.json`.
"polygon": {
"url": "https://polygon.codeforces.com",
"apiKey": "<key>",
"apiSecret": "<secret>",
"wooda": {
"polygon": {
"ignore": ".*\\.a$",
"test": "^tests/\\d+$"
}
}
"apiSecret": "<secret>"
},
"system": {
"editor": "nano"
Expand Down Expand Up @@ -279,35 +273,37 @@ valeria -i 318882 | bat -l tex
![valeria logo](https://algolymp.ru/static/img/valeria.png)

## wooda
*Upload problem files filtered by regexp to Polygon using API.*
*Upload problem files filtered by glob to Polygon using API.*

### About

**Now this is a proof of concept. Many more modes will be supported in the future.**

Match all files in directory with config regexp patterns. Upload recognized files to Polygon.
Match all files in directory with glob pattern. Upload recognized files to Polygon.

Supported modes:

- `ignore`
- `test`
- `tags`

### Flags
- `-i` - problem id (required)
- `-m` - mode from config (required)
- `-d` - problem directory (required)
- `-m` - uploading mode (required)
- `-g` - problem files glob (required)

You should know your shell and probably pass `-g "<glob>"`, not `-g <glob>`

### Config
- `polygon.url`
- `polygon.apiKey`
- `polygon.apiSecret`
- `wooda`

### Examples

```bash
wooda --help
wooda -i 337320 -m polygon -d .
wooda -i 337320 -m test -g "tests/*[^.a]"
wooda -i 337320 -m tags -g tags
```

![wooda logo](https://algolymp.ru/static/img/wooda.png)
48 changes: 35 additions & 13 deletions cmd/wooda/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,33 +12,55 @@ import (
)

func main() {
cfg := config.NewConfig()
woodaKeys := make([]string, 0, len(cfg.Polygon.Wooda))
for k := range cfg.Polygon.Wooda {
woodaKeys = append(woodaKeys, k)
woodaModes := []string{
wooda.ModeTest,
wooda.ModeTags,
}

parser := argparse.NewParser("wooda", "Upload problem files filtered by regexp to Polygon.")
parser := argparse.NewParser("wooda", "Upload problem files filtered by glob to Polygon.")
pID := parser.Int("i", "pid", &argparse.Options{
Required: true,
Help: "Polygon problem ID",
})
mode := parser.Selector("m", "mode", woodaKeys, &argparse.Options{
mode := parser.Selector("m", "mode", woodaModes, &argparse.Options{
Required: true,
Help: "Problem mode (from config)",
Help: "Uploading mode",
})
pDir := parser.String("d", "directory", &argparse.Options{
glob := parser.String("g", "glob", &argparse.Options{
Required: true,
Help: "Problem directory",
Help: "Problem files glob",
})
if err := parser.Parse(os.Args); err != nil {
logrus.WithError(err).Fatal("bad arguments")
}

cfg := config.NewConfig()
pClient := polygon.NewPolygon(&cfg.Polygon)
woodaCfg := cfg.Polygon.Wooda[*mode] // mode is good argparse.Selector
wooda := wooda.NewWooda(pClient, *pID, &woodaCfg)
if err := filepath.Walk(*pDir, wooda.DirWalker); err != nil {
logrus.WithError(err).Fatal("failed wooda matching")
wooda := wooda.NewWooda(pClient, *pID, *mode)

files, err := filepath.Glob(*glob)
if err != nil {
logrus.WithError(err).Fatal("failed to match glob")
}
if len(files) == 0 {
logrus.WithField("glob", *glob).Warn("no files matched glob")

return
}
logrus.WithFields(logrus.Fields{"glob": *glob, "count": len(files)}).
Info("glob match result")

errCount := 0
for _, path := range files {
if err := wooda.Resolve(path); err != nil {
errCount++
logrus.WithError(err).WithField("path", path).Error("failed to resolve")
}
}

if errCount == 0 {
logrus.Info("success resolve all files")
} else {
logrus.WithField("count", errCount).Warn("some errors happened")
}
}
22 changes: 13 additions & 9 deletions polygon/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,9 @@ var (
)

type Config struct {
URL string `json:"url"`
APIKey string `json:"apiKey"`
APISecret string `json:"apiSecret"`
Wooda map[string]WoodaConfig `json:"wooda"`
}

type WoodaConfig struct {
Ignore string `json:"ignore"`
Test string `json:"test"`
URL string `json:"url"`
APIKey string `json:"apiKey"`
APISecret string `json:"apiSecret"`
}

type Polygon struct {
Expand Down Expand Up @@ -200,3 +194,13 @@ func (p *Polygon) SaveTest(tReq TestRequest) error {

return err
}

func (p *Polygon) SaveTags(pID int, tags string) error {
link, params := p.buildURL("problem.saveTags", url.Values{
"problemId": []string{strconv.Itoa(pID)},
"tags": []string{tags},
})
_, err := p.makeQuery(http.MethodPost, link, params)

return err
}
79 changes: 29 additions & 50 deletions polygon/wooda/wooda.go
Original file line number Diff line number Diff line change
@@ -1,59 +1,58 @@
package wooda

import (
"errors"
"fmt"
"io/fs"
"os"
"path/filepath"
"regexp"
"strings"

"github.com/Gornak40/algolymp/polygon"
"github.com/sirupsen/logrus"
)

const (
ModeTest = "test"
ModeTags = "tags"
)

var (
ErrUnknownMode = errors.New("unknown wooda mode")
)

type Wooda struct {
client *polygon.Polygon
pID int
config *polygon.WoodaConfig
mode string
testIndex int
}

func NewWooda(pClient *polygon.Polygon, pID int, wCfg *polygon.WoodaConfig) *Wooda {
func NewWooda(pClient *polygon.Polygon, pID int, mode string) *Wooda {
return &Wooda{
client: pClient,
pID: pID,
config: wCfg,
mode: mode,
testIndex: 1,
}
}

func pathMatch(pattern, path string) bool {
res, err := regexp.MatchString(pattern, path)
if err != nil {
logrus.WithError(err).Error("failed match filepath")

return false
}

return res
}

func getData(mode, path string) (string, error) {
logrus.WithFields(logrus.Fields{"mode": mode, "path": path}).Info("resolve file")
func (w *Wooda) Resolve(path string) error {
logrus.WithFields(logrus.Fields{"mode": w.mode, "path": path}).Info("resolve file")
data, err := os.ReadFile(path)
if err != nil {
return "", err
}

return string(data), nil
}

func (w *Wooda) resolveTest(path string) error {
data, err := getData("test", path)
if err != nil {
return err
}
switch w.mode {
case ModeTest:
return w.resolveTest(path, string(data))
case ModeTags:
return w.resolveTags(string(data))
default:
return fmt.Errorf("%w: %s", ErrUnknownMode, w.mode)
}
}

func (w *Wooda) resolveTest(path, data string) error {
tr := polygon.NewTestRequest(w.pID, w.testIndex).
Input(data).
Description(fmt.Sprintf("File \"%s\"", filepath.Base(path)))
Expand All @@ -65,28 +64,8 @@ func (w *Wooda) resolveTest(path string) error {
return nil
}

func (w *Wooda) matcher(path string) error {
switch {
case pathMatch(w.config.Ignore, path): // silent ignore is the best practice
break
case pathMatch(w.config.Test, path):
if err := w.resolveTest(path); err != nil {
return err
}
default:
logrus.WithField("path", path).Warn("no valid matching")
}

return nil
}

func (w *Wooda) DirWalker(path string, info fs.FileInfo, err error) error {
if err != nil {
return err
}
if info.IsDir() {
return nil
}
func (w *Wooda) resolveTags(data string) error {
tags := strings.Join(strings.Split(data, "\n"), ",")

return w.matcher(path)
return w.client.SaveTags(w.pID, tags)
}

0 comments on commit 6cfe91a

Please sign in to comment.