github.com/LanceLRQ/deer-common@v0.0.9-0.20210319081233-e8222ac018a8/provider/main.go (about) 1 /* Compiler Provider Base 2 * (C) 2019 LanceLRQ 3 * 4 * This code is licenced under the GPLv3. 5 */ 6 package provider 7 8 import ( 9 "context" 10 "encoding/json" 11 "fmt" 12 "github.com/LanceLRQ/deer-common/structs" 13 "github.com/LanceLRQ/deer-common/utils" 14 "github.com/pkg/errors" 15 "github.com/satori/go.uuid" 16 "io/ioutil" 17 "os" 18 "path" 19 "strings" 20 "time" 21 ) 22 23 type CompileCommandsStruct struct { 24 GNUC string `json:"gcc"` 25 GNUCPP string `json:"g++"` 26 Java string `json:"java"` 27 Go string `json:"golang"` 28 NodeJS string `json:"nodejs"` 29 PHP string `json:"php"` 30 Ruby string `json:"ruby"` 31 Python2 string `json:"python2"` 32 Python3 string `json:"python3"` 33 Rust string `json:"rust"` 34 } 35 36 var CompileCommands = CompileCommandsStruct{ 37 GNUC: "gcc %s -o %s -ansi -fno-asm -Wall -std=c11 -lm", 38 GNUCPP: "g++ %s -o %s -ansi -fno-asm -Wall -lm -std=c++11", 39 Java: "javac -encoding utf-8 %s -d %s", 40 Go: "go build -o %s %s", 41 NodeJS: "node -c %s", 42 PHP: "php -l -f %s", 43 Ruby: "ruby -c %s", 44 Python2: "python -u %s", 45 Python3: "python3 -u %s", 46 Rust: "rustc %s -o %s", 47 } 48 49 type CodeCompileProviderInterface interface { 50 // 初始化 51 Init(code string, workDir string) error 52 // 初始化文件信息 53 initFiles(codeExt string, programExt string) error 54 // 执行编译 55 Compile() (result bool, errmsg string) 56 // 清理工作目录 57 Clean() 58 // 获取程序的运行命令参数组 59 GetRunArgs() (args []string) 60 // 判断STDERR的输出内容是否存在编译错误信息,通常用于脚本语言的判定, 61 IsCompileError(remsg string) bool 62 // 是否为实时编译的语言 63 IsRealTime() bool 64 // 是否已经编译完毕 65 IsReady() bool 66 // 调用Shell命令并获取运行结果 67 shell(commands string) (success bool, errout string) 68 // 保存代码到文件 69 saveCode() error 70 // 检查工作目录是否存在 71 checkWorkDir() error 72 // 获取名称 73 GetName() string 74 } 75 76 type CodeCompileProvider struct { 77 CodeCompileProviderInterface 78 Name string // 编译器提供程序名称 79 codeContent string // 代码 80 realTime bool // 是否为实时编译的语言 81 isReady bool // 是否已经编译完毕 82 codeFileName, codeFilePath string // 目标程序源文件 83 programFileName, programFilePath string // 目标程序文件 84 workDir string // 工作目录 85 } 86 87 func PlaceCompilerCommands(configFile string) error { 88 if configFile != "" { 89 _, err := os.Stat(configFile) 90 // ignore 91 if os.IsNotExist(err) { 92 return nil 93 } 94 cbody, err := ioutil.ReadFile(configFile) 95 if err != nil { 96 return err 97 } 98 err = json.Unmarshal(cbody, &CompileCommands) 99 if err != nil { 100 return err 101 } 102 } 103 return nil 104 } 105 106 func (prov *CodeCompileProvider) initFiles(codeExt string, programExt string) error { 107 prov.codeFileName = fmt.Sprintf("%s%s", uuid.NewV4().String(), codeExt) 108 prov.programFileName = fmt.Sprintf("%s%s", uuid.NewV4().String(), programExt) 109 prov.codeFilePath = path.Join(prov.workDir, prov.codeFileName) 110 prov.programFilePath = path.Join(prov.workDir, prov.programFileName) 111 112 err := prov.saveCode() 113 return err 114 } 115 116 func (prov *CodeCompileProvider) GetName() string { 117 return prov.Name 118 } 119 120 func (prov *CodeCompileProvider) Clean() { 121 _ = os.Remove(prov.codeFilePath) 122 _ = os.Remove(prov.programFilePath) 123 } 124 125 func (prov *CodeCompileProvider) shell(commands string) (success bool, errout string) { 126 ctx, _ := context.WithTimeout(context.Background(), 10*time.Second) 127 cmdArgs := strings.Split(commands, " ") 128 if len(cmdArgs) <= 1 { 129 return false, "not enough arguments for compiler" 130 } 131 ret, err := utils.RunUnixShell(&structs.ShellOptions{ 132 Context: ctx, 133 Name: cmdArgs[0], 134 Args: cmdArgs[1:], 135 StdWriter: nil, 136 OnStart: nil, 137 }) 138 if err != nil { 139 return false, err.Error() 140 } 141 if !ret.Success { 142 return false, ret.Stderr 143 } 144 return true, "" 145 } 146 147 func (prov *CodeCompileProvider) saveCode() error { 148 file, err := os.OpenFile(prov.codeFilePath, os.O_RDWR|os.O_CREATE, 0644) 149 if err != nil { 150 return err 151 } 152 defer file.Close() 153 _, err = file.WriteString(prov.codeContent) 154 return err 155 } 156 157 func (prov *CodeCompileProvider) checkWorkDir() error { 158 _, err := os.Stat(prov.workDir) 159 if err != nil { 160 if os.IsNotExist(err) { 161 return errors.Errorf("work dir not exists") 162 } 163 return err 164 } 165 return nil 166 } 167 168 func (prov *CodeCompileProvider) IsRealTime() bool { 169 return prov.realTime 170 } 171 172 func (prov *CodeCompileProvider) IsReady() bool { 173 return prov.isReady 174 }