Skip to content

Commit

Permalink
feat: add vydra polygon package upload (#34)
Browse files Browse the repository at this point in the history
* feat: add vydra polygon package upload

* chore: minor

* chore: resources

* chore: executables

* chore: statement sections

* ci: linter

* chore: time-limit-exceeded-or-accepted

* chore: errors channel; non fatal

* feat: support tags; validator; checker

* feat: update problem info

* feat: upload tests; natstream internal

* feat: validator tests upload

* feat: checker tests

* docs: vydra logo + directory flag

* fix: stdin/stdout; empty tags

* fix: skip dumb generated tests

* feat: points & groups; decompose Upload

* chore: deps better logging

* docs: minor

* fix: no empty script

* chore: remove random mac build

* fix: multitest generator (gen > {3-100})

* docs: known issues block

* docs: minor

* fix: multitest generator

* docs: minor
  • Loading branch information
Gornak40 authored Aug 9, 2024
1 parent 1276fe0 commit 93f8f14
Show file tree
Hide file tree
Showing 12 changed files with 1,021 additions and 17 deletions.
51 changes: 49 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ Extended release notes can be found at [chat](https://t.me/algolymp).
| [ripper](#ripper) | change runs status | 🦍 | ||
| [scalp](#scalp) | incremental scoring | | 🦍 ||
| [valeria](#valeria) | valuer.cfg + tex scoring | | 🦍 ||
| [vydra](#vydra) | upload package | | 🦍 | 🧑‍💻 |
| [wooda](#wooda) | glob problem files upload | | 🦍 ||
| ⚙️ | move json config to ini | | | 🤔 |
| 👻 | set good random group scores | | 🦍 | 🤔 |
| 👻 | algolymp config manager | | | 🤔 |
| 👻 | upload package | | 🦍 | 🤔 |
| 👻 | import polygon problem | 🦍 | 🦍 | 🤔 |
| 👻 | autogen static problem | 🦍 | | 🤔 |
| 👻 | zip extractor for websites | | | 🤔 |
Expand All @@ -37,8 +37,10 @@ Extended release notes can be found at [chat](https://t.me/algolymp).
- 🦍 Engines usage

## Build

Download and install the latest version of [Go](https://go.dev/doc/install).

```bash
sudo apt install go
make
export PATH=$(pwd)/bin:$PATH
```
Expand Down Expand Up @@ -316,6 +318,8 @@ Print `python` solution that outputs correct answer for each passed input file a

Useful with Polygon to upload a problem without main correct solution.

**Make sure your input files has `\r\n` line endings (use `unix2dos`), because Polygon works in Windows.**

It's ready to work with any input/output files, encoding and escape sequences don't matter.

Works great with [wooda](#wooda).
Expand Down Expand Up @@ -450,6 +454,49 @@ valeria -i 285375 -t moscow -c n -c m -c k

![valeria logo](https://algolymp.ru/static/img/valeria.png)

## vydra
*Upload full problem package to Polygon using API.*

### About

**This tool is in beta right now.**

This tool uses `problem.xml` for uploading all package content.

Useful for migration between `polygon.lksh.ru` and `polygon.codeforces.com`.

Designed to replace ~~legacy~~ [polygon-cli](https://github.com/kunyavskiy/polygon-cli) tool.

**Ensure that the problem you are uploading the package into is empty.**

### Known issues

- If problem has testsets other than `tests`, you should create them manually, [issue](https://github.com/Codeforces/polygon-issue-tracking/issues/549);
- If problem is interactive, set `Is problem interactive` checkbox manually;
- If problem has statements resources, upload them manually;
- If problem has custom input/output, set it manually;
- If problem has [FreeMaker](https://freemarker.apache.org) generator, it will expand;
- If problem has stresses, unpload them manually;
- If checker is custom, it's recommended to set `Auto-update` checkbox for `testlib.h`.

### Flags
- `-i` - problem id (required)
- `-p` - problem directory (default: `.`)

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

### Examples

```bash
vydra --help
vydra -i 364022
```

![vydra logo](https://algolymp.ru/static/img/vydra.png)

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

Expand Down
47 changes: 47 additions & 0 deletions cmd/vydra/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package main

import (
"os"

"github.com/Gornak40/algolymp/config"
"github.com/Gornak40/algolymp/polygon"
"github.com/Gornak40/algolymp/polygon/vydra"
"github.com/akamensky/argparse"
"github.com/sirupsen/logrus"
)

func main() {
parser := argparse.NewParser("vydra", "Upload package to Polygon.")
pID := parser.Int("i", "pid", &argparse.Options{
Required: true,
Help: "Polygon problem ID",
})
pDir := parser.String("p", "prob-dir", &argparse.Options{
Required: false,
Default: ".",
Help: "Problem directory (with problem.xml)",
})

if err := parser.Parse(os.Args); err != nil {
logrus.WithError(err).Fatal("bad arguments")
}
if err := os.Chdir(*pDir); err != nil {
logrus.WithError(err).Fatal("bad problem directory")
}

cfg := config.NewConfig()
pClient := polygon.NewPolygon(&cfg.Polygon)

vyd := vydra.NewVydra(pClient, *pID)
errs := make(chan error)
go func() {
for err := range errs {
if err != nil {
logrus.WithError(err).Error("vydra error")
}
}
}()
if err := vyd.Upload(errs); err != nil {
logrus.WithError(err).Fatal("upload failed")
}
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ go 1.22
require (
github.com/PuerkitoBio/goquery v1.8.1
github.com/akamensky/argparse v1.4.0
github.com/facette/natsort v0.0.0-20181210072756-2cd4dd1e2dcb
github.com/sirupsen/logrus v1.9.3
github.com/stretchr/testify v1.9.0
)

require (
github.com/andybalholm/cascadia v1.3.1 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/facette/natsort v0.0.0-20181210072756-2cd4dd1e2dcb // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
golang.org/x/net v0.7.0 // indirect
golang.org/x/sys v0.5.0 // indirect
Expand Down
43 changes: 43 additions & 0 deletions internal/natstream/natstream.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package natstream

import (
"errors"
"os"
"path/filepath"

"github.com/facette/natsort"
)

var (
ErrEndStream = errors.New("no more files in natstream")
)

type NatStream struct {
files []string
idx int
}

func (ns *NatStream) Init(glob string) error {
files, err := filepath.Glob(glob)
if err != nil {
return err
}
ns.files = files
natsort.Sort(ns.files)
ns.idx = 0

return nil
}

func (ns *NatStream) Next() (string, error) {
if ns.idx == len(ns.files) {
return "", ErrEndStream
}
data, err := os.ReadFile(ns.files[ns.idx])
if err != nil {
return "", err
}
ns.idx++

return string(data), nil
}
90 changes: 78 additions & 12 deletions polygon/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,20 @@ import (

const (
sixSecretSymbols = "gorill"
defaultTestset = "tests"
)

type SolutionTag string

const (
TagMain SolutionTag = "MA"
TagCorrect SolutionTag = "OK"
TagIncorrect SolutionTag = "RJ"
TagMain SolutionTag = "MA"
TagCorrect SolutionTag = "OK"
TagIncorrect SolutionTag = "RJ"
TagTimeLimit SolutionTag = "TL"
TagTLorOK SolutionTag = "TO"
TagWrongAnswer SolutionTag = "WA"
TagPresentationError SolutionTag = "PE"
TagMemoryLimit SolutionTag = "ML"
TagRuntimeError SolutionTag = "RE"
)

type FileType string
Expand Down Expand Up @@ -127,15 +132,31 @@ func (p *Polygon) makeQuery(method, link string, params url.Values) (*Answer, er
}

func (p *Polygon) skipEscape(params url.Values) string {
pairs := []string{}
type pair struct {
key string
value string
}

var pairs []pair
for k, vals := range params {
for _, v := range vals {
pairs = append(pairs, fmt.Sprintf("%s=%s", k, v))
pairs = append(pairs, pair{key: k, value: v})
}
}
sort.Strings(pairs)
sort.Slice(pairs, func(i, j int) bool {
if pairs[i].key != pairs[j].key {
return pairs[i].key < pairs[j].key
}

return pairs[i].value < pairs[j].value
})

pairs2 := make([]string, 0, len(pairs))
for _, p := range pairs {
pairs2 = append(pairs2, fmt.Sprintf("%s=%s", p.key, p.value))
}

return strings.Join(pairs, "&")
return strings.Join(pairs2, "&")
}

func (p *Polygon) buildURL(method string, params url.Values) (string, url.Values) {
Expand Down Expand Up @@ -371,12 +392,57 @@ func (p *Polygon) SetInteractor(pID int, interactor string) error {
return err
}

func (p *Polygon) SaveSolution(pID int, name, data string, tag SolutionTag) error {
link, params := p.buildURL("problem.saveSolution", url.Values{
func (p *Polygon) SaveScript(pID int, testset, source string) error {
link, params := p.buildURL("problem.saveScript", url.Values{
"problemId": []string{strconv.Itoa(pID)},
"testset": []string{testset},
"source": []string{source},
})
_, err := p.makeQuery(http.MethodPost, link, params)

return err
}

func (p *Polygon) SaveSolution(sr SolutionRequest) error {
link, params := p.buildURL("problem.saveSolution", url.Values(sr))
_, err := p.makeQuery(http.MethodPost, link, params)

return err
}

func (p *Polygon) SaveStatement(sr StatementRequest) error {
link, params := p.buildURL("problem.saveStatement", url.Values(sr))
_, err := p.makeQuery(http.MethodPost, link, params)

return err
}

func (p *Polygon) SaveValidatorTest(vtr ValidatorTestRequest) error {
link, params := p.buildURL("problem.saveValidatorTest", url.Values(vtr))
_, err := p.makeQuery(http.MethodPost, link, params)

return err
}

func (p *Polygon) SaveCheckerTest(ctr CheckerTestRequest) error {
link, params := p.buildURL("problem.saveCheckerTest", url.Values(ctr))
_, err := p.makeQuery(http.MethodPost, link, params)

return err
}

func (p *Polygon) SaveTestGroup(tgr TestGroupRequest) error {
link, params := p.buildURL("problem.saveTestGroup", url.Values(tgr))
_, err := p.makeQuery(http.MethodPost, link, params)

return err
}

func (p *Polygon) SaveStatementResource(pID int, name, file string) error {
link, params := p.buildURL("problem.saveScript", url.Values{
"problemId": []string{strconv.Itoa(pID)},
"name": []string{name},
"file": []string{data},
"tag": []string{string(tag)},
"file": []string{file},
})
_, err := p.makeQuery(http.MethodPost, link, params)

Expand Down
Loading

0 comments on commit 93f8f14

Please sign in to comment.