Commit 64310851 authored by Timon Stampfli's avatar Timon Stampfli

Adding Fetchbundle mechanism and 0.8.0 workspacesettings

parent 992cb827
Pipeline #4898 failed with stages
in 34 seconds
......@@ -37,11 +37,11 @@
"program": "${workspaceRoot}/helper/",
"env": {},
"args": [
"outfile",
"/home/timon/soicodedbg/test.txt",
"compile",
"echo",
"hallo"
"fetchBundle",
"--url",
"https://blob.dolansoft.org/soicode/compilerbundle-linux-amd64-soiheaders.tar.xz",
"--targetDir",
"/home/timon/.config/VSCodium/User/globalStorage/swissolyinfo.soicode/bundle/soiheaders"
]
}
]
......
......@@ -6,4 +6,5 @@ src/**
.gitignore
tsconfig.json
vsc-extension-quickstart.md
tslint.json
\ No newline at end of file
tslint.json
helper/**
......@@ -8,35 +8,19 @@ import (
"net/http"
"os"
"path/filepath"
"regexp"
"time"
"github.com/cenkalti/backoff"
"github.com/ulikunitz/xz"
)
var updateExcludeFilenames = regexp.MustCompile(".*\\.cpp")
func fetchBundle() {
fetchBundleCmd := flag.NewFlagSet("fetchBundle", flag.ExitOnError)
url := fetchBundleCmd.String("url", "", "URL to compiler bundle")
targetDir := fetchBundleCmd.String("targetDir", "", "Bundle target directory")
func fetchSoicodeBundle() {
bootstrapCmd := flag.NewFlagSet("bootstrap", flag.ExitOnError)
url := bootstrapCmd.String("url", "", "URL to task blob")
targetDir := bootstrapCmd.String("target-dir", "", "Task target directory")
update := bootstrapCmd.Bool("update", false, "Update folder and exclude templates from extraction")
if len(os.Args) == 1 {
fmt.Println("usage: helper <command> [<args>]")
fmt.Println(" bootstrap Bootstraps a task folder from a remote source")
return
}
switch os.Args[1] {
case "bootstrap":
bootstrapCmd.Parse(os.Args[2:])
default:
fmt.Printf("%q is not valid command.\n", os.Args[1])
os.Exit(2)
}
if bootstrapCmd.Parsed() {
fetchBundleCmd.Parse(os.Args[2:])
if fetchBundleCmd.Parsed() {
if *url == "" {
fmt.Printf("URL is required\n")
os.Exit(2)
......@@ -45,7 +29,9 @@ func fetchSoicodeBundle() {
fmt.Printf("Target Dir is required\n")
os.Exit(2)
}
bootstrap(*url, *targetDir, *update)
downloadAndUnpack(*url, *targetDir)
} else {
os.Exit(4)
}
}
......@@ -57,7 +43,7 @@ func newUserFriendlyBackoff() backoff.BackOff {
return b
}
func bootstrap(url, targetDir string, update bool) {
func downloadAndUnpack(url, targetDir string) {
var res *http.Response
getBootstrapStream := func() error {
var err error
......@@ -84,6 +70,14 @@ func bootstrap(url, targetDir string, update bool) {
fmt.Printf("Invalid compression header: %v", err)
os.Exit(3)
}
if _, err := os.Stat(targetDir); !os.IsNotExist(err) {
err = os.RemoveAll(targetDir)
if err != nil {
fmt.Printf("Couldn't delete targetDir")
os.Exit(3)
}
}
tr := tar.NewReader(r)
for {
header, err := tr.Next()
......@@ -100,10 +94,6 @@ func bootstrap(url, targetDir string, update bool) {
continue
}
if update && updateExcludeFilenames.MatchString(header.Name) {
continue
}
target := filepath.Join(targetDir, header.Name)
switch header.Typeflag {
......
package main
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"net"
"os"
"sort"
"github.com/fatih/color"
)
func sendResult(conn net.Conn, binaryPath, sampleName string, res sampleExecutionResult) {
type transportSampleExecutionResult struct {
Binarypath string
Samplename string
Result sampleExecutionResult
}
msg, err := json.Marshal(transportSampleExecutionResult{
Binarypath: binaryPath,
Samplename: sampleName,
Result: res,
})
if err != nil {
panic(err)
}
fmt.Fprintf(conn, string(msg))
fmt.Fprintf(conn, "\n")
func printUsage() {
fmt.Println("usage: helper <command> [<args>]")
fmt.Println(" fetchBundle Downloads and unpacks the compiler bundle if a new version is available")
fmt.Println(" runOneSample Evaluate one sample")
fmt.Println(" runAllSamples Evaluate all samples")
fmt.Println(" runWithManualInput Evaluate samples on manual input")
}
var (
colorInfo = color.New(color.FgYellow)
colorInfoIdent = color.New(color.FgHiYellow)
colorError = color.New(color.FgRed)
colorErrorIdent = color.New(color.FgHiRed)
colorCorrect = color.New(color.FgGreen)
colorCorrectIdent = color.New(color.FgHiGreen)
colorProgramOutput = color.New(color.FgBlue)
colorExpectedOutput = color.New(color.FgCyan)
)
func printRunManualInput(binaryPath string) {
colorInfo.Printf("Running program '")
colorInfoIdent.Printf("%v", binaryPath)
colorInfo.Printf("' with your input :\n")
}
func printRunSampleInfo(binaryPath, sampleName string) {
colorInfo.Printf("Running Sample'")
colorInfoIdent.Printf("%v", sampleName)
colorInfo.Printf("' on program '")
colorInfoIdent.Printf("%v", binaryPath)
colorInfo.Printf("':\n")
}
func printSampleVerdict(binaryPath, sampleName, programOutput, expectedOutput, processError string) {
if programOutput != expectedOutput {
// Todo: Highlight diff
colorError.Printf("Sample '")
colorErrorIdent.Printf("%v", sampleName)
colorError.Printf("': Output differs\n")
colorInfo.Printf("Expected Output:\n")
colorProgramOutput.Printf("%v", expectedOutput)
colorInfo.Printf("\nYour Program's output:\n")
colorExpectedOutput.Printf("%v\n", programOutput)
} else {
colorCorrect.Printf("Sample '")
colorCorrectIdent.Printf("%v", sampleName)
colorCorrect.Printf("': Correct\n")
func main() {
if len(os.Args) <= 1 {
printUsage()
return
}
fmt.Printf("%v\n", processError)
}
type anything interface {
}
func mapToSortedKeys(m map[string]Sample) []string {
keys := []string{}
for k := range m {
keys = append(keys, k)
switch os.Args[1] {
case "fetchBundle":
fetchBundle()
case "runOneSample":
runOneSample()
case "runAllSamples":
runAllSamples()
case "runWithManualInput":
runWithManualInput()
default:
fmt.Printf("%q is not valid command.\n", os.Args[1])
os.Exit(2)
}
sort.Strings(keys)
return keys
}
func main() {
var conn net.Conn
for argIndex := 1; argIndex < len(os.Args); argIndex++ {
switch os.Args[argIndex] {
case "connectTo": // port
argIndex++
port := os.Args[argIndex]
var err error
conn, err = net.Dial("tcp", "127.0.0.1:"+port)
if err != nil {
panic(err)
}
case "runSample": // binaryPath soitaskPath sampleName
argIndex++
binaryPath := os.Args[argIndex]
argIndex++
soitaskPath := os.Args[argIndex]
argIndex++
sampleName := os.Args[argIndex]
sample, err := parseSample(soitaskPath, sampleName)
if err != nil {
panic(err)
}
printRunSampleInfo(binaryPath, sampleName)
executionResult := runSample(binaryPath, bytes.NewBufferString(sample.Input), os.Stdout, os.Stderr)
printSampleVerdict(binaryPath, sampleName, executionResult.Stdout, sample.Output, executionResult.ProcessError)
sendResult(conn, binaryPath, sampleName, executionResult)
case "runAllSamples": // binaryPath soitaskPath
argIndex++
binaryPath := os.Args[argIndex]
argIndex++
soitaskPath := os.Args[argIndex]
samples, err := parseAllSamples(soitaskPath)
if err != nil {
panic(err)
}
for _, sampleName := range mapToSortedKeys(samples) {
sample := samples[sampleName]
printRunSampleInfo(binaryPath, sampleName)
executionResult := runSample(binaryPath, bytes.NewBufferString(sample.Input), ioutil.Discard, ioutil.Discard)
printSampleVerdict(binaryPath, sampleName, executionResult.Stdout, sample.Output, executionResult.ProcessError)
sendResult(conn, binaryPath, sampleName, executionResult)
}
case "runManualInput": // binaryPath
argIndex++
binaryPath := os.Args[argIndex]
printRunManualInput(binaryPath)
executionResult := runSample(binaryPath, os.Stdin, os.Stdout, os.Stderr)
sendResult(conn, binaryPath, "manualInput", executionResult)
}
}
}
package main
import (
"sort"
"github.com/fatih/color"
"bytes"
"encoding/json"
"flag"
"fmt"
// "io/ioutil"
"net"
"os"
)
var (
colorInfo = color.New(color.FgYellow)
colorInfoIdent = color.New(color.FgHiYellow)
colorError = color.New(color.FgRed)
colorErrorIdent = color.New(color.FgHiRed)
colorCorrect = color.New(color.FgGreen)
colorCorrectIdent = color.New(color.FgHiGreen)
colorProgramOutput = color.New(color.FgBlue)
colorExpectedOutput = color.New(color.FgCyan)
)
func sendResult(conn net.Conn, binaryPath, sampleName string, res sampleExecutionResult) {
type transportSampleExecutionResult struct {
Binarypath string
Samplename string
Result sampleExecutionResult
}
msg, err := json.Marshal(transportSampleExecutionResult{
Binarypath: binaryPath,
Samplename: sampleName,
Result: res,
})
if err != nil {
panic(err)
}
fmt.Fprintf(conn, string(msg))
fmt.Fprintf(conn, "\n")
}
func printRunManualInput(binaryPath string) {
colorInfo.Printf("Running program '")
colorInfoIdent.Printf("%v", binaryPath)
colorInfo.Printf("' with your input :\n")
}
func printRunSampleInfo(binaryPath, sampleName string) {
colorInfo.Printf("Running Sample'")
colorInfoIdent.Printf("%v", sampleName)
colorInfo.Printf("' on program '")
colorInfoIdent.Printf("%v", binaryPath)
colorInfo.Printf("':\n")
}
func printSampleVerdict(binaryPath, sampleName, programOutput, expectedOutput, processError string) {
if programOutput != expectedOutput {
// Todo: Highlight diff
colorError.Printf("Sample '")
colorErrorIdent.Printf("%v", sampleName)
colorError.Printf("': Output differs\n")
colorInfo.Printf("Expected Output:\n")
colorProgramOutput.Printf("%v", expectedOutput)
colorInfo.Printf("\nYour Program's output:\n")
colorExpectedOutput.Printf("%v\n", programOutput)
} else {
colorCorrect.Printf("Sample '")
colorCorrectIdent.Printf("%v", sampleName)
colorCorrect.Printf("': Correct\n")
}
fmt.Printf("%v\n", processError)
}
type anything interface {
}
func mapToSortedKeys(m map[string]Sample) []string {
keys := []string{}
for k := range m {
keys = append(keys, k)
}
sort.Strings(keys)
return keys
}
func runOneSample() {
runOneSampleCmd := flag.NewFlagSet("runOneSample", flag.ExitOnError)
binaryPath := runOneSampleCmd.String("binaryPath", "", "path of binary which is executed")
soitaskPath := runOneSampleCmd.String("soitaskPath", "", "path of soitask file, that contains the sample")
sampleName := runOneSampleCmd.String("sampleName", "", "Full path of the sample which is executed. E.g. sample.01")
port := runOneSampleCmd.String("port", "", "Port to which the runner reports the evaluation reports")
runOneSampleCmd.Parse(os.Args[2:])
if runOneSampleCmd.Parsed() {
if *binaryPath == "" {
fmt.Printf("binaryPath is required\n")
os.Exit(2)
}
if *soitaskPath == "" {
fmt.Printf("soitaskPath is required\n")
os.Exit(2)
}
if *sampleName == "" {
fmt.Printf("sampleName is required\n")
os.Exit(2)
}
if *port == "" {
fmt.Printf("port is required\n")
os.Exit(2)
}
} else {
os.Exit(4)
}
conn, err := net.Dial("tcp", "127.0.0.1:"+*port)
if err != nil {
panic(err)
}
sample, err := parseSample(*soitaskPath, *sampleName)
if err != nil {
panic(err)
}
printRunSampleInfo(*binaryPath, *sampleName)
executionResult := runSample(*binaryPath, bytes.NewBufferString(sample.Input), os.Stdout, os.Stderr)
printSampleVerdict(*binaryPath, *sampleName, executionResult.Stdout, sample.Output, executionResult.ProcessError)
sendResult(conn, *binaryPath, *sampleName, executionResult)
}
func runAllSamples() {
runAllSampleCmd := flag.NewFlagSet("runAllSamples", flag.ExitOnError)
binaryPath := runAllSampleCmd.String("binaryPath", "", "path of binary which is executed")
soitaskPath := runAllSampleCmd.String("soitaskPath", "", "path of soitask file, that contains the sample")
port := runAllSampleCmd.String("port", "", "Port to which the runner reports the evaluation reports")
runAllSampleCmd.Parse(os.Args[2:])
if runAllSampleCmd.Parsed() {
if *binaryPath == "" {
fmt.Printf("binaryPath is required\n")
os.Exit(2)
}
if *soitaskPath == "" {
fmt.Printf("soitaskPath is required\n")
os.Exit(2)
}
if *port == "" {
fmt.Printf("port is required\n")
os.Exit(2)
}
} else {
os.Exit(4)
}
conn, err := net.Dial("tcp", "127.0.0.1:"+*port)
if err != nil {
panic(err)
}
samples, err := parseAllSamples(*soitaskPath)
if err != nil {
panic(err)
}
for _, sampleName := range mapToSortedKeys(samples) {
sample := samples[sampleName]
printRunSampleInfo(*binaryPath, sampleName)
// executionResult := runSample(*binaryPath, bytes.NewBufferString(sample.Input), ioutil.Discard, ioutil.Discard)
executionResult := runSample(*binaryPath, bytes.NewBufferString(sample.Input), os.Stdout, os.Stderr)
printSampleVerdict(*binaryPath, sampleName, executionResult.Stdout, sample.Output, executionResult.ProcessError)
sendResult(conn, *binaryPath, sampleName, executionResult)
}
}
func runWithManualInput() {
runWithManualInputCmd := flag.NewFlagSet("runWithManualInput", flag.ExitOnError)
binaryPath := runWithManualInputCmd.String("binaryPath", "", "path of binary which is executed")
port := runWithManualInputCmd.String("port", "", "Port to which the runner reports the evaluation reports")
runWithManualInputCmd.Parse(os.Args[2:])
if runWithManualInputCmd.Parsed() {
if *binaryPath == "" {
fmt.Printf("binaryPath is required\n")
os.Exit(2)
}
if *port == "" {
fmt.Printf("port is required\n")
os.Exit(2)
}
} else {
os.Exit(4)
}
conn, err := net.Dial("tcp", "127.0.0.1:"+*port)
if err != nil {
panic(err)
}
printRunManualInput(*binaryPath)
executionResult := runSample(*binaryPath, os.Stdin, os.Stdout, os.Stderr)
sendResult(conn, *binaryPath, "manualInput", executionResult)
}
......@@ -2,7 +2,7 @@
"name": "soicode",
"displayName": "soicode",
"description": "A extension which provides integration to solve soi (soi.ch) tasks in vscode",
"version": "0.0.7",
"version": "0.8.0",
"publisher": "swissolyinfo",
"engines": {
"vscode": "^1.33.0"
......@@ -259,8 +259,12 @@
"icon": "images/soilogo.png",
"homepage": "https://soi.ch",
"scripts": {
"vscode:prepublish": "npm run compile",
"compile": "tsc -p ./",
"vscode:prepublish": "npm run compile && npm run build-helper",
"build-helper-linux": "CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o ./out/helper-linux-amd64 ./helper",
"build-helper-windows": "CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -o ./out/helper-windows-amd64 ./helper",
"build-helper-darwin": "CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -o ./out/helper-darwin-amd64 ./helper",
"build-helper": "npm run build-helper-linux && npm run build-helper-windows && npm run build-helper-darwin",
"compile": "build-helper && tsc -p ./",
"watch": "tsc -watch -p ./",
"pretest": "npm run compile",
"build-package": "vsce package",
......
......@@ -6,19 +6,10 @@ import * as path from "path";
import { getWorkspaceOrShowError } from "./storeHelper";
export function getCompilerPath(store: Store): string {
if (getWorkspaceOrShowError(store).settings.compiler.useManagedCompiler) {
return path.join(store.soicodeExtensionDataPath, "compiler", "g++");
} else {
return getWorkspaceOrShowError(store).settings.compiler.manualCompilePath;
}
return getWorkspaceOrShowError(store).settings.settings.compilerPath;
}
export function getDebuggerPath(store: Store): string {
if (getWorkspaceOrShowError(store).settings.compiler.useManagedCompiler) {
return path.join(store.soicodeExtensionDataPath, "compiler", "gdb");
} else {
// return settings.compiler.manualCompilePath; // todo
return "/usr/bin/gdb";
}
return getWorkspaceOrShowError(store).settings.settings.debuggerPath;
}
export function getDebuggerFlavor(store: Store): "gdb" | "lldb" | null {
let debuggerPath = getDebuggerPath(store);
......@@ -31,57 +22,23 @@ export function getDebuggerFlavor(store: Store): "gdb" | "lldb" | null {
}
return null;
}
export function getClangFormatPath(store: Store): string {
if (getWorkspaceOrShowError(store).settings.compiler.useManagedCompiler) {
// todo needs on boolean flag since clangformat and compiler are independant
return path.join(
store.soicodeExtensionDataPath,
"compiler",
"clang-format"
);
} else {
// return settings.compiler.manualCompilePath; // todo
return "";
}
}
export async function getCppHeaderPath(store: Store): Promise<string | null> {
if (getWorkspaceOrShowError(store).settings.compiler.useManagedCompiler) {
// todo needs on boolean flag since headers and compiler are independant
return path.join(store.soicodeExtensionDataPath, "compiler", "headers");
} else {
// return settings.compiler.manualCompilePath; // todo
return "";
}
export function getCppHeaderPath(store: Store): string {
return getWorkspaceOrShowError(store).settings.settings.cppHeaderPath;
}
export async function getSoiHeaderPath(store: Store): Promise<string | null> {
if (getWorkspaceOrShowError(store).settings.compiler.useManagedCompiler) {
// todo needs on boolean flag since soi headers and compiler are independant
return path.join(store.soicodeExtensionDataPath, "compiler", "soiHeaders");
} else {
// return settings.compiler.manualCompilePath; // todo
return "";
export function getSoiHeaderPath(store: Store): string {
if (getWorkspaceOrShowError(store).settings.settings.useBundledSoiheaders) {
return getWorkspaceOrShowError(store).settings.settings.soiHeaderPath;
}
return path.join(
store.soicodeExtensionDataPath,
"bundle",
"soiheaders",
"soiheaders"
);
}
// export async function downloadCompilerBundle(store: Store) {
// let platform = "";
// // also look at process.arch
// switch (process.platform) {
// case "darwin":
// platform = "darwin-amd64";
// case "win32":
// platform = "windows-amd64";
// case "linux":
// platform = "linux-amd64";
// }
// await fs.mkdir(store.soicodeExtensionPath);
// let file = fs.createWriteStream(
// path.join(store.soicodeExtensionPath, "helper")
// );
// let response = await https.get(
// "https://blob.dolansoft.org/soicode/helper-" + platform
// );
// response.pipe(file);
// }
export function getCompilationFlags(store: Store): string[] {
return getWorkspaceOrShowError(store).settings.settings.flags.split(" ");
}
......@@ -15,11 +15,11 @@ import {
} from "./lenses/emptySoitaskLens";