Skip to content

Commit a975437

Browse files
committed
tmp
1 parent 595a1bd commit a975437

File tree

9 files changed

+149
-46
lines changed

9 files changed

+149
-46
lines changed

cmd/root.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ func initCommands() {
103103
rootCmd.SetOut(os.Stdout)
104104
rootCmd.InitDefaultVersionFlag()
105105
rootCmd.Flags().SortFlags = false
106-
rootCmd.PersistentFlags().StringP("lang", "l", "", "language of code to generate: cpp, go, python ...")
106+
rootCmd.PersistentFlags().StringP("lang", "l", "", "language of code to generate: cpp, go, python, java...")
107107
rootCmd.PersistentFlags().StringP("site", "", "", "leetcode site: cn, us")
108108
rootCmd.PersistentFlags().BoolP("yes", "y", false, "answer yes to all prompts")
109109
rootCmd.InitDefaultHelpFlag()

config/config.go

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -70,16 +70,16 @@ type Modifier struct {
7070
}
7171

7272
type CodeConfig struct {
73-
Lang string `yaml:"lang" mapstructure:"lang" comment:"Language of code generated for questions: go, python, ... \n(will be override by project config and flag --lang)"`
74-
FilenameTemplate string `yaml:"filename_template" mapstructure:"filename_template" comment:"The default template to generate filename (without extension), e.g. {{.Id}}.{{.Slug}}\nAvailable attributes: Id, Slug, Title, Difficulty, Lang, SlugIsMeaningful\nAvailable functions: lower, upper, trim, padWithZero, toUnderscore, group"`
75-
SeparateDescriptionFile bool `yaml:"separate_description_file" mapstructure:"separate_description_file" comment:"Generate question description into a separate question.md file"`
76-
Blocks []Block `yaml:"blocks,omitempty" mapstructure:"blocks" comment:"Default block definitions for all languages"`
77-
Modifiers []Modifier `yaml:"modifiers,omitempty" mapstructure:"modifiers" comment:"Default modifiers for all languages"`
78-
Go GoConfig `yaml:"go" mapstructure:"go"`
79-
Python PythonConfig `yaml:"python3" mapstructure:"python3"`
80-
Cpp CppConfig `yaml:"cpp" mapstructure:"cpp"`
81-
Rust RustConfig `yaml:"rust" mapstructure:"rust"`
82-
Java BaseLangConfig `yaml:"java" mapstructure:"java"`
73+
Lang string `yaml:"lang" mapstructure:"lang" comment:"Language of code generated for questions: go, python, ... \n(will be overridden by command line flag -l/--lang)"`
74+
FilenameTemplate string `yaml:"filename_template" mapstructure:"filename_template" comment:"The default template to generate filename (without extension), e.g. {{.Id}}.{{.Slug}}\nAvailable attributes: Id, Slug, Title, Difficulty, Lang, SlugIsMeaningful\nAvailable functions: lower, upper, trim, padWithZero, toUnderscore, group"`
75+
SeparateDescriptionFile bool `yaml:"separate_description_file" mapstructure:"separate_description_file" comment:"Generate question description into a separate question.md file"`
76+
Blocks []Block `yaml:"blocks,omitempty" mapstructure:"blocks" comment:"Default block definitions for all languages"`
77+
Modifiers []Modifier `yaml:"modifiers,omitempty" mapstructure:"modifiers" comment:"Default modifiers for all languages"`
78+
Go GoConfig `yaml:"go" mapstructure:"go"`
79+
Python PythonConfig `yaml:"python3" mapstructure:"python3"`
80+
Cpp CppConfig `yaml:"cpp" mapstructure:"cpp"`
81+
Rust RustConfig `yaml:"rust" mapstructure:"rust"`
82+
Java JavaConfig `yaml:"java" mapstructure:"java"`
8383
// Add more languages here
8484
}
8585

@@ -110,6 +110,11 @@ type RustConfig struct {
110110
BaseLangConfig `yaml:",inline" mapstructure:",squash"`
111111
}
112112

113+
type JavaConfig struct {
114+
BaseLangConfig `yaml:",inline" mapstructure:",squash"`
115+
GroupID string `yaml:"group_id" mapstructure:"group_id" comment:"Maven group ID"`
116+
}
117+
113118
type Credentials struct {
114119
From string `yaml:"from" mapstructure:"from" comment:"How to provide credentials: browser, cookies, password or none"`
115120
Browsers []string `yaml:"browsers" mapstructure:"browsers" comment:"Browsers to get cookies from: chrome, safari, edge or firefox. If empty, all browsers will be tried"`
@@ -223,7 +228,12 @@ func defaultConfig() *Config {
223228
BaseLangConfig: BaseLangConfig{OutDir: "python"},
224229
Executable: constants.DefaultPython,
225230
},
226-
Java: BaseLangConfig{OutDir: "java"},
231+
Java: JavaConfig{
232+
BaseLangConfig: BaseLangConfig{
233+
OutDir: "java",
234+
FilenameTemplate: `p{{ .Id | padWithZero 4 }}{{ if .SlugIsMeaningful }}_{{ .Slug | lower | toUnderscore }}{{ end }}`,
235+
},
236+
},
227237
Rust: RustConfig{BaseLangConfig: BaseLangConfig{OutDir: "rust"}},
228238
// Add more languages here
229239
},

lang/base.go

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -167,16 +167,6 @@ func getTempBinFile(q *leetcode.QuestionData, lang Lang) (string, error) {
167167
return filepath.Join(tmpDir, filename), nil
168168
}
169169

170-
func getTempBinDir(q *leetcode.QuestionData, lang Lang) (string, error) {
171-
tmpDir := config.Get().TempDir()
172-
dirname := fmt.Sprintf("%s-%s", q.TitleSlug, lang.Slug())
173-
dir := filepath.Join(tmpDir, dirname)
174-
if err := utils.CreateIfNotExists(dir, true); err != nil {
175-
return "", err
176-
}
177-
return dir, nil
178-
}
179-
180170
func separateDescriptionFile(lang Lang) bool {
181171
ans := viper.Get("code." + lang.Slug() + ".separate_description_file")
182172
if ans != nil {

lang/cpp.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import (
1010
"github.com/j178/leetgo/config"
1111
"github.com/j178/leetgo/constants"
1212
"github.com/j178/leetgo/leetcode"
13-
cppUtils "github.com/j178/leetgo/testutils/cpp"
13+
cppEmbed "github.com/j178/leetgo/testutils/cpp"
1414
"github.com/j178/leetgo/utils"
1515
)
1616

@@ -19,21 +19,21 @@ type cpp struct {
1919
}
2020

2121
func (c cpp) Initialize(outDir string) error {
22-
headerPath := filepath.Join(outDir, cppUtils.HeaderName)
23-
err := utils.WriteFile(headerPath, cppUtils.HeaderContent)
22+
headerPath := filepath.Join(outDir, cppEmbed.HeaderName)
23+
err := utils.WriteFile(headerPath, cppEmbed.HeaderContent)
2424
if err != nil {
2525
return err
2626
}
2727
stdCxxPath := filepath.Join(outDir, "bits", "stdc++.h")
28-
err = utils.WriteFile(stdCxxPath, cppUtils.StdCxxContent)
28+
err = utils.WriteFile(stdCxxPath, cppEmbed.StdCxxContent)
2929
if err != nil {
3030
return err
3131
}
3232
return nil
3333
}
3434

3535
func (c cpp) HasInitialized(outDir string) (bool, error) {
36-
headerPath := filepath.Join(outDir, cppUtils.HeaderName)
36+
headerPath := filepath.Join(outDir, cppEmbed.HeaderName)
3737
if !utils.IsExist(headerPath) {
3838
return false, nil
3939
}
@@ -278,7 +278,7 @@ func (c cpp) generateCodeFile(
278278
#include "%s"
279279
using namespace std;
280280
281-
`, cppUtils.HeaderName,
281+
`, cppEmbed.HeaderName,
282282
)
283283
testContent, err := c.generateTestContent(q)
284284
if err != nil {

lang/java.go

Lines changed: 110 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,113 @@ package lang
22

33
import (
44
"fmt"
5+
"path/filepath"
6+
"regexp"
7+
"runtime"
8+
"strings"
59

610
"github.com/j178/leetgo/config"
711
"github.com/j178/leetgo/leetcode"
12+
javaEmbed "github.com/j178/leetgo/testutils/java"
813
"github.com/j178/leetgo/utils"
914
)
1015

16+
const (
17+
pomTemplate = `
18+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
19+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
20+
<modelVersion>4.0.0</modelVersion>
21+
22+
<groupId>%s</groupId>
23+
<artifactId>%s</artifactId>
24+
<version>1.0</version>
25+
<packaging>jar</packaging>
26+
27+
<name>leetcode-solutions</name>
28+
29+
<properties>
30+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
31+
</properties>
32+
33+
<dependencies>
34+
<dependency>
35+
<groupId>io.github.j178</groupId>
36+
<artifactId>leetgo-java</artifactId>
37+
<version>1.0</version>
38+
</dependency>
39+
</dependencies>
40+
41+
<build>
42+
<plugins>
43+
<plugin>
44+
<groupId>org.codehaus.mojo</groupId>
45+
<artifactId>exec-maven-plugin</artifactId>
46+
<version>3.1.1</version>
47+
</plugin>
48+
</plugins>
49+
</build>
50+
51+
</project>
52+
`
53+
)
54+
1155
type java struct {
1256
baseLang
1357
}
1458

59+
func mvnwCmd(dir string, args ...string) []string {
60+
cmdName := "mvnw"
61+
if runtime.GOOS == "windows" {
62+
cmdName = "mvnw.cmd"
63+
}
64+
return append([]string{filepath.Join(dir, cmdName), "-q"}, args...)
65+
}
66+
1567
func (j java) HasInitialized(outDir string) (bool, error) {
16-
return false, nil
68+
return utils.IsExist(filepath.Join(outDir, "pom.xml")), nil
69+
}
70+
71+
var nameReplacer = regexp.MustCompile(`[^a-zA-Z0-9_]`)
72+
73+
func (j java) groupID() string {
74+
cfg := config.Get()
75+
if cfg.Code.Java.GroupID != "" {
76+
return cfg.Code.Java.GroupID
77+
}
78+
name := nameReplacer.ReplaceAllString(strings.ToLower(cfg.Author), "_")
79+
return "io.github." + name
80+
}
81+
82+
func (j java) sourceDir() string {
83+
groupID := j.groupID()
84+
path := []string{"src", "main", "java"}
85+
path = append(path, strings.Split(groupID, ".")...)
86+
return filepath.Join(path...)
1787
}
1888

1989
func (j java) Initialize(outDir string) error {
90+
// Copy mvn wrapper from embed
91+
err := utils.CopyFS(outDir, javaEmbed.MvnWrapper)
92+
if err != nil {
93+
return err
94+
}
95+
96+
groupID := j.groupID()
97+
artifactID := "leetcode-solutions"
98+
99+
// Write pom.xml
100+
pomXML := fmt.Sprintf(pomTemplate, groupID, artifactID)
101+
err = utils.WriteFile(filepath.Join(outDir, "pom.xml"), []byte(pomXML))
102+
if err != nil {
103+
return err
104+
}
105+
106+
// Create layout
107+
sourceDir := filepath.Join(outDir, j.sourceDir())
108+
err = utils.MakeDir(sourceDir)
109+
if err != nil {
110+
return err
111+
}
20112
return nil
21113
}
22114

@@ -32,19 +124,15 @@ func (j java) RunLocalTest(q *leetcode.QuestionData, outDir string, targetCase s
32124
return false, fmt.Errorf("file %s not found", utils.RelToCwd(testFile))
33125
}
34126

35-
execDir, err := getTempBinDir(q, j)
36-
if err != nil {
37-
return false, fmt.Errorf("get temp bin dir failed: %w", err)
38-
}
39-
40-
args := []string{"javac", "-d", execDir, testFile}
41-
err = buildTest(q, genResult, args)
127+
buildCmd := mvnwCmd(outDir, "compile")
128+
err = buildTest(q, genResult, buildCmd)
42129
if err != nil {
43130
return false, fmt.Errorf("build failed: %w", err)
44131
}
45132

46-
args = []string{"java", "--class-path", execDir, "Main"}
47-
return runTest(q, genResult, args, targetCase)
133+
// TODO 生成 package name, 后续执行需要用这个名字拼成的完整 main class
134+
execCmd := mvnwCmd(outDir, "exec:exec", fmt.Sprintf("-Dexec.mainClass=%s.Main"))
135+
return runTest(q, genResult, execCmd, targetCase)
48136
}
49137

50138
func (j java) generateNormalTestCode(q *leetcode.QuestionData) (string, error) {
@@ -64,6 +152,7 @@ func (j java) generateTestContent(q *leetcode.QuestionData) (string, error) {
64152

65153
func (j java) generateCodeFile(
66154
q *leetcode.QuestionData,
155+
packageName string,
67156
filename string,
68157
blocks []config.Block,
69158
modifiers []ModifierFunc,
@@ -72,7 +161,11 @@ func (j java) generateCodeFile(
72161
FileOutput,
73162
error,
74163
) {
75-
codeHeader := ""
164+
codeHeader := fmt.Sprintf(
165+
`package %s;
166+
`,
167+
packageName,
168+
)
76169
testContent, err := j.generateTestContent(q)
77170
if err != nil {
78171
return FileOutput{}, err
@@ -108,14 +201,14 @@ func (j java) generateCodeFile(
108201

109202
func (j java) GeneratePaths(q *leetcode.QuestionData) (*GenerateResult, error) {
110203
filenameTmpl := getFilenameTemplate(q, j)
111-
baseFilename, err := q.GetFormattedFilename(j.slug, filenameTmpl)
204+
packageName, err := q.GetFormattedFilename(j.slug, filenameTmpl)
112205
if err != nil {
113206
return nil, err
114207
}
115208
genResult := &GenerateResult{
116-
SubDir: baseFilename,
117209
Question: q,
118210
Lang: j,
211+
SubDir: filepath.Join(j.sourceDir(), packageName),
119212
}
120213
genResult.AddFile(
121214
FileOutput{
@@ -142,14 +235,14 @@ func (j java) GeneratePaths(q *leetcode.QuestionData) (*GenerateResult, error) {
142235

143236
func (j java) Generate(q *leetcode.QuestionData) (*GenerateResult, error) {
144237
filenameTmpl := getFilenameTemplate(q, j)
145-
baseFilename, err := q.GetFormattedFilename(j.slug, filenameTmpl)
238+
packageName, err := q.GetFormattedFilename(j.slug, filenameTmpl)
146239
if err != nil {
147240
return nil, err
148241
}
149242
genResult := &GenerateResult{
150243
Question: q,
151244
Lang: j,
152-
SubDir: baseFilename,
245+
SubDir: filepath.Join(j.sourceDir(), packageName),
153246
}
154247

155248
separateDescriptionFile := separateDescriptionFile(j)
@@ -158,7 +251,8 @@ func (j java) Generate(q *leetcode.QuestionData) (*GenerateResult, error) {
158251
if err != nil {
159252
return nil, err
160253
}
161-
codeFile, err := j.generateCodeFile(q, "solution.java", blocks, modifiers, separateDescriptionFile)
254+
fqPackageName := fmt.Sprintf("%s.%s", j.groupID(), packageName)
255+
codeFile, err := j.generateCodeFile(q, fqPackageName, "solution.java", blocks, modifiers, separateDescriptionFile)
162256
if err != nil {
163257
return nil, err
164258
}

leetcode/question.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -562,6 +562,8 @@ func contestShortSlug(contestSlug string) string {
562562
return strings.Replace(contestSlug, "-contest-", "-", 1)
563563
}
564564

565+
var nonIdentifierRe = regexp.MustCompile(`[^a-zA-Z0-9_]`)
566+
565567
func (q *QuestionData) GetFormattedFilename(lang string, filenameTemplate string) (string, error) {
566568
id, slugValid := q.normalizeQuestionId()
567569
data := &filenameTemplateData{
@@ -595,7 +597,7 @@ func (q *QuestionData) GetFormattedFilename(lang string, filenameTemplate string
595597
return fmt.Sprintf("%0*s", n, s)
596598
},
597599
"toUnderscore": func(s string) string {
598-
return strings.ReplaceAll(s, "-", "_")
600+
return nonIdentifierRe.ReplaceAllString(s, "_")
599601
},
600602
"group": func(size int, s string) string {
601603
id, err := strconv.Atoi(s)

testutils/java/.mvn/maven.config

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
-Dmaven.plugin.validation=none
2+
-DskipTests=true
3+
-q

testutils/java/.mvn/wrapper/maven-wrapper.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,5 @@
1414
# KIND, either express or implied. See the License for the
1515
# specific language governing permissions and limitations
1616
# under the License.
17-
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.2/apache-maven-3.9.2-bin.zip
17+
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.6/apache-maven-3.9.6-bin.zip
1818
wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package io.github.j178.abc;
2+
3+
public class A {
4+
}

0 commit comments

Comments
 (0)