Skip to content

Commit

Permalink
Improve cmd
Browse files Browse the repository at this point in the history
  • Loading branch information
mraron committed Apr 14, 2024
1 parent b300dea commit 7b7e294
Show file tree
Hide file tree
Showing 5 changed files with 148 additions and 68 deletions.
13 changes: 1 addition & 12 deletions cmd/glue.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,21 +68,10 @@ func NewGlueCmd(v *viper.Viper) *cobra.Command {
},

RunE: func(cmd *cobra.Command, args []string) error {
fmt.Println(cfg)
conn, err := cfg.Database.Connect()
conn, err := cfg.Database.ConnectAndPing(slog.Default())
if err != nil {
return err
}
for {
slog.Info("Trying to ping database...")
if err := conn.Ping(); err == nil {
slog.Info("OK, connected to database")
break
} else {
slog.Error("Failed to connect to database", "error", err)
}
time.Sleep(5 * time.Second)
}
judges := glue.NewJudges(conn, slog.Default())
go func() {
for {
Expand Down
2 changes: 1 addition & 1 deletion cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ func BindEnvs(iface interface{}, parts ...string) {

var RootCmd = &cobra.Command{
Use: "njudge",
Version: "v0.1.0",
Version: "v0.3.1",
Long: "cli tool to manage njudge instance",
}

Expand Down
175 changes: 121 additions & 54 deletions cmd/testproblem.go
Original file line number Diff line number Diff line change
@@ -1,75 +1,142 @@
package cmd

import (
"context"
"fmt"
"github.com/mraron/njudge/internal/judge"
"github.com/mraron/njudge/pkg/language"
"github.com/mraron/njudge/pkg/language/sandbox"
"github.com/mraron/njudge/pkg/problems"
"github.com/spf13/cobra"
"io"
"log/slog"
"os"
"runtime"
"time"
)

var TestProblemArgs struct {
type TestProblemConfig struct {
ProblemDir string
Language string
SolutionPath string
Verbose int
Verbose bool

IsolateSandboxRange []int
Isolate bool
Concurrency int
}

var DefaultTestProblemConfig = TestProblemConfig{
ProblemDir: ".",
Language: "cpp17",
SolutionPath: "./sol/solution.cpp",
Verbose: false,

IsolateSandboxRange: []int{10, 99},
Isolate: true,
Concurrency: 4,
}

type ProblemStore struct {
problem problems.Problem
}

func (p ProblemStore) GetProblem(s string) (problems.Problem, error) {
return p.problem, nil
}

var TestProblemCmd = &cobra.Command{
Use: "testproblem",
RunE: func(cmd *cobra.Command, args []string) error {
//todo
/*sp := sandbox.NewProvider()
s1, _ := sandbox.NewIsolate(50)
sp.Put(s1)
s2, _ := sandbox.NewIsolate(51)
sp.Put(s2)
w := judge.NewWorker(1, sp)
logger, err := zap.NewDevelopment()
if err != nil {
return err
}
p, err := problems.Parse(TestProblemArgs.ProblemDir)
if err != nil {
return err
}
l, _ := language.DefaultStore.Get(TestProblemArgs.Language)
src, err := os.ReadFile(TestProblemArgs.SolutionPath)
if err != nil {
return err
}
st, err := w.Judge(context.Background(), logger, p, src, l, judge.NewWriterCallback(io.Discard, func() {}))
for _, test := range st.Feedback[0].Testcases() {
fmt.Println(test.Group, test.Index, test.VerdictName, test.Score, test.MaxScore)
}
fmt.Println(st.Feedback[0].Verdict(), st.Feedback[0].Score(), "/", st.Feedback[0].MaxScore())
fmt.Println(st.FeedbackType)
if TestProblemArgs.Verbose > 0 {
res, err := json.Marshal(st)
func NewTestProblemCmd() *cobra.Command {
cfg := TestProblemConfig{}
cmd := &cobra.Command{
Use: "test_problem",
Short: "Test a problem with a solution",
RunE: func(cmd *cobra.Command, args []string) error {
log := slog.Default()
if !cfg.Verbose {
log = slog.New(slog.NewJSONHandler(io.Discard, nil))
}

p, err := problems.Parse(cfg.ProblemDir)
if err != nil {
return err
}

fmt.Println(string(res))
}
provider := sandbox.NewProvider()
sandboxCount := 0
if cfg.Isolate {
for i := cfg.IsolateSandboxRange[0]; i <= cfg.IsolateSandboxRange[1]; i++ {
s, err := sandbox.NewIsolate(i, sandbox.IsolateOptionUseLogger(log))
if err != nil {
return err
}
provider.Put(s)
sandboxCount++
}
} else {
for i := 0; i < 10; i++ {
s, err := sandbox.NewDummy(sandbox.DummyWithLogger(log))
if err != nil {
return err
}
provider.Put(s)
sandboxCount++
}
}

return err*/
return nil
},
}
if 2*cfg.Concurrency > sandboxCount {
log.Warn("sandbox count is low for concurrency")
}
if cfg.Concurrency > runtime.GOMAXPROCS(0) {
log.Warn("concurrency is higher than GOMAXPROCS")
}

func init() {
TestProblemCmd.Flags().StringVar(&TestProblemArgs.ProblemDir, "problem", "", "problemdir")
TestProblemCmd.Flags().StringVar(&TestProblemArgs.Language, "lang", "", "language")
TestProblemCmd.Flags().StringVar(&TestProblemArgs.SolutionPath, "sol", "", "solutionpath")
TestProblemCmd.Flags().CountVarP(&TestProblemArgs.Verbose, "verbose", "v", "verbose")
tokens := make(chan struct{}, cfg.Concurrency)
for range cfg.Concurrency {
tokens <- struct{}{}
}

TestProblemCmd.MarkFlagFilename("sol")
TestProblemCmd.MarkFlagDirname("problem")
j := &judge.Judge{
SandboxProvider: provider,
ProblemStore: ProblemStore{problem: p},
LanguageStore: language.DefaultStore,
RateLimit: 200 * time.Millisecond,
Tokens: tokens,
Logger: log,
}
src, err := os.ReadFile(cfg.SolutionPath)
if err != nil {
return err
}

TestProblemCmd.MarkFlagRequired("problem")
TestProblemCmd.MarkFlagRequired("lang")
TestProblemCmd.MarkFlagRequired("sol")
res, err := j.Judge(context.Background(), judge.Submission{
Source: src,
Language: cfg.Language,
}, func(result judge.Result) error {
fmt.Println(result.Status.Feedback[0].Verdict(), result.Status.Feedback[0].Score(), "/", result.Status.Feedback[0].MaxScore())
return nil
})
if err != nil {
return err
}
for _, test := range res.Feedback[0].Testcases() {
fmt.Println(test.Group, test.Index, test.VerdictName, test.Score, test.MaxScore)
}
fmt.Println(res.Feedback[0].Verdict(), res.Feedback[0].Score(), "/", res.Feedback[0].MaxScore())
fmt.Println(res.FeedbackType)
return nil
},
}
cmd.Flags().StringVar(&cfg.ProblemDir, "problem_dir", DefaultTestProblemConfig.ProblemDir, "problem directory")
cmd.Flags().StringVar(&cfg.Language, "lang", DefaultTestProblemConfig.Language, "language")
cmd.Flags().StringVar(&cfg.SolutionPath, "sol", DefaultTestProblemConfig.SolutionPath, "sol")
cmd.Flags().BoolVar(&cfg.Verbose, "verbose", DefaultTestProblemConfig.Verbose, "verbose")
cmd.Flags().BoolVar(&cfg.Isolate, "isolate", DefaultTestProblemConfig.Isolate, "isolate")
cmd.Flags().IntSliceVar(&cfg.IsolateSandboxRange, "isolate_sandbox_range", DefaultTestProblemConfig.IsolateSandboxRange, "inclusive interval of isolate sandbox IDs")
cmd.Flags().IntVar(&cfg.Concurrency, "concurrency", DefaultTestProblemConfig.Concurrency, "the maximum number of concurrently executed testcase")

RootCmd.AddCommand(TestProblemCmd)
return cmd
}

func init() {
RootCmd.AddCommand(NewTestProblemCmd())
}
6 changes: 5 additions & 1 deletion internal/judge/judge.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,13 @@ type Judger interface {
Judge(ctx context.Context, sub Submission, callback ResultCallback) (*problems.Status, error)
}

type ProblemStore interface {
GetProblem(string) (problems.Problem, error)
}

type Judge struct {
SandboxProvider sandbox.Provider
ProblemStore problems.Store
ProblemStore ProblemStore
LanguageStore language.Store
RateLimit time.Duration

Expand Down
20 changes: 20 additions & 0 deletions internal/web/helpers/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import (
"errors"
"fmt"
"io/ioutil"
"log/slog"
"time"
)

type Database struct {
Expand All @@ -33,6 +35,24 @@ func (db Database) Connect() (*sql.DB, error) {
return sql.Open("postgres", connStr)
}

func (db Database) ConnectAndPing(log *slog.Logger) (*sql.DB, error) {
conn, err := db.Connect()
if err != nil {
return nil, err
}
for {
log.Info("Trying to ping database...")
if err := conn.Ping(); err == nil {
log.Info("OK, connected to database")
break
} else {
log.Error("Failed to connect to database", "error", err)
}
time.Sleep(5 * time.Second)
}
return conn, nil
}

type Server struct {
Mode string
Hostname string
Expand Down

0 comments on commit 7b7e294

Please sign in to comment.